SightGruppenBearbeiter.java
001 /*
002  * Created on 17.04.2004
003  */
004 package de.fub.tip.datenbank.logik;
005 
006 import java.sql.Connection;
007 import java.sql.PreparedStatement;
008 import java.sql.ResultSet;
009 import java.sql.SQLException;
010 import java.sql.Statement;
011 import java.util.ArrayList;
012 import java.util.Collection;
013 import java.util.Vector;
014 
015 import javax.sql.DataSource;
016 
017 import org.apache.log4j.Logger;
018 
019 import de.fub.tip.datenanzeige.beans.HtmlCheckboxDarstellungBean;
020 import de.fub.tip.datenanzeige.container.SightGruppeVOContainer;
021 import de.fub.tip.datenanzeige.ormapper.SightGruppeVO;
022 import de.fub.tip.datenanzeige.ormapper.UserdataVO;
023 import de.fub.tip.datenbank.factory.LogicObject;
024 import de.fub.tip.exceptions.NoDataFoundException;
025 import de.fub.tip.exceptions.NoUserLoggedInException;
026 
027 /**
028  * Sinn: stellt die Logik zur Verfügung, mit der Sehenswürdigkeitsgruppen 
029  * bearbeitet werden können. Das sind Funktionen:
030  <ul>
031  <li>zur Anzeige aller Sehenswürdigkeitsgruppen des Systems</li>
032  <li>zur Anzeige aller nicht abonnierten Sehenswürdigkeitsgruppen 
033  * eines Benutzers</li>
034  <li>zur Anzeige aller abonnierten Sehenswürdigkeitsgruppen eines 
035  * Benutzers</li>
036  <li>zur Bearbeitung und Anzeige des Sehenswürdigkeitsprofils</li>
037  <li>zur Speicherung der Änderungen am Profil in der Datenbank</li>
038  </ul>
039  
040  * vergleichbar zum Themenbearbeiter:
041  @see de.fub.tip.datenbank.logik.ThemenBearbeiter
042  
043  @author hirsch, 17.04.2004
044  @version 2004-04-22
045  * $Id: SightGruppenBearbeiter.java,v 1.24 2004/06/10 12:05:24 hirsch Exp $
046  
047  */
048 public class SightGruppenBearbeiter implements LogicObject {
049   /** Logger zur Fehlersuche */
050   private static Logger logger = 
051       Logger.getLogger(SightGruppenBearbeiter.class);
052   /** Datenquelle mit der der <code>SightGruppenBearbeiter</code>
053    * arbeitet */
054   private DataSource datasource = null;
055 
056   /**
057    * Standardkonstruktor, der einen SightGruppenBearbeiter erzeugt  
058    @param datasource Datenquelle
059    */
060   public SightGruppenBearbeiter(DataSource datasource) {
061     this.datasource = datasource;
062     logger.info("SightGruppenBearbeiter initialized.");
063   // end of Konstruktor
064 
065   /**
066    * gibt alle verfügbaren Sehenswürdigkeitsgruppen zurück
067    
068    @return container mit <code>SightGruppeVO</code>-Objekten
069    
070    @throws NoDataFoundException wenn keine Einträge vorhanden sind
071    @throws SQLException bei Datenbankproblemen
072    */
073   public SightGruppeVOContainer getAllSightGroups() 
074     throws  NoDataFoundException, 
075             SQLException {
076     
077     SightGruppeVO gruppe = null;
078       String sql = "SELECT * FROM sight_objects ORDER BY name ";
079     
080     // die einzelnen Container stets methodenlokal verwalten, da sonst immer 
081     // auch die Daten im Container bleiben, die aus anderen Methodenaufrufen
082     // stammen.
083     SightGruppeVOContainer ergebnis = new SightGruppeVOContainer();
084 
085     Connection con = this.datasource.getConnection();
086     Statement statement = con.createStatement();
087     ResultSet rs = statement.executeQuery(sql);
088     
089     // erste den Erfolgsfall bearbeiten
090     ifrs != null) {
091       while(rs.next()) {
092         // SightGruppeVO zusammenbasteln 
093         gruppe = new SightGruppeVO();
094         
095         // falls es Unregelmässigkeiten beim Laden der Daten aus der DB 
096         // gibt, sollen diese *nie* an STRUTS weitergeleitet werden
097         try {
098             gruppe.setActive(new Boolean(rs.getBoolean("active")));
099             gruppe.setDescription(rs.getString("description"));
100             gruppe.setId(new Integer(rs.getInt("so_id")));
101             gruppe.setName(rs.getString("name"));
102 
103         catch(Exception e) {
104           // Probleme gibt es hier beispielsweise bei NULL-Werten!
105           // Diese werden einfach gefangen und generieren keinen Fehler
106           logger.error("SightGruppenBearbeiter.getAllTopics(): "+
107             e + " - Ausnahme beim Parsen der Daten! " +
108             e.getLocalizedMessage());
109         // end of catch
110   
111         // zur Ergebnismenge hinzufügen und probeweise loggen
112         ergebnis.add(gruppe);
113         gruppe.logObject(logger);
114       // end of while
115     // end if
116     
117     // Schliessen/Freigabe der Datenbankverbindung
118     try {
119       ifcon != null con.close();
120       logger.debug("SightGruppenBearbeiter.getAllTopics(): " +
121         "DB-Con geschlossen.");
122     catch (SQLException e) {
123       logger.debug("SightGruppenBearbeiter.getAllTopics(): " +
124         "geschachtelte Ausnahme beim Schliessen der " +
125         "DB-Verbindung.");
126     // end of try
127   
128     // keine Themen da ?
129     ifrs == null) {
130       throw new NoDataFoundException("SightGruppenBearbeiter." +
131         "getAllTopics(): Ausnahme - keine Themen in der DB zu finden.");
132     else {
133       return ergebnis;
134     // end if
135   // end of getAllSightGroups
136 
137   /**
138    * gibt alle abonnierten Themen des angemeldeten Benutzers zurück
139    
140    @param user angemeldeter Benutzer
141    
142    @return container mit <code>SightGruppeVO</code>-Objekten
143    
144    @throws NoDataFoundException wenn keine Einträge vorhanden sind
145    @throws SQLException bei Datenbankproblemen
146    @throws NoUserLoggedInException falls keine Anmeldung erfolgt ist
147    */
148   public SightGruppeVOContainer getSelectedSightGroupsForUser(
149           UserdataVO user
150     throws  NoDataFoundException, 
151       SQLException, 
152       NoUserLoggedInException {
153 
154     if user == null throw new NoUserLoggedInException("Sight" +
155       "GruppenBearbeiter.getSelectedTopicsForUser(): " +
156       "ungültiger User übergeben");
157 
158     // die abonnierten Sachen müssen aus der Tabelle profile geholt
159     // werden, die zu jedem Benutzer die IDs der Objekte speichert,
160     // die im jeweiligen Profil enthalten sind
161     String sql = "SELECT so.* " 
162       "FROM user_int_obj int, profile p, sight_objects so " 
163       "WHERE p.pid = int.pid AND p.udid = ? AND so.so_id=int.o_id " 
164       "ORDER BY so.name ";   
165 
166     SightGruppeVO gruppe = null;
167     
168     // die einzelnen Container stets methodenlokal verwalten, da sonst immer 
169     // auch die Daten im Container bleiben, die aus anderen Methodenaufrufen
170     // stammen.
171     SightGruppeVOContainer ergebnis = new SightGruppeVOContainer();
172 
173     Connection con = this.datasource.getConnection();
174     PreparedStatement prepStatement = con.prepareStatement(sql);
175     prepStatement.setInt(1, user.getId().intValue());
176     ResultSet rs = prepStatement.executeQuery();
177     
178     // erste den Erfolgsfall bearbeiten
179     ifrs != null) {
180       while(rs.next()) {
181         // SightGruppeVO zusammenbasteln 
182         gruppe = new SightGruppeVO();
183         
184         // falls es Unregelmässigkeiten beim Laden der Daten aus der DB 
185         // gibt, sollen diese *nie* an STRUTS weitergeleitet werden
186         try {
187             gruppe.setActive(new Boolean(rs.getBoolean("active")));
188             gruppe.setDescription(rs.getString("description"));
189             gruppe.setId(new Integer(rs.getInt("so_id")));
190             gruppe.setName(rs.getString("name"));
191 
192         catch(Exception e) {
193           // Probleme gibt es hier beispielsweise bei NULL-Werten!
194           // Diese werden einfach gefangen und generieren keinen Fehler
195           logger.error("SightGruppenBearbeiter.getSelectedSight" +
196             "GroupsForUser(): "+ e + " - Ausnahme beim Parsen der Daten! " +
197             e.getLocalizedMessage());
198         // end of catch
199   
200         // zur Ergebnismenge hinzufügen und probeweise loggen
201         ergebnis.add(gruppe);
202         gruppe.logObject(logger);
203       // end of while
204     // end if
205     
206     // Schliessen/Freigabe der Datenbankverbindung
207     try {
208       ifcon != null con.close();
209       logger.debug("SightGruppenBearbeiter.getSelectedSight" +
210           "GroupsForUser(): DB-Con geschlossen.");
211     catch (SQLException e) {
212       logger.debug("SightGruppenBearbeiter.getSelectedSight" +
213         "GroupsForUser(): geschachtelte Ausnahme beim Schliessen der "+
214         "DB-Verbindung.");
215     // end of try
216     
217     // keine Gruppen da ?
218     ifrs == null) {
219       throw new NoDataFoundException("SightGruppenBearbeiter." +
220         "getSelectedSightGroupsForUser(): Ausnahme - " +
221         "keine Gruppen in der DB zu finden.");
222     else {
223       return ergebnis;
224     // end if
225   // end of getSelectedSightGroupsForUser
226   
227   
228   /**
229    * gibt alle nicht abonnierten Sehenswürdigkeitsgruppen 
230    * des angemeldeten Benutzers zurück
231    
232    @param user angemeldeter Benutzer
233    
234    @return container mit <code>SightGruppeVO</code>-Objekten
235    
236    @throws NoDataFoundException wenn keine Einträge vorhanden sind
237    @throws SQLException bei Datenbankproblemen
238    @throws NoUserLoggedInException falls keine Anmeldung erfolgt ist
239    */
240   public SightGruppeVOContainer getNotSelectedSightGroupsForUser(
241           UserdataVO user
242     throws  NoDataFoundException, 
243       SQLException, 
244       NoUserLoggedInException {
245 
246     if user == null throw new NoUserLoggedInException(
247           "SightGruppenBearbeiter.getNotSelectedSightGroupsForUser(): "+
248       "ungültiger User übergeben");
249 
250     // Die Abfrage der nicht abonnierten Gruppen geht so, dass alle die
251     // Gruppen selektiert werden, deren ID nicht in der positiv-Menge der 
252     // Gruppen enthalten ist. 
253     String sql = "SELECT so.* " +
254       "FROM sight_objects so " 
255       "WHERE so_id NOT IN (SELECT so.so_id "  
256       "FROM user_int_obj int, profile p, sight_objects so "+
257       "WHERE p.pid = int.pid AND p.udid = ? AND so.so_id=int.o_id) " +
258       "ORDER BY so.name";
259 
260     SightGruppeVO gruppe = null;
261     
262     // die einzelnen Container stets methodenlokal verwalten, da sonst immer 
263     // auch die Daten im Container bleiben, die aus anderen Methodenaufrufen
264     // stammen.
265     SightGruppeVOContainer ergebnis = new SightGruppeVOContainer();
266 
267     Connection con = this.datasource.getConnection();
268     PreparedStatement prepStatement = con.prepareStatement(sql);
269     prepStatement.setInt(1, user.getId().intValue());
270     ResultSet rs = prepStatement.executeQuery();
271     
272     // erste den Erfolgsfall bearbeiten
273     ifrs != null) {
274       while(rs.next()) {
275         // SightGruppeVO zusammenbasteln 
276         gruppe = new SightGruppeVO();
277         
278         // falls es Unregelmässigkeiten beim Laden der Daten aus der DB 
279         // gibt, sollen diese *nie* an STRUTS weitergeleitet werden
280         try {
281             gruppe.setActive(new Boolean(rs.getBoolean("active")));
282             gruppe.setDescription(rs.getString("description"));
283             gruppe.setId(new Integer(rs.getInt("so_id")));
284             gruppe.setName(rs.getString("name"));
285 
286         catch(Exception e) {
287           // Probleme gibt es hier beispielsweise bei NULL-Werten!
288           // Diese werden einfach gefangen und generieren keinen Fehler
289           logger.error("SightGruppenBearbeiter.getNotSelectedSight" +
290             "GroupsForUser(): "+ e + 
291             " - Ausnahme beim Parsen der Daten! " +
292             e.getLocalizedMessage());
293         // end of catch
294   
295         // zur Ergebnismenge hinzufügen und probeweise loggen
296         ergebnis.add(gruppe);
297         gruppe.logObject(logger);
298       // end of while
299     // end if
300     
301     // Schliessen/Freigabe der Datenbankverbindung
302     try {
303       ifcon != null con.close();
304       logger.debug("SightGruppenBearbeiter.getNotSelectedSight" +
305           "GroupsForUser(): DB-Con geschlossen.");
306     catch (SQLException e) {
307       logger.debug("SightGruppenBearbeiter.getNotSelectedSight" +
308         "GroupsForUser(): geschachtelte Ausnahme beim Schliessen " +
309         "der DB-Verbindung.");
310     // end of try
311     
312     // keine Gruppen da ?
313     ifrs == null) {
314       throw new NoDataFoundException("SightGruppenBearbeiter." +
315         "getNotSelectedSightGroupsForUser(): Ausnahme - " +
316         "keine Gruppen in der DB zu finden.");
317     else {
318       return ergebnis;
319     // end if
320   // end of getNotSelectedSightGroupsForUser
321   
322 
323   /**
324    * gibt alle Sehenswürdigkeitsgruppen des angemeldeten Benutzers zurück.
325    * Die View kann dann je nachdem wie das Attribut aboStatus gesetzt ist,
326    * entscheiden, ob ein Häkchen für &quot;abonniert&quot;
327    * oder keines für &quot;nicht abonniert&quot; gesetzt wird.
328    
329    @param user angemeldeter Benutzer
330    
331    @return container mit <code>SightGruppeVO</code>-Objekten
332    
333    @throws NoDataFoundException wenn keine Einträge vorhanden sind
334    @throws SQLException bei Datenbankproblemen
335    @throws NoUserLoggedInException falls keine Anmeldung erfolgt ist
336    */
337   public SightGruppeVOContainer getViewableSightGroupProfile(
338           UserdataVO user
339     throws  NoDataFoundException, 
340       SQLException, 
341       NoUserLoggedInException {
342 
343       SightGruppeVO sgruppe = null;
344       
345       // Arbeitsprinzip
346       // 1. alle restlichen Dinge holen und deren IDs speichern.
347       SightGruppeVOContainer alle = this.getAllSightGroups();
348       SightGruppeVOContainer ergebnis = null;
349       
350       // 2. alle abonnierten Objekte des Users holen und deren IDs 
351       // in einen Vector speichern
352       SightGruppeVOContainer abonnierte = 
353           this.getSelectedSightGroupsForUser(user);
354       Vector nurIds = new Vector();
355 
356       whileabonnierte.hasNext() ) {
357           nurIds.add(  ((SightGruppeVOabonnierte.next() ).getId());
358       // end of while
359       nurIds.trimToSize();
360 
361       // wenn der Nutzer keine Gruppen abonniert hat, kann einfach
362       // der Container mit allen Sehenswürdigkeitsgruppen 
363       // *ohne Modifikationen* zurückgegeben werden, 
364       // da die aboStatus-Werte standardmässig 
365       // auf falsch gesetzt sind.
366       if(nurIds.size() == 0return alle;
367 
368       // 3. alle IDs auslesen und diesen Container durchklappern und
369       // für jedes gelesene Objekte - je nach Zugehörigkeit zu Schritt 1 oder
370       // 2 - den aboStatus setzen.
371       ergebnis = new SightGruppeVOContainer();
372 
373       whilealle.hasNext() ) {
374           sgruppe = (SightGruppeVOalle.next();
375           
376           // ist Gruppe abonniert ?
377           if nurIds.contains(sgruppe.getId()) ) {
378               sgruppe.setAboStatus(new Boolean(true));
379               logger.debug("aboPositiv: " + sgruppe);
380           // end if
381           ergebnis.add(sgruppe);
382           
383       // end of while
384 
385       // 4. Ergebnis zurückgeben
386       return ergebnis;
387   // end of getViewableSightGroupProfile
388 
389   /**
390    * schreibt das neue Profil für <code>SightGruppeVO</code>-Objekte
391    * in die Datenbank.<br>
392    * Am Beginn der Transaktion wird das komplett bestehende
393    <code>SightGruppeVO</code>-Profil des Benutzers gelöscht und
394    * der Inhalt des Containers als neues Profil geschrieben.<br>
395    * Dabei sind im Container jeweils nur die Objekte von Interesse, die den
396    <code>aboStatus</code> gesetzt haben. 
397    
398    @param user angemeldeter Benutzer
399    
400    @throws NoDataFoundException wenn keine Einträge vorhanden sind
401    @throws SQLException bei Datenbankproblemen
402    @throws NoUserLoggedInException falls keine Anmeldung erfolgt ist
403    */
404   public void setSightGroupProfileForUser(UserdataVO user, 
405           String[] changes
406     throws  NoDataFoundException, 
407       SQLException, 
408       NoUserLoggedInException {
409 
410     if user == null throw new NoUserLoggedInException(
411             "SightGruppenBearbeiter.setSightGroupProfileForUser(): " +
412         "ungültiger User übergeben");
413       
414       // Prinzip:
415       // 1. Containerelemente checken und in einen neuen Container alle 
416     // die schreiben, die aboStatus true haben; also in die DB kommen
417       // 1a. BEGIN WORK
418       // 2. alle Elemente aus der DB zum Profil des Users löschen!
419       // 3. Container hinzufügen mit einer Schleife und INSERT INTO ...
420       // 4. COMMIT o. Rollback
421     
422     logger.info("SightGruppenBearbeiter.setSightGroupProfileForUser() " +
423         "startet ...");
424 
425     // Auf Grund der Tabellenstruktur wird etwas kompliziert eingefügt ....    
426     String loesche = "DELETE FROM user_int_obj WHERE pid= ? ";
427     String profilId = "SELECT pid FROM profile WHERE udid=? ";
428     String fuegeAn = "INSERT INTO user_int_obj (pid, o_id) VALUES (?, ?) ";
429     
430     // lokale Variablen
431     // ProfilID des aktuellen Benutzers
432     Integer pid  = null;
433     Connection con = null;
434     Statement stat = null;
435     PreparedStatement prepStat = null;
436     ResultSet rs = null;
437 
438     try {
439       con = this.datasource.getConnection();
440       stat = con.createStatement();
441       
442       // 1. ausserhalb der Transaktion die ProfilID lesen
443       logger.debug("ProfilID lesen");
444       prepStat = con.prepareStatement(profilId);
445       prepStat.setInt(1, user.getId().intValue());
446       rs = prepStat.executeQuery();
447       if rs != null && rs.next()) {
448           pid = new Integer(rs.getInt("pid"));
449       else {
450           throw new SQLException("konnte ProfilID des" +
451               " Benutzers "+ user.getId()+" nicht auslesen!");
452       // end if
453       
454       // 2. Transaktion anfangen, bestehende Daten löschen,
455       // neue hinzufügen
456       logger.debug("Transaktion anfangen ...für Profil "+ pid);
457       con.setAutoCommit(false);
458       stat.execute("BEGIN WORK");
459 
460       // 2a. löschen der bestehenden Einträge
461       prepStat = con.prepareStatement(loesche);
462       prepStat.setInt(1, pid.intValue());
463       logger.debug(prepStat.executeUpdate() 
464         " Profileinträge gelöscht.");
465 
466       // 2b. jetzt den Inhalt der Collection in die DB schreiben
467       prepStat = con.prepareStatement(fuegeAn);
468       
469       // ist NULL, wenn der Benutzer alles deaktiviert hat
470       if changes != null ) {
471         // im BatchModus die ganzen Sachen hinzufügen
472         for int i = 0; i < changes.length; i++ ) {
473             prepStat.setInt(1, pid.intValue());
474             // die Collection enthält nur die abonnierten IDs!
475             prepStat.setString(2, changes[i]);
476             prepStat.addBatch();
477         // end for
478         
479         // Loslegen und für Ausgabe umbauen
480         int[] gespeichert = prepStat.executeBatch();
481         String erg = "";
482         for int i = 0; i < gespeichert.length; i++) {
483             erg+=gespeichert[i]"+";
484         // end of for
485         logger.debug(erg+ 
486           " SightGroupVO-Datensätze erfolgreich eingefügt");
487       // end if
488 
489       // Transaktion beenden
490       logger.debug("COMMIT machen ...");
491       stat.execute("COMMIT");
492 
493     catch (SQLException e) {
494       logger.error(
495               "SightGruppenBearbeiter.setSightGroupProfileForUser():"+
496           " Fehler - "+e + ", "+ e.getLocalizedMessage());
497       
498       try {
499         logger.error("SightGruppenBearbeiter." +
500           "setSightGroupProfileForUser(): ROLLBACK gemacht!");
501         stat.execute("ROLLBACK");
502       catch (SQLException e1) {
503         logger.error("SightGruppenBearbeiter." +
504           "setSightGroupProfileForUser()-SQLException: " +
505           "verschachtelte Ausnahme beim ROLLBACK aufgetreten!");
506       // end of try
507 
508     catch(Exception e) {
509       // Damit auf keinen Fall auf den Webseiten Fehler angezeigt werden,
510       // die durch das Logging verursacht wurden ....
511       logger.error("SightGruppenBearbeiter." +
512         "setSightGroupProfileForUser(): " +
513         "Problem - "+e + ", " + e.getLocalizedMessage());
514 
515       try {
516         logger.error("SightGruppenBearbeiter." +
517             "setSightGroupProfileForUser(): ROLLBACK gemacht!");
518         stat.execute("ROLLBACK");
519       catch (SQLException e1) {
520         logger.error("SightGruppenBearbeiter." +
521           "setSightGroupProfileForUser()-SQLException: " +
522           "verschachtelte Ausnahme beim ROLLBACK aufgetreten!");
523       // end of try
524 
525     // end of try
526 
527     // Datenbankverbindung immer korrekt schliessen
528     finally {
529       try {
530         if(con!=nullcon.close();
531         logger.debug("SightGruppenBearbeiter." +
532           "setSightGroupProfileForUser(): DB-Con geschlossen.");
533       catch (SQLException e1) {
534         logger.error("SightGruppenBearbeiter." +
535           "setSightGroupProfileForUser(): " + e1 + 
536           "Fehler beim Schliessen der DB-Con: " 
537           e1.getLocalizedMessage());
538       // end of catch
539     // end of finally
540 
541     logger.info("SightGruppenBearbeiter.setSightGroupProfileForUser() " +
542         "erfolgreich beendet.");
543   // end of setSightGroupProfileForUser
544   
545 
546   /**
547    * gibt alle Sehenswürdigkeitsgruppen des angemeldeten Benutzers zurück.
548    * Die View kann dann je nachdem wie das Attribut aboStatus gesetzt ist,
549    * entscheiden, ob ein Häkchen für &quot;abonniert&quot;
550    * oder keines für &quot;nicht abonniert&quot; gesetzt wird.
551    
552    @param user angemeldeter Benutzer
553    
554    @return collection 
555    <code>HtmlCheckboxDarstellungBean</code>-Objekten
556    
557    @throws NoDataFoundException wenn keine Einträge vorhanden sind
558    @throws SQLException bei Datenbankproblemen
559    @throws NoUserLoggedInException falls keine Anmeldung erfolgt ist
560    */
561   public Collection getBeanSightGroupProfile(UserdataVO user
562     throws  NoDataFoundException, 
563       SQLException, 
564       NoUserLoggedInException {
565       
566       SightGruppeVOContainer container =
567           getViewableSightGroupProfile(user);
568       
569       ArrayList list = new ArrayList(container.size());
570       SightGruppeVO sightgruppe = null;
571       HtmlCheckboxDarstellungBean bean = null;
572       
573       // Umwandeln des Containers in eine Collection<Bean>
574       while(container.hasNext()) {
575           try {
576                 sightgruppe = ((SightGruppeVOcontainer.next());
577                 bean = new HtmlCheckboxDarstellungBean(sightgruppe);
578                 list.add(bean);
579             catch (ClassCastException e) {
580                 logger.debug(e + "," + sightgruppe);
581             }
582       // end of while
583       
584       logger.debug("SightGruppenProfil in Liste mit " + list.size() +
585         " Elementen umgewandelt.");
586       return list;
587   // end of getBeanSightGroupProfile
588 // end of class