[Schmitzm-commits] r2285 - in trunk/schmitzm-hibernate/src/main: java/de/schmitzm/db/hibernate java/de/schmitzm/db/hibernate/gui java/de/schmitzm/db/hibernate/gui/event resources/de/schmitzm/db/hibernate/resource/locales

scm-commit at wald.intevation.org scm-commit at wald.intevation.org
Mon Mar 25 22:10:30 CET 2013


Author: mojays
Date: 2013-03-25 22:10:30 +0100 (Mon, 25 Mar 2013)
New Revision: 2285

Added:
   trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/
   trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/DatabaseEntityTable.java
   trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/DatabaseEntityTableModel.java
   trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/DatabaseSearchQueryToolBar.java
   trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/GUIUtil.java
   trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/event/
   trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/event/DatabaseRecordDeletedEvent.java
   trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/event/DatabaseRecordUpdatedEvent.java
   trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/event/DatabaseSearchListener.java
   trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/event/DatabaseUpdateAdapter.java
   trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/event/DatabaseUpdateEmitter.java
   trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/event/DatabaseUpdateEvent.java
   trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/event/DatabaseUpdateListener.java
Modified:
   trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/DBUtil.java
   trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/HibernateApplication.java
   trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/HibernateSessionFactory.java
   trunk/schmitzm-hibernate/src/main/resources/de/schmitzm/db/hibernate/resource/locales/HibernateResourceBundle.properties
   trunk/schmitzm-hibernate/src/main/resources/de/schmitzm/db/hibernate/resource/locales/HibernateResourceBundle_de.properties
Log:
Global session removed from DBUtil; instead reference to static instance of HibernateSessionFactory
HibernateApplication: implementation of DatabaseUpdateEmitter
Several generic classes taken from WIME

Modified: trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/DBUtil.java
===================================================================
--- trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/DBUtil.java	2013-03-25 21:07:57 UTC (rev 2284)
+++ trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/DBUtil.java	2013-03-25 21:10:30 UTC (rev 2285)
@@ -1,12 +1,15 @@
 package de.schmitzm.db.hibernate;
 
+import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
 
 import org.apache.log4j.Logger;
 import org.hibernate.Criteria;
+import org.hibernate.JDBCException;
 import org.hibernate.Session;
+import org.hibernate.Transaction;
 import org.hibernate.criterion.Criterion;
 import org.hibernate.criterion.Order;
 import org.hibernate.criterion.Restrictions;
@@ -16,7 +19,7 @@
 import de.schmitzm.db.hibernate.types.UniqueIDType;
 import de.schmitzm.lang.LangUtil;
 import de.schmitzm.lang.ResourceProvider;
-import de.schmitzm.swing.SwingUtil;
+import de.schmitzm.swing.ExceptionDialog;
 
 /**
  * Utility methods for hibernate.
@@ -27,46 +30,16 @@
 	private static Logger LOGGER = LangUtil.createLogger(DBUtil.class);
 
     /**
-     * {@link ResourceProvider} for the localization in the package
-     * {@code de.schmitzm.db.hibernate}.
+     * Returns the global {@link Session} of the application wide {@link HibernateSessionFactory}
+     * instance. This session is used for internal/automatic database update, e.g. in
+     * {@link #getOrCreateBasicType(Class, String)}
      */
-    public static ResourceProvider RESOURCE = ResourceProvider.newInstance(
-            LangUtil.extendPackagePath(DBUtil.class,
-                    "resource.locales.HibernateResourceBundle"), Locale.ENGLISH);
+	public static Session getGlobalSession() {
+	  final HibernateSessionFactory globalFactory = HibernateSessionFactory.getGlobalFactory();
+      return globalFactory.getSession();
+	}
 
 	/**
-	 * Can hold a global {@link Session} used for updates. Should never
-	 * be closed!
-	 */
-	protected static Session GLOBAL_SESSION = null;
-	
-    /**
-     * Returns the global {@link Session} which is used for internal/automatic
-     * database update, e.g. in {@link #getOrCreateBasicType(Class, String)}
-     * @param checkNull if {@code true} an exception is thrown if {@link #GLOBAL_SESSION}
-     *                  is not set or closed.
-     */
-	public static Session getGlobalSession(boolean checkNull) {
-	  if ( checkNull ) {
-	    if ( GLOBAL_SESSION == null )
-	      throw new UnsupportedOperationException("DBUtil.GLOBAL_SESSION is not set.");
-        if ( !GLOBAL_SESSION.isOpen() )
-          throw new UnsupportedOperationException("DBUtil.GLOBAL_SESSION is not open.");
-	    if ( !GLOBAL_SESSION.isConnected() )
-	      throw new UnsupportedOperationException("DBUtil.GLOBAL_SESSION is not connected.");
-	  }
-	  return GLOBAL_SESSION;
-	}
-	
-	/**
-	 * Sets the global {@link Session} which is used for internal/automatic
-	 * database update, e.g. in {@link #getOrCreateBasicType(Class, String)}
-	 */
-    public static void setGlobalSession(Session session) {
-      GLOBAL_SESSION = session;
-    }
-
-    /**
 	 * Checks whether two objects represent the same record. The ID is 
 	 * used for compare.
 	 * 
@@ -141,11 +114,11 @@
 
     /**
      * Returns a {@link BasicTypeInterface} instance for the given description
-     * or creates it if it does not exist. The {@linkplain #getGlobalSession(boolean) global session}
+     * or creates it if it does not exist. The {@linkplain #getGlobalSession() global session}
      * is used for possible database updates.
      * @param basicType basic type to determine the instance for
      * @param desc description for the {@link BasicTypeInterface} instance
-     * @see #getGlobalSession(boolean)
+     * @see #getGlobalSession()
      */
     public static <E extends BasicTypeInterface> E getOrCreateBasicType(Class<E> basicType, String desc) {
       return getOrCreateBasicType(basicType, desc, true);
@@ -153,7 +126,7 @@
     
     /**
      * Returns a {@link BasicTypeInterface} instance for the given description
-     * or creates it if it does not exist. The {@linkplain #getGlobalSession(boolean) global session}
+     * or creates it if it does not exist. The {@linkplain #getGlobalSession() global session}
      * is used for possible database updates.
      * @param basicType basic type to determine the instance for
      * @param desc description for the {@link BasicTypeInterface} instance
@@ -162,7 +135,7 @@
      *            creation). This has to be done explicitly later, e.g. in case when
      *            additional {@link BasicTypeInterface} attributes has to be
      *            filled before insert.
-     * @see #getGlobalSession(boolean)
+     * @see #getGlobalSession()
      */
     public static <E extends BasicTypeInterface> E getOrCreateBasicType(Class<E> basicType, String desc, boolean saveOrUpdate) {
         return getOrCreateBasicType(null, basicType, desc, saveOrUpdate);
@@ -173,20 +146,20 @@
      * or creates it if it does not exist.
      * @param basicType basic type to determine the instance for
      * @param session session to use for update (if {@code null} the
-     *                {@linkplain #getGlobalSession(boolean) global session} is used)
+     *                {@linkplain #getGlobalSession() global session} is used)
      * @param desc description for the {@link BasicTypeInterface} instance
      * @param saveOrUpdate
      *            if {@code false}, no {@code Session.saveOrUpdate(.)} is performed (on possible
      *            creation). This has to be done explicitly later, e.g. in case when
      *            additional {@link BasicTypeInterface} attributes has to be
      *            filled before insert.
-     * @see #getGlobalSession(boolean)
+     * @see #getGlobalSession()
 	 */
 	public static <E extends BasicTypeInterface> E getOrCreateBasicType(Session session, Class<E> basicType, String desc, boolean saveOrUpdate) {
 		if (org.apache.commons.lang.StringUtils.trimToNull(desc) == null)
 			return null;
 		if ( session == null )
-		  session = getGlobalSession(true);
+		  session = getGlobalSession();
 		E instance = determineBasicType(basicType, desc);
 		if (instance == null) {
 			instance = createBasicTypeInstance(basicType);
@@ -201,7 +174,7 @@
      * Checks whether a {@link BasicTypeInterface} instance is already persistent.
      * If not it will be stored in database.
      * @param session session to use for update (if {@code null} the
-     *                {@linkplain #getGlobalSession(boolean) global session} is used)
+     *                {@linkplain #getGlobalSession() global session} is used)
      * @param basicType basic type to check
      * @return always {@code basicType}
      */
@@ -213,7 +186,7 @@
         return basicType;
       
       if ( session == null )
-        session = getGlobalSession(true);
+        session = getGlobalSession();
       session.persist(basicType);
       
       return basicType;
@@ -222,7 +195,7 @@
 
 	/**
 	 * Retrieves the first instances of a {@link BasicType} from database.
-	 * The {@linkplain #getGlobalSession(boolean) global session} is used 
+	 * The {@linkplain #getGlobalSession() global session} is used 
 	 * for database access.
      * @param basicType basic type to determine an instance for
 	 * @return {@code null} if the table is empty
@@ -237,7 +210,7 @@
 	/**
 	 * Retrieves all instances of a type from database.
      * @param session session to use for database access (if {@code null} the
-     *                {@linkplain #getGlobalSession(boolean) global session} is used)
+     *                {@linkplain #getGlobalSession() global session} is used)
      * @param type type to determine the instances for
 	 */
 	public static <E extends Object> List<E> determineAllRecords(Session session, Class<E> type) {
@@ -247,14 +220,14 @@
 	/**
 	 * Retrieves all instances of a type from database, which satisfies a filter.
      * @param session session to use for database access (if {@code null} the
-     *                {@linkplain #getGlobalSession(boolean) global session} is used)
+     *                {@linkplain #getGlobalSession() global session} is used)
      * @param type type to determine the instances for
      * @param filter filter to apply
 	 */
 	public static <E extends Object> List<E> determineAllRecords(Session session, Class<E> type, Criterion filter, Order order) {
 	    // if no session is specified, use the global session 
 	    if ( session == null )
-	      session = getGlobalSession(true);
+	      session = getGlobalSession();
 
 	    // Query muss in einer Transaktion erfolgen, damit die
 		// korrekten Daten ermittelt werden.
@@ -270,7 +243,7 @@
 
     /**
      * Retrieves all instances of a {@link BasicType} from database. The
-     * {@linkplain #getGlobalSession(boolean) global session} is used for database access.
+     * {@linkplain #getGlobalSession() global session} is used for database access.
      * @param basicType type to determine the instances for
      */
     public static <E extends BasicTypeInterface> List<E> determineAllBasicTypes(Class<E> basicType) {
@@ -281,7 +254,7 @@
     /**
 	 * Retrieves all instances of a {@link BasicType} from database.
      * @param session session to use for database access (if {@code null} the
-     *                {@linkplain #getGlobalSession(boolean) global session} is used)
+     *                {@linkplain #getGlobalSession() global session} is used)
      * @param basicType type to determine the instances for
 	 */
 	public static <E extends BasicTypeInterface> List<E> determineAllBasicTypes(Session session, Class<E> basicType) {
@@ -291,7 +264,7 @@
     /**
      * Retrieves all instances of a {@link BasicType} from database.
      * @param session session to use for database access (if {@code null} the
-     *                {@linkplain #getGlobalSession(boolean) global session} is used)
+     *                {@linkplain #getGlobalSession() global session} is used)
      * @param basicType type to determine the instances for
      * @param filter filter to apply
      */
@@ -301,11 +274,11 @@
     
 	/**
 	 * Retrieves an instances of a {@link BasicType} from database with the specified description.
-	 * The {@linkplain #getGlobalSession(boolean) global session} is used for database access.
+	 * The {@linkplain #getGlobalSession() global session} is used for database access.
 	 */
 	public static <E extends BasicTypeInterface> E determineBasicType(Class<E> basicType, String description) {
-		Criteria query = getGlobalSession(true).createCriteria(basicType);
-		query.add(Restrictions.eq("bezeichnung", description));
+		Criteria query = getGlobalSession().createCriteria(basicType);
+		query.add(Restrictions.eq(BasicType.DESCRIPTION_COL, description));
 		List<E> resultList = (List<E>) query.list();
 
 		if (resultList.isEmpty())
@@ -318,7 +291,7 @@
 
 	/**
 	 * Retrieves the description of all {@link BasicType} instances from database.
-     * The {@linkplain #getGlobalSession(boolean) global session} is used for database access.
+     * The {@linkplain #getGlobalSession() global session} is used for database access.
 	 */
 	public static <E extends BasicTypeInterface> List<String> determineAllBasicTypeDescriptions(Class<E> basicType) {
 		List<E> basicTypes = determineAllBasicTypes(basicType);
@@ -328,7 +301,23 @@
 		return basicTypeDesc;
 	}
 
-	/**
+    /**
+     * Returns the name of the database table which represents the given type. This method expects that
+     * every type which represents a hibernate entity holds a static String field "TABLENAME".
+     */
+    public static String getDatabaseTable(Class<?> type) {
+        // TODO: Maybe we can use the annotation "Entity(name=...)" instead to retrieve the table name
+        try {
+            // Klassenname klappt irgenwie nicht !?
+            // return type.getSimpleName();
+            return (String) type.getDeclaredField("TABLENAME").get(null);
+        } catch (Exception err) {
+            throw new UnsupportedOperationException("Table name could not be retrieved from "
+                    + LangUtil.getSimpleClassName(type), err);
+        }
+    }
+
+    /**
 	 * Returns the name of the discriminator column for a given type. This method expects that the types which are
 	 * define the shared table ("InheritanceType.SINGLE_TABLE") hold a static String field "DESCR_COLUMN".
 	 */
@@ -355,4 +344,75 @@
 	}
 
 
+    /**
+     * End the transaction of the global session.
+     * @param commit if {@code true} a COMMIT done, otherwise a ROLLBACK
+     * @return {@code false} if an error occurred
+     */
+    public static boolean endTransaction(boolean commit) {
+      return endTransaction(null, commit);
+    }
+    
+    /**
+     * End the transaction of a session.
+     * @param commit if {@code true} a COMMIT done, otherwise a ROLLBACK
+     * @return {@code false} if an error occurred
+     */
+    public static boolean endTransaction(Session session, boolean commit) {
+        if ( session == null )
+          session = getGlobalSession();
+        
+        Transaction transaction = session.getTransaction();
+        // Wenn keine Transaktion aktiv ist, nichts machen
+        if (transaction == null || !transaction.isActive())
+            return true;
+        try {
+            if (commit) {
+                // Transaktion durchfuehren
+                session.flush();
+                transaction.commit();
+            } else {
+                // Transaktion abbrechen
+                transaction.rollback();
+                // MS 26.10.2011: nicht ganz sicher, ob das sein muss!
+                // wenn drin, verhindert es, dass beim Abbrechen und erneutem
+                // Oeffnen des SeminarDataFrames ein eingefuegter, aber nicht
+                // gespeicherter Datensatz (Zombie) noch angezeigt wird!
+                // Dennoch: zuvor war es auskommentiert!?
+                session.clear(); 
+            }
+            return true;
+        } catch (Exception err) {
+            err = getNextException(err);
+            ExceptionDialog.show(err);
+            transaction.rollback();
+
+            return false;
+        } finally {
+            HibernateSessionFactory.beginTransactionIfNeeded(session);
+        }
+    }
+
+    /**
+     * If the given exception is a {@link JDBCException} the method returns
+     * {@code JDBCException.getSQLException().getNextException()} because its
+     * descriptions is more useful to show in {@link ExceptionDialog}.<br>
+     * Otherwise the methods returns the given {@link Exception} itself.
+     */
+    public static Exception getNextException(Exception err) {
+        // Wenn es sich um eine JDBCException handelt, deren
+        // Ausloeser anzeigen (aussagekraefitiger als die
+        // abgefangene Exception!)
+        if (err instanceof JDBCException) {
+            SQLException err2 = ((JDBCException) err).getSQLException();
+            if (err2 != null) {
+                err = err2;
+                if (err2.getNextException() != null)
+                    err = err2.getNextException();
+            }
+        }
+        return err;
+
+    }
+
 }

Modified: trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/HibernateApplication.java
===================================================================
--- trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/HibernateApplication.java	2013-03-25 21:07:57 UTC (rev 2284)
+++ trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/HibernateApplication.java	2013-03-25 21:10:30 UTC (rev 2285)
@@ -33,8 +33,8 @@
 
 import javax.swing.JOptionPane;
 
-import org.apache.log4j.Logger;
-
+import de.schmitzm.db.hibernate.gui.GUIUtil;
+import de.schmitzm.db.hibernate.gui.event.DatabaseUpdateEmitter;
 import de.schmitzm.swing.Disposable;
 import de.schmitzm.swing.ExceptionDialog;
 import de.schmitzm.swing.SwingUtil;
@@ -50,7 +50,7 @@
  * the database. 
  * @author Martin O.J. Schmitz
  */
-public abstract class HibernateApplication implements Disposable {
+public abstract class HibernateApplication extends DatabaseUpdateEmitter implements Disposable {
   
   /** Holds the {@link HibernateSessionFactory} which handles the
    *  database connection via hibernate.  */
@@ -162,8 +162,8 @@
       boolean ret = connectToDatabase(true);
       if (ret)
           JOptionPane.showMessageDialog(getMainFrame(),
-                                        DBUtil.RESOURCE.getString("HibernateApplication.db.init.confirm.mess"),
-                                        DBUtil.RESOURCE.getString("HibernateApplication.db.init.title"),
+                                        GUIUtil.R("HibernateApplication.db.init.confirm.mess"),
+                                        GUIUtil.R("HibernateApplication.db.init.title"),
                                         JOptionPane.INFORMATION_MESSAGE);
       return ret;
   }
@@ -206,7 +206,7 @@
           try {
               Object[] optionValues = MultipleOptionPane.showMultipleInputDialog(
                                               getMainFrame(),
-                                              DBUtil.RESOURCE.getString("HibernateApplication.db.conn.dialog.title"),
+                                              GUIUtil.R("HibernateApplication.db.conn.dialog.title"),
                                               dbConnectOptions);
               if (optionValues == null) {
                   // clear Password for security reasons
@@ -214,9 +214,10 @@
                   return false;
               }
               if (forceCreate) {
-                  int ret = JOptionPane.showConfirmDialog(getMainFrame(),
-                                DBUtil.RESOURCE.getString("HibernateApplication.db.init.warn.mess"),
-                                DBUtil.RESOURCE.getString("HibernateApplication.db.init.title"),
+                  int ret = JOptionPane.showConfirmDialog(
+                                getMainFrame(),
+                                GUIUtil.R("HibernateApplication.db.init.warn.mess"),
+                                GUIUtil.R("HibernateApplication.db.init.title"),
                                 JOptionPane.YES_NO_OPTION);
                   if (ret != JOptionPane.YES_OPTION) {
                       dbConnectOptions[4].setValue(null);
@@ -251,7 +252,7 @@
               };
               SwingWorker worker = new SwingWorker(connectionWork,
                                                    getMainFrame(),
-                                                   DBUtil.RESOURCE.getString("HibernateApplication.db.conn.progress.mess"),
+                                                   GUIUtil.R("HibernateApplication.db.conn.progress.mess"),
                                                    0.5, 0.5);
               // worker.getDialog().setDialogOption(StatusDialog.NONE_OPTION);
               worker.start();
@@ -277,6 +278,7 @@
               handleConnectionException(err);
           }
 
+      fireDatabaseConnectionEstablished();
       return true;
   }
 
@@ -290,6 +292,8 @@
           return false;
       sessionFactory.disconnectAllSessions();
       sessionFactory.killSessionFactory();
+      
+      fireDatabaseConnectionReleased();
       return true;
   }
 

Modified: trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/HibernateSessionFactory.java
===================================================================
--- trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/HibernateSessionFactory.java	2013-03-25 21:07:57 UTC (rev 2284)
+++ trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/HibernateSessionFactory.java	2013-03-25 21:10:30 UTC (rev 2285)
@@ -1,6 +1,5 @@
 package de.schmitzm.db.hibernate;
 
-import java.io.File;
 import java.io.Serializable;
 import java.sql.Connection;
 import java.sql.DatabaseMetaData;
@@ -18,18 +17,18 @@
 import org.hibernate.cfg.Environment;
 import org.hibernate.jdbc.Work;
 
-import de.schmitzm.io.IOUtil;
 import de.schmitzm.lang.LangUtil;
-import de.schmitzm.versionnumber.ReleaseControl;
-import de.schmitzm.versionnumber.ReleaseUpdater;
 
 /**
  * Configures and provides access to Hibernate sessions, tied to the current thread of execution. Follows the Thread
  * Local Session pattern, see {@link http://hibernate.org/42.html }.
  */
 public abstract class HibernateSessionFactory {
-	private Logger LOGGER = LangUtil.createLogger(this);
+	private static Logger LOGGER = LangUtil.createLogger(HibernateSessionFactory.class);
 
+	/** Application wide instance of {@link HibernateSessionFactory}. */
+	private static HibernateSessionFactory INST;
+	
     private Session globalSession = null;
 	private Map<Object,Session> sessions = new HashMap<Object,Session>();
 
@@ -65,18 +64,42 @@
 	public HibernateSessionFactory(boolean multipleSessions, String configFile) {
 	  this.MULTIPLE_SESSIONS = multipleSessions;
 	  this.configFile = configFile;
+	  setGlobalInstance(this);
 	}
 	
-//	/**
-//     * return session factory
-//     * 
-//     * session factory will be rebuilded in the next call
-//     */
-//    public static void setConfigFile(String configFile) {
-//      sessionFactory = null;
-//    }
+	/**
+	 * Returns the application wide instance of {@link HibernateSessionFactory}.
+     * @param checkNull if {@code true} an exception is thrown if {@link #INST}
+     *                  is not set yet or not connected.
+	 */
+	public static HibernateSessionFactory getGlobalFactory(boolean checkNull) {
+      if ( checkNull ) {
+        if ( INST == null )
+          throw new UnsupportedOperationException("No instance of "+LangUtil.getSimpleClassName(HibernateSessionFactory.class)+" created yet!");
+        if ( !INST.isConnected() )
+          throw new UnsupportedOperationException("Global instance of "+LangUtil.getSimpleClassName(HibernateSessionFactory.class)+" is not connected!");
+      }
+	  return INST;
+	}
+	
+    /**
+     * Returns the application wide instance of {@link HibernateSessionFactory}.
+     */
+    public static HibernateSessionFactory getGlobalFactory() {
+      return getGlobalFactory(true);
+    }
 
     /**
+	 * Sets the application wide {@link HibernateSessionFactory} instance.
+	 * Should only be called by constructor.
+	 */
+    protected static void setGlobalInstance(HibernateSessionFactory factory) {
+      if ( INST != null && factory != null )
+        LOGGER.warn(LangUtil.getSimpleClassName(HibernateSessionFactory.class)+".setGlobalInstance(.) called twice! Application wide instance should one be set once!");
+      INST = factory;
+    }
+	
+    /**
      * return hibernate configuration
      * 
      */
@@ -334,7 +357,7 @@
      *            transaction end (<b>Note:</b> it depends on the database and version, which constraints are effected
      *            by the <i>deferred</i> setting!!)
      */
-    private void beginTransactionIfNeeded(Session session, boolean deferredChecks) {
+    private static void beginTransactionIfNeeded(Session session, boolean deferredChecks) {
       if (session == null)
         throw new UnsupportedOperationException(
         "Transaktion kann nicht begonnen werden, da keine Session zur Verfuegung steht!");
@@ -363,7 +386,7 @@
     /**
      * Starts a new transaction with immediate constraint checking.
      */
-    public void beginTransactionIfNeeded(Session session) {
+    public static void beginTransactionIfNeeded(Session session) {
         beginTransactionIfNeeded(session,false);
     }
 

Added: trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/DatabaseEntityTable.java
===================================================================
--- trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/DatabaseEntityTable.java	                        (rev 0)
+++ trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/DatabaseEntityTable.java	2013-03-25 21:10:30 UTC (rev 2285)
@@ -0,0 +1,90 @@
+package de.schmitzm.db.hibernate.gui;
+
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.List;
+import java.util.Vector;
+
+import javax.swing.ListSelectionModel;
+
+import de.schmitzm.db.hibernate.types.UniqueIDType;
+import de.schmitzm.swing.SortableJTable;
+
+/**
+ * Panel, which shows a list of database records of one table.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ */
+public class DatabaseEntityTable<E extends UniqueIDType> extends SortableJTable {
+  /**
+   * Creates a new panel.
+   */
+  public DatabaseEntityTable(DatabaseEntityTableModel<E> tableModel) {
+    super(tableModel);
+    initGUI();
+  }
+
+  /**
+   * Initalises the GUI components.
+   */
+  protected void initGUI() {
+    setAutoGrowColums(true);
+    setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
+    addMouseListener( new MouseAdapter() {
+      public void mouseClicked(MouseEvent e) {
+        // nur auf Doppelklick reagieren
+        if ( e.getClickCount() < 2 || e.getButton() != e.BUTTON1 )
+          return;
+        
+        E selectedEntity = getSelectedEntity();
+        if ( selectedEntity == null )
+          return;
+        performEntitySelection(selectedEntity);
+      }
+    });
+  }
+  
+  /**
+   * Returns the table model.
+   */
+  @Override
+  public DatabaseEntityTableModel<E> getModel() {
+    return (DatabaseEntityTableModel<E>)super.getModel();
+  }
+
+  /**
+   * Returns the entity which currently is selected in table.
+   */
+  public E getSelectedEntity() {
+    int selectedModelRow = getSelectedModelRow();
+    if ( selectedModelRow < 0 )
+      return null;
+    return getModel().getEntity(selectedModelRow);
+  }
+  
+  /**
+   * Returns all entities currently selected in table.
+   */
+  public List<E> getSelectedEntities() {
+    int[] selectedModelRows = getSelectedModelRows();
+    List<E> selectedKontakte = new Vector<E>();
+    for (int selectedModelRow : selectedModelRows)
+      selectedKontakte.add( getModel().getEntity(selectedModelRow) );
+    return selectedKontakte;
+  }
+
+  /**
+   * Returns all entities currently displayed in table.
+   */
+  public List<E> getEntities() {
+    return getModel().getEntities();
+  }
+
+  /**
+   * Reacts on double click on a table row.
+   * This method does nothing. Sub-classes can override this method
+   * to implement a special functionality.
+   */
+  protected void performEntitySelection(E kontakt) {
+  }
+
+}
\ No newline at end of file

Added: trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/DatabaseEntityTableModel.java
===================================================================
--- trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/DatabaseEntityTableModel.java	                        (rev 0)
+++ trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/DatabaseEntityTableModel.java	2013-03-25 21:10:30 UTC (rev 2285)
@@ -0,0 +1,180 @@
+package de.schmitzm.db.hibernate.gui;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.table.TableModel;
+
+import de.schmitzm.db.hibernate.DBUtil;
+import de.schmitzm.db.hibernate.HibernateSessionFactory;
+import de.schmitzm.db.hibernate.gui.event.DatabaseRecordDeletedEvent;
+import de.schmitzm.db.hibernate.gui.event.DatabaseUpdateEmitter;
+import de.schmitzm.db.hibernate.gui.event.DatabaseUpdateEvent;
+import de.schmitzm.db.hibernate.gui.event.DatabaseUpdateListener;
+import de.schmitzm.db.hibernate.types.UniqueIDType;
+import de.schmitzm.swing.Disposable;
+import de.schmitzm.swing.table.AbstractTableModel;
+
+/**
+ * Read-only {@link TableModel} for the content of a database table.
+ * Because only read-access is needed to update records in table,
+ * the {@linkplain DBUtil#getGlobalSession() global session} is
+ * used for database access. The application has ensure that an instance of
+ * {@link HibernateSessionFactory} is already created to provide this global
+ * session.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *
+ */
+public abstract class DatabaseEntityTableModel<E extends UniqueIDType> extends AbstractTableModel implements DatabaseUpdateListener, Disposable {
+  private boolean disposed = false;
+  
+  /** Holds the entities */
+  protected List<E> entities = new ArrayList<E>();
+  /** Holds the {@link DatabaseUpdateEmitter} which informs the table about
+   *  database changes. */
+  protected DatabaseUpdateEmitter dbUpdateEmitter = null;
+  
+  /**
+   * Creates a new table model.
+   * @param updateEmitter emitter which informs the table about database changes
+   * @param entities initial data
+   */
+  public DatabaseEntityTableModel(DatabaseUpdateEmitter updateEmitter, List<E> entities) {
+    super();
+    if ( entities == null )
+      entities = new ArrayList<E>();
+    this.entities = entities;
+    this.dbUpdateEmitter = updateEmitter;
+    if ( updateEmitter != null )
+      updateEmitter.addDatabaseUpdateListener(this);
+  }
+
+  /**
+   * Creates an empty table model.
+   * @param updateEmitter emitter which informs the table about database changes
+   */
+  public DatabaseEntityTableModel(DatabaseUpdateEmitter updateEmitter) {
+    this(updateEmitter,null);
+  }
+
+  /**
+   * Sets the data of the table.
+   */
+  public void setEntities(List<E> entities) {
+    this.entities = entities;
+    fireTableDataChanged();
+  }
+
+  /**
+   * Returns the data of the table.
+   */
+  public List<E> getEntities() {
+    return entities;
+  }
+  
+  /**
+   * Returns on entity of the table.
+   */
+  public E getEntity(int row) {
+    return entities.get(row);
+  }
+
+  /**
+   * Returns the number of (displayed) entities in the table.
+   */
+  @Override
+  public int getRowCount() {
+    if ( entities == null )
+      return 0;
+    return entities.size();
+  }
+
+  /**
+   * Always returns {@code false}.
+   */
+  @Override
+  public boolean isCellEditable(int row, int col) {
+    return false;
+  }
+  
+  /**
+   * Clears the list.
+   */
+  public void clear() {
+    entities.clear();
+    fireTableDataChanged();
+  }
+  
+  /**
+   * Returns the column type for a table column (table attribute).
+   */
+  @Override
+  public abstract Class getColumnClass(int col);
+
+  /**
+   * Returns an entity attribute value.
+   */
+  @Override
+  public abstract Object getValueAt(int row, int col);
+
+  /**
+   * Returns the attribute names for the table.
+   */
+  @Override
+  public abstract String[] createColumnNames();
+  
+  /**
+   * If the updated entity is an instance of {@code E} and it is
+   * displayed in table, the record is updated from database (using 
+   * {@link DBUtil#getGlobalSession()}!!) and renewed in {@link TableModel}.
+   * If the event is a {@link DatabaseRecordDeletedEvent} the entity is removed
+   * from {@link TableModel}.
+   */
+  @Override
+  public void databaseUpdated(DatabaseUpdateEvent e) {
+    if ( entities == null )
+      return;
+    if ( !entities.contains(e.getUpdatedRecord()) )
+      return;
+    
+    int row = entities.indexOf( e.getUpdatedRecord() );
+    if (e instanceof DatabaseRecordDeletedEvent){
+      entities.remove(row);
+      fireTableRowsDeleted(row, row);   		
+    } else {
+      E updatedRecord = (E)e.getUpdatedRecord();
+      int id      = updatedRecord.getId();
+      updatedRecord = (E)DBUtil.getGlobalSession().get(updatedRecord.getClass(), id);
+      DBUtil.getGlobalSession().evict(updatedRecord);
+      entities.set(row,updatedRecord);
+      fireTableRowsUpdated(row, row);
+    }
+  }
+
+  /**
+   * Clears the table model if the connection was closed.
+   */
+  @Override
+  public void databaseConnectionStateChanged(boolean connected) {
+    if ( !connected )
+      setEntities(null);
+  }
+
+  /**
+   * Removes the {@link DatabaseUpdateListener} from {@link DatabaseUpdateEmitter}.
+   */
+  @Override
+  public void dispose() {
+    if ( dbUpdateEmitter != null )
+      dbUpdateEmitter.removeDatabaseUpdateListener(this);
+    this.disposed = true;
+  }
+  
+  /**
+   * Prueft, ob das Datenmodell noch aktiv ist.
+   * @return
+   */
+  public boolean isDisposed() {
+    return disposed;
+  }
+}
\ No newline at end of file

Added: trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/DatabaseSearchQueryToolBar.java
===================================================================
--- trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/DatabaseSearchQueryToolBar.java	                        (rev 0)
+++ trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/DatabaseSearchQueryToolBar.java	2013-03-25 21:10:30 UTC (rev 2285)
@@ -0,0 +1,156 @@
+package de.schmitzm.db.hibernate.gui;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.Action;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JToolBar;
+import javax.swing.RootPaneContainer;
+
+import org.apache.commons.lang.StringUtils;
+
+import net.miginfocom.swing.MigLayout;
+import de.schmitzm.db.hibernate.DBUtil;
+import de.schmitzm.db.hibernate.gui.event.DatabaseSearchListener;
+import de.schmitzm.db.hibernate.gui.event.DatabaseUpdateEmitter;
+import de.schmitzm.db.hibernate.gui.event.DatabaseUpdateEvent;
+import de.schmitzm.db.hibernate.gui.event.DatabaseUpdateListener;
+import de.schmitzm.swing.GUIBuilder;
+import de.schmitzm.swing.SwingUtil;
+
+/**
+ * Panel to specify the search query. To update the GUI fields automatically
+ * when database connection is established or closed, this class should added
+ * as {@link DatabaseUpdateListener} to the {@link DatabaseUpdateEmitter} of
+ * the application.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ */
+public abstract class DatabaseSearchQueryToolBar<E> extends JToolBar implements DatabaseUpdateListener {
+  protected JButton searchButton;
+  protected JLabel queryLabel;
+  protected JComboBox<String> queryComboBox;
+  
+  protected ActionListener searchActionListener;
+  protected Action searchAction;
+  
+  /** Lis of listeners, which react on search query results. */
+  protected List<DatabaseSearchListener<E>> resultListeners = new ArrayList<DatabaseSearchListener<E>>();
+  
+  /**
+   * Creates a new panel.
+   */
+  public DatabaseSearchQueryToolBar() {
+    super();
+    setFloatable(false);
+    setLayout( new MigLayout("","0[][][]","center") );
+    
+    queryLabel = GUIBuilder.INST.createHeaderLabel(GUIUtil.R("DatabaseSearchQueryToolBar.Query"));
+    queryComboBox = new JComboBox<String>();
+    queryComboBox.setEditable(true);
+    
+    searchActionListener = new ActionListener() {
+      @Override
+      public void actionPerformed(ActionEvent e) {
+        String pattern = getQueryPattern();
+        // Wenn das Pattern noch nicht in der Liste enthalten ist,
+        // der Combobox-Auswahl hinzufuegen
+        if ( queryComboBox.getSelectedIndex() < 0 && !StringUtils.isBlank(pattern) )
+          queryComboBox.insertItemAt(pattern, 0);
+        
+        performSearch();
+      }
+    };
+    searchAction = GUIBuilder.INST.createAction(GUIUtil.R("DatabaseSearchQueryToolBar.SEARCH"),
+                                                         searchActionListener,
+                                                         "SEARCH",
+                                                         GUIUtil.R("DatabaseSearchQueryToolBar.SEARCH.desc"),
+                                                         GUIUtil.ICON_SEARCH);
+    searchButton = new JButton(searchAction);
+    
+    add(queryLabel,"");
+    add(queryComboBox,"w 100:200, growx");
+    add(searchButton,"span 1 2");
+    addSeparator();
+    
+    // Update actions as no connection is established yet
+    databaseConnectionStateChanged(false);
+  }
+  
+  /**
+   * Sets the Search-button as default button for RETURN key.
+   */
+  public void setSearchButtonToDefaultAction(RootPaneContainer frame) {
+    frame.getRootPane().setDefaultButton(searchButton);
+  }
+  
+  /**
+   * Performs the search query and informs the connected listeners by
+   * {@link #fireSearchResult(List)}.
+   */
+  protected abstract void performSearch();
+
+  /**
+   * Returns the query pattern specified in editable {@link JComboBox}.
+   */
+  public String getQueryPattern() {
+    String pattern = queryComboBox.getSelectedItem() != null ? queryComboBox.getSelectedItem().toString() : "";
+    return pattern;
+  }
+  
+  /**
+   * Informs all connected {@link DatabaseSearchListener} about the new search
+   * result.
+   * @param result search result
+   */
+  protected void fireSearchResult(List<E> result) {
+    String pattern = getQueryPattern();
+    for (DatabaseSearchListener<E> l : resultListeners)
+      l.performSeachResult(pattern,result);
+  }
+  
+  /**
+   * Adds a listener. Each {@link DatabaseSearchListener} can only be added once.
+   * @return {@code true} if the listener was added successfully 
+   */
+  public boolean addSearchListener(DatabaseSearchListener<E> l) {
+    if ( resultListeners.contains(l) )
+      return false;
+    return resultListeners.add(l);
+  }
+
+  /**
+   * Removes a listener.
+   */
+  public boolean removeSearchUpdateListener(DatabaseSearchListener<E> l) {
+    return resultListeners.remove(l);
+  }
+
+  /**
+   * Returns all listeners.
+   */
+  public List<DatabaseSearchListener<E>> getSearchListeners() {
+    return resultListeners;
+  }
+
+  /**
+   * Does nothing.
+   */
+  @Override
+  public void databaseUpdated(DatabaseUpdateEvent e) {
+  }
+
+  /**
+   * Updates the actions in panel.
+   */
+  @Override
+  public void databaseConnectionStateChanged(boolean connected) {
+    searchButton.setEnabled(connected);
+  }
+  
+}

Added: trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/GUIUtil.java
===================================================================
--- trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/GUIUtil.java	                        (rev 0)
+++ trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/GUIUtil.java	2013-03-25 21:10:30 UTC (rev 2285)
@@ -0,0 +1,135 @@
+/**
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focusing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Tzeggai - additional utility classes
+ */
+package de.schmitzm.db.hibernate.gui;
+
+import java.awt.Component;
+import java.util.Locale;
+
+import javax.swing.ImageIcon;
+import javax.swing.JOptionPane;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+
+import de.schmitzm.db.hibernate.DBUtil;
+import de.schmitzm.lang.LangUtil;
+import de.schmitzm.lang.ResourceProvider;
+import de.schmitzm.swing.SwingUtil;
+
+/**
+ * Utility GUI method for working with Hibernate.
+ * @author Martin O.J. Schmitz
+ *
+ */
+public class GUIUtil {
+  /** Icon for "SEARCH" button. */
+  public static final ImageIcon ICON_SEARCH = SwingUtil.createImageIconFromResourcePath("resource/icons/small/zoom.png", null);
+
+  /**
+   * {@link ResourceProvider} for the localization in the package
+   * {@code de.schmitzm.db.hibernate}.
+   */
+  public static ResourceProvider RESOURCE = ResourceProvider.newInstance(
+          LangUtil.extendPackagePath(DBUtil.class,
+                  "resource.locales.HibernateResourceBundle"), Locale.ENGLISH);
+  /**
+   * Shortcut for {@code RESOURCE.getString(..)}.
+   */
+  public static String R(String key, Object... values) {
+    return RESOURCE.getString(key, values);
+  }
+
+  /**
+   * Shows a dialog to confirm the database update.
+   * @return {@link JOptionPane#YES_OPTION}, {@link JOptionPane#CANCEL_OPTION}
+   *         oder {@link JOptionPane#NO_OPTION}
+   */
+  public static int confirmSaveMessage(Component parent) {
+    int confirm = JOptionPane.showConfirmDialog(
+                      parent,
+                      R("GUIUtil.save.confirm.mess"),
+                      R("GUIUtil.save.confirm.mess.title"),
+                      JOptionPane.YES_NO_CANCEL_OPTION);
+    return confirm;
+  }
+
+  /**
+   * Ends the current transaction (of the global session). If not persistent changes
+   * exist the user is asked whether the changes should be committed or aborted.
+   * @param parent parent component for comfirm dialog
+   * @return {@code false} if the dialog was canceled or in case of errors;
+   *         {@code true} if transaction was ended correctly (commit or rollback)
+   *         or if there are not changes to commit
+   */
+  public static boolean confirmTransactionEnd(Component parent) {
+    return confirmTransactionEnd(parent, null);
+  }
+  
+  /**
+   * Ends the current transaction of a session. If not persistent changes
+   * exist the user is asked whether the changes should be committed or aborted.
+   * @param parent parent component for comfirm dialog
+   * @return {@code false} if the dialog was canceled or in case of errors;
+   *         {@code true} if transaction was ended correctly (commit or rollback)
+   *         or if there are not changes to commit
+   */
+  public static boolean confirmTransactionEnd(Component parent, Session session) {
+      if ( session == null )
+        session = DBUtil.getGlobalSession();
+      Transaction transaction = session.getTransaction();
+      // Wenn keine Transaktion aktiv ist, nichts machen
+      if (transaction == null || !transaction.isActive())
+          return true;
+      // Wenn keine Aenderungen vorliegen, Transaktion abbrechen
+      // und weiter nichts machen
+      if (!session.isDirty()) {
+          DBUtil.endTransaction(session,false);
+          return true;
+      }
+
+      // Speichern der Aenderungen bestaetigen lassen
+      int confirm = confirmSaveMessage(parent);
+      switch (confirm) {
+      case JOptionPane.CANCEL_OPTION: // Abbrechen
+      case JOptionPane.CLOSED_OPTION: // "Kreuzchen" des Dialogs oder ESC
+          // -> Nichts machen und zur letzzen Aktion zurueck kehren
+          return false;
+      case JOptionPane.NO_OPTION:
+          // Transaktion abbrechen
+          return DBUtil.endTransaction(session,false);
+      case JOptionPane.YES_OPTION:
+          // Transaktion durchfuehren
+          return DBUtil.endTransaction(session,true);
+      }
+
+      return true;
+  }
+
+}

Added: trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/event/DatabaseRecordDeletedEvent.java
===================================================================
--- trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/event/DatabaseRecordDeletedEvent.java	                        (rev 0)
+++ trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/event/DatabaseRecordDeletedEvent.java	2013-03-25 21:10:30 UTC (rev 2285)
@@ -0,0 +1,16 @@
+package de.schmitzm.db.hibernate.gui.event;
+
+/**
+ * Event that indicates that a database record was deleted.
+ * @author Martin O.J. Schmitz
+ */
+public class DatabaseRecordDeletedEvent extends DatabaseUpdateEvent {
+    /**
+     * Creates a new event.
+     * @param source object that initiated the database change
+     * @param deletedRecord deleted database entity
+     */
+	public DatabaseRecordDeletedEvent(Object source, Object deletedRecord) {
+		super(source,deletedRecord);
+	}
+}

Added: trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/event/DatabaseRecordUpdatedEvent.java
===================================================================
--- trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/event/DatabaseRecordUpdatedEvent.java	                        (rev 0)
+++ trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/event/DatabaseRecordUpdatedEvent.java	2013-03-25 21:10:30 UTC (rev 2285)
@@ -0,0 +1,17 @@
+package de.schmitzm.db.hibernate.gui.event;
+
+/**
+ * Event that indicates that a database record was changed.
+ * @author Martin O.J. Schmitz
+ */
+public class DatabaseRecordUpdatedEvent extends DatabaseUpdateEvent {
+  /**
+   * Creates a new event.
+   * @param source object that initiated the database change
+   * @param updatedRecord updated database entity
+   */
+  public DatabaseRecordUpdatedEvent(Object source, Object updatedRecord) {
+      super(source,updatedRecord);
+  }
+
+}

Added: trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/event/DatabaseSearchListener.java
===================================================================
--- trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/event/DatabaseSearchListener.java	                        (rev 0)
+++ trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/event/DatabaseSearchListener.java	2013-03-25 21:10:30 UTC (rev 2285)
@@ -0,0 +1,15 @@
+package de.schmitzm.db.hibernate.gui.event;
+
+import java.util.List;
+
+/**
+ * Listener, which reacts on search results of ...
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *
+ */
+public interface DatabaseSearchListener<E> {
+  /**
+   * Called by ....
+   */
+  public void performSeachResult(String pattern, List<E> searchResult);
+}

Added: trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/event/DatabaseUpdateAdapter.java
===================================================================
--- trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/event/DatabaseUpdateAdapter.java	                        (rev 0)
+++ trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/event/DatabaseUpdateAdapter.java	2013-03-25 21:10:30 UTC (rev 2285)
@@ -0,0 +1,26 @@
+package de.schmitzm.db.hibernate.gui.event;
+
+/**
+ * Empty implementation of {@link DatabaseUpdateListener}.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *
+ */
+public class DatabaseUpdateAdapter {
+  /**
+   * Called if a table changed.
+   */
+  public void databaseUpdated(DatabaseUpdateEvent e) {
+  }
+
+  /**
+   * Called when database connection was established.
+   */
+  public void databaseConnectionEstablished() {
+  }
+
+  /**
+   * Called when database connection was closed
+   */
+  public void databaseConnectionReleased() {
+  }
+}

Added: trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/event/DatabaseUpdateEmitter.java
===================================================================
--- trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/event/DatabaseUpdateEmitter.java	                        (rev 0)
+++ trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/event/DatabaseUpdateEmitter.java	2013-03-25 21:10:30 UTC (rev 2285)
@@ -0,0 +1,99 @@
+package de.schmitzm.db.hibernate.gui.event;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class represents a central objects, which informs all connected
+ * {@link DatabaseUpdateListener} about database changes by invoking
+ * {@link #fireDatabaseUpdate(DatabaseUpdateEvent)} method.<br>
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *
+ */
+public class DatabaseUpdateEmitter {
+  /** Holds the connected listeners. */
+  protected List<DatabaseUpdateListener> listeners = new ArrayList<DatabaseUpdateListener>();
+  
+  /**
+   * Adds a listener. Every {@link DatabaseUpdateListener}
+   * can only be connected once.
+   * @return {@code true} if the listener was added 
+   */
+  public boolean addDatabaseUpdateListener(DatabaseUpdateListener l) {
+    if ( listeners.contains(l) )
+      return false;
+    return listeners.add(l);
+  }
+
+  /**
+   * Removes a listener.
+   */
+  public boolean removeDatabaseUpdateListener(DatabaseUpdateListener l) {
+    return listeners.remove(l);
+  }
+
+  /**
+   * Returns all connected listeners.
+   */
+  public List<DatabaseUpdateListener> getDatabaseUpdateListeners() {
+    return listeners;
+  }
+
+  /**
+   * Calls {@link DatabaseUpdateListener#databaseUpdated(DatabaseUpdateEvent)}
+   * for all connected listeners.
+   */
+  public void fireDatabaseUpdate(DatabaseUpdateEvent e) {
+    for (DatabaseUpdateListener l : listeners)
+      l.databaseUpdated(e);
+  }
+
+  /**
+   * Calls {@link DatabaseUpdateListener#databaseUpdated(DatabaseUpdateEvent)}
+   * for all connected listeners.
+   * @param source object which initiates the event
+   * @param updatedRecord updated database entity
+   */
+  public void fireDatabaseUpdate(Object source, Object updatedRecord) {
+    fireDatabaseUpdate(new DatabaseUpdateEvent(source, updatedRecord));
+  }
+
+  /**
+   * Calls {@link DatabaseUpdateListener#databaseUpdated(DatabaseUpdateEvent)}
+   * for all connected listeners.
+   * @param source object which initiates the event
+   * @param deletedRecord deleted database entity
+   */
+  public void fireDatabaseRecordDeleted(Object source, Object deletedRecord) {
+	  fireDatabaseUpdate(new DatabaseRecordDeletedEvent(source, deletedRecord));
+  }
+
+  /**
+   * Calls {@link DatabaseUpdateListener#databaseUpdated(DatabaseUpdateEvent)}
+   * for all connected listeners
+   * @param source object which initiates the event
+   * @param updatedType updated type/table
+   */
+  public void fireDatabaseUpdate(Object source, Class<?> updatedType) {
+    fireDatabaseUpdate(new DatabaseUpdateEvent(source, updatedType));
+  }
+
+  /**
+   * Calls {@link DatabaseUpdateListener#databaseConnectionEstablished()}
+   * for all connected listeners.
+   */
+  public void fireDatabaseConnectionEstablished() {
+    for (DatabaseUpdateListener l : listeners)
+      l.databaseConnectionStateChanged(true);
+  }
+
+  /**
+   * Calls {@link DatabaseUpdateListener#databaseConnectionReleased()}
+   * for all connected listeners.
+   */
+  public void fireDatabaseConnectionReleased() {
+    for (DatabaseUpdateListener l : listeners)
+      l.databaseConnectionStateChanged(false);
+  }
+
+}

Added: trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/event/DatabaseUpdateEvent.java
===================================================================
--- trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/event/DatabaseUpdateEvent.java	                        (rev 0)
+++ trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/event/DatabaseUpdateEvent.java	2013-03-25 21:10:30 UTC (rev 2285)
@@ -0,0 +1,126 @@
+package de.schmitzm.db.hibernate.gui.event;
+
+import de.schmitzm.db.hibernate.DBUtil;
+
+/**
+ * Ereignis einer DB-Aenderungen (Daten, Verbindung, ...).
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *
+ */
+public class DatabaseUpdateEvent{
+  /** Enthaelt die Tabelle, die sich geaendert hat. */
+  protected String updatedTable = null;
+  /** Enthaelt den zur Tabelle korrespondierenden Datentyp,
+   *  der sich geaendert hat. */
+  protected Class<?> updatedType = null;
+  /** Enthaelt den Datensatz, der sich geaendert hat. */
+  protected Object updatedRecord = null;
+  
+  /** Enthaelt des Ausloeser des Events. */
+  protected Object updateSource = null;
+  
+  /**
+   * Erzeugt ein neues Event. Dem Event wird kein Datensatz zugeordnet.
+   * @param source Ausloeser des Events.
+   * @param updatedTable Tabelle, die sich geaendert hat
+   * @param updatedType  Zu der Tabelle korrespondierender Datentyp
+   */
+  public <E> DatabaseUpdateEvent(Object source, String updatedTable, Class<E> updatedType) {
+    this.updateSource = source;
+    this.updatedType = updatedType;
+    this.updatedTable = updatedTable;
+    this.updatedRecord = null;
+  }
+
+  /**
+   * Erzeugt ein neues Event. Dem Event wird kein Datentyp zugeordnet.
+   * @param source Ausloeser des Events.
+   * @param updatedTable Tabelle, die sich geaendert hat
+   * @param updatedRecord  Datensatz, der sich geaendert hat
+   */
+  public <E> DatabaseUpdateEvent(Object source, String updatedTable, Object updatedRecord) {
+    this.updateSource = source;
+    this.updatedTable = updatedTable;
+    this.updatedType  = updatedRecord != null ? updatedRecord.getClass() : null;
+    this.updatedRecord = updatedRecord;
+  }
+
+  /**
+   * Erzeugt ein allgemeines Event. Dem Event wird weder ein Datentyp,
+   * noch eine Tabelle oder ein Datensatz zugeordnet.
+   */
+  public <E> DatabaseUpdateEvent() {
+    this(null, null,(Class<?>)null);
+  }
+
+  /**
+   * Erzeugt ein allgemeines Event. Dem Event wird weder ein Datentyp,
+   * noch eine Tabelle oder ein Datensatz zugeordnet.
+   * @param source Ausloeser des Events.
+   */
+  public <E> DatabaseUpdateEvent(Object source) {
+    this(source, null,(Class<?>)null);
+  }
+
+  /**
+   * Erzeugt ein neues Event. Dem Event wird weder ein Datentyp,
+   * noch ein Datensatz zugeordnet.
+   * @param source Ausloeser des Events.
+   * @param updatedTable Tabelle, die sich geaendert hat
+   */
+  public <E> DatabaseUpdateEvent(Object source, String updatedTable) {
+    this(source, updatedTable,(Class<?>)null);
+  }
+
+  /**
+   * Erzeugt ein neues Event. Die Tablle wird ueber
+   * {@link DBUtil#getDatabaseTable(Class)} ermittelt. Dem Event
+   * wird kein Datensatz zugeordnet.
+   * @param source Ausloeser des Events.
+   * @param updatedType   Datentyp, der sich geaendert hat
+   */
+  public <E> DatabaseUpdateEvent(Object source, Class<E> updatedType) {
+    this(source, DBUtil.getDatabaseTable(updatedType), updatedType);
+  }
+
+  /**
+   * Erzeugt ein neues Event. Die Tablle wird ueber
+   * {@link DBUtil#getDatabaseTable(Class)} ermittelt.
+   * @param source Ausloeser des Events.
+   * @param updatedRecord  Datensatz, der sich geaendert hat
+   */
+  public <E> DatabaseUpdateEvent(Object source, Object updatedRecord) {
+    this(source, updatedRecord != null ? DBUtil.getDatabaseTable( updatedRecord.getClass()) : null, updatedRecord);
+  }
+
+  /**
+   * Liefert den Ausloeser des Events.
+   */
+  public Object getSource() {
+    return updateSource;
+  }
+
+  /**
+   * Liefert die Tabelle, die sich geaendert hat.
+   */
+  public String getUpdatedTable() {
+    return updatedTable;
+  }
+
+  /**
+   * Liefert den Datentyp, der geaendert hat.
+   */
+  public Class<?> getUpdatedType() {
+    return updatedType;
+  }
+
+  /**
+   * Liefert den Datensatz, der geaendert hat.
+   */
+  public Object getUpdatedRecord() {
+    return updatedRecord;
+  }
+
+
+
+}

Added: trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/event/DatabaseUpdateListener.java
===================================================================
--- trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/event/DatabaseUpdateListener.java	                        (rev 0)
+++ trunk/schmitzm-hibernate/src/main/java/de/schmitzm/db/hibernate/gui/event/DatabaseUpdateListener.java	2013-03-25 21:10:30 UTC (rev 2285)
@@ -0,0 +1,20 @@
+package de.schmitzm.db.hibernate.gui.event;
+
+/**
+ * Listener, which reacts on database changes.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *
+ */
+public interface DatabaseUpdateListener {
+  /**
+   * Called when a table changes.
+   */
+  public void databaseUpdated(DatabaseUpdateEvent e);
+
+  /**
+   * Called when the database connection state changes.
+   * @param connected indicates whether the connection was established or closed
+   */
+  public void databaseConnectionStateChanged(boolean connected);
+
+}

Modified: trunk/schmitzm-hibernate/src/main/resources/de/schmitzm/db/hibernate/resource/locales/HibernateResourceBundle.properties
===================================================================
--- trunk/schmitzm-hibernate/src/main/resources/de/schmitzm/db/hibernate/resource/locales/HibernateResourceBundle.properties	2013-03-25 21:07:57 UTC (rev 2284)
+++ trunk/schmitzm-hibernate/src/main/resources/de/schmitzm/db/hibernate/resource/locales/HibernateResourceBundle.properties	2013-03-25 21:10:30 UTC (rev 2285)
@@ -35,4 +35,10 @@
 HibernateApplication.db.conn.dialog.title=Database connection
 HibernateApplication.db.conn.progress.mess=Establishing database connection ...
 
+GUIUtil.save.confirm.mess=Changes were made. Do you want to save the changes in database?
+GUIUtil.save.confirm.mess.title=Save changes
 
+DatabaseSearchQueryToolBar.Query=Query:
+DatabaseSearchQueryToolBar.SEARCH=search
+DatabaseSearchQueryToolBar.SEARCH.desc=Submit search query
+

Modified: trunk/schmitzm-hibernate/src/main/resources/de/schmitzm/db/hibernate/resource/locales/HibernateResourceBundle_de.properties
===================================================================
--- trunk/schmitzm-hibernate/src/main/resources/de/schmitzm/db/hibernate/resource/locales/HibernateResourceBundle_de.properties	2013-03-25 21:07:57 UTC (rev 2284)
+++ trunk/schmitzm-hibernate/src/main/resources/de/schmitzm/db/hibernate/resource/locales/HibernateResourceBundle_de.properties	2013-03-25 21:10:30 UTC (rev 2285)
@@ -35,3 +35,9 @@
 HibernateApplication.db.conn.dialog.title=Datenbank-Anmeldung
 HibernateApplication.db.conn.progress.mess=Datenbank-Verbindung wird aufgebaut...
 
+GUIUtil.save.confirm.mess=Es wurden Änderungen vorgenommen. Wollen Sie diese speichern?
+GUIUtil.save.confirm.mess.title=Änderungen speichern
+
+DatabaseSearchQueryToolBar.Query=Anfrage:
+DatabaseSearchQueryToolBar.SEARCH=suchen
+DatabaseSearchQueryToolBar.SEARCH.desc=Suchanfrage absetzen



More information about the Schmitzm-commits mailing list