fixed an issue with pring not correctly handling the datasource after a transaction
authorn.hoffmann <n.hoffmann@localhost>
Mon, 6 Apr 2009 15:51:13 +0000 (15:51 +0000)
committern.hoffmann <n.hoffmann@localhost>
Mon, 6 Apr 2009 15:51:13 +0000 (15:51 +0000)
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/conversation/ConversationHolder.java
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/conversation/IConversationEnabled.java
cdmlib-services/src/test/java/eu/etaxonomy/cdm/test/function/TestConcurrentSession.java
cdmlib-services/src/test/java/eu/etaxonomy/cdm/test/function/TestConversationEnabled.java
cdmlib-services/src/test/resources/eu/etaxonomy/cdm/applicationContext-test.xml

index 32cb742b80e00b2d830666bff01f9264e1b0f117..df8a14f94ad556a7e0ccede005bb55dd29b55de7 100644 (file)
@@ -3,6 +3,8 @@
  */
 package eu.etaxonomy.cdm.api.conversation;
 
+import java.util.Map;
+
 import javax.sql.DataSource;
 
 import org.apache.log4j.Logger;
@@ -20,7 +22,7 @@ import org.springframework.transaction.TransactionStatus;
 import org.springframework.transaction.support.ResourceHolder;
 import org.springframework.transaction.support.TransactionSynchronizationManager;
 
-import eu.etaxonomy.cdm.persistence.hibernate.CdmPostCrudObservableListener;
+import eu.etaxonomy.cdm.persistence.hibernate.CdmPostDataChangeObservableListener;
 
 /**
  * This is an implementation of the session-per-conversation pattern for usage
@@ -46,6 +48,7 @@ public class ConversationHolder{
        private PlatformTransactionManager transactionManager;
 
 
+       
        /**
         * The persistence context for this conversation
         */
@@ -86,69 +89,47 @@ public class ConversationHolder{
         */
        public void bind() {
                
-
-               if(TransactionSynchronizationManager.hasResource(getSessionFactory())){
-                       TransactionSynchronizationManager.unbindResource(getSessionFactory());
-               }
-
-               /*
-                * FIXME it is a rather strange behaviour that HibernateTransactionManager 
-                * binds a dataSource and then complains about that later on. At least that 
-                * is what happens in the editor.
-                * 
-                *  With this in the code the tests will not run, but the editor for now.
-                * 
-                */
-//             if(TransactionSynchronizationManager.hasResource(getDataSource())){
-//                     TransactionSynchronizationManager.unbindResource(getDataSource());
-//             }
-       
+               logger.info("Binding resources for ConversationHolder: [" + this + "]");        
                
                if(TransactionSynchronizationManager.isSynchronizationActive()){
                        TransactionSynchronizationManager.clearSynchronization();
                }
-
-               
-               logger.info("Binding resources for ConversationHolder: [" + this + "]");
                
-               // lazy creation of session
-               if (longSession == null) {
-                       longSession = SessionFactoryUtils.getNewSession(getSessionFactory());
-                       longSession.setFlushMode(FlushMode.MANUAL);
-
-                       // TODO set the ConnectionReleaseMode to AFTER_TRANSACTION, possibly in applicationContext
+               try{
+                       // FIXME for debugging -> remove
+                       Map resourceMap = TransactionSynchronizationManager.getResourceMap();
                        
-                       logger.info("Creating Session: [" + longSession + "]");
-               }
+                       
+                       logger.info("Starting new Synchronization in TransactionSynchronizationManager.");
+                       TransactionSynchronizationManager.initSynchronization();
+                       
+                       if(TransactionSynchronizationManager.hasResource(getSessionFactory())){
+                               TransactionSynchronizationManager.unbindResource(getSessionFactory());
+                       }
+                       
+                       logger.info("Binding Session to TransactionSynchronizationManager.");
+                       TransactionSynchronizationManager.bindResource(getSessionFactory(), getSessionHolder());
+                       
+               }catch(Exception e){
+                       logger.error("Error binding resources for session", e);
+               }                       
                
-
-               // lazy creation of session holder
-               if(sessionHolder == null){
-                       sessionHolder = new SessionHolder(longSession);
+       }
+       
+       public SessionHolder getSessionHolder(){
+               if(this.sessionHolder == null){
                        logger.info("Creating SessionHolder: [" + sessionHolder + "]");
+                       this.sessionHolder = new SessionHolder(getSession());
                }
-               
-               // connect dataSource with session
-               if (!longSession.isConnected()){
-                       
-                       longSession.reconnect(DataSourceUtils.getConnection(dataSource));
-                       logger.info("Reconnecting DataSource: [" + dataSource + "]" );
-               }
-               
-               
-               logger.info("Binding Session to TransactionSynchronizationManager.");
-               TransactionSynchronizationManager.bindResource(getSessionFactory(), sessionHolder);
-
-               logger.info("Starting new Synchronization in TransactionSynchronizationManager.");
-               TransactionSynchronizationManager.initSynchronization();
-               
-               
+               return this.sessionHolder;
        }
        
+       
+       
        /**
         * @return
         */
-       private DataSource getDataSource() {
+       public DataSource getDataSource() {
                return this.dataSource;
        }
 
@@ -171,9 +152,8 @@ public class ConversationHolder{
                        logger.warn("We allow only one transaction at the moment but startTransaction " +
                                        "was called a second time.\nReturning the transaction already associated with this " +
                                        "ConversationManager");
-               }else{  
+               }else{                          
                        transactionStatus = transactionManager.getTransaction(definition);
-
                        
                        logger.info("Transaction started: [" + transactionStatus + "]");
                }
@@ -205,7 +185,10 @@ public class ConversationHolder{
                        
                        // commit the changes
                        transactionManager.commit(transactionStatus);
-                                               
+                       
+                       // propagate transaction end
+                       CdmPostDataChangeObservableListener.getDefault().delayedNotify();       
+                       
                        // Reset the transactionStatus.
                        transactionStatus = null;
                        
@@ -235,6 +218,18 @@ public class ConversationHolder{
         * @return the session associated with this conversation manager 
         */
        public Session getSession() {
+               if(longSession == null){
+                       logger.info("Creating Session: [" + longSession + "]");
+                       longSession = SessionFactoryUtils.getNewSession(getSessionFactory());
+                       longSession.setFlushMode(FlushMode.MANUAL);
+               }
+               
+               // connect dataSource with session
+               if (!longSession.isConnected()){
+                       longSession.reconnect(DataSourceUtils.getConnection(getDataSource()));
+                       logger.info("Reconnecting DataSource: [" + dataSource + "]" );
+               }
+               
                return longSession;
        }
        
@@ -274,6 +269,6 @@ public class ConversationHolder{
         * Register to get updated after any interaction with the datastore
         */
        public void registerForDataStoreChanges(IConversationEnabled observer) {
-               CdmPostCrudObservableListener.getDefault().register(observer);
+               CdmPostDataChangeObservableListener.getDefault().register(observer);
        }
 }
index 8edb941b883e48fae902529942fe4a32cfe1ad66..166a402da533f535374bb8b07f27b6cf5cc1d246 100644 (file)
@@ -9,7 +9,7 @@
 
 package eu.etaxonomy.cdm.api.conversation;
 
-import eu.etaxonomy.cdm.persistence.hibernate.ICdmPostCrudObserver;
+import eu.etaxonomy.cdm.persistence.hibernate.ICdmPostDataChangeObserver;
 
 
 /**
@@ -19,7 +19,7 @@ import eu.etaxonomy.cdm.persistence.hibernate.ICdmPostCrudObserver;
  * @created 17.03.2009
  * @version 1.0
  */
-public interface IConversationEnabled extends ICdmPostCrudObserver {
+public interface IConversationEnabled extends ICdmPostDataChangeObserver {
        
        /** 
         * @return the conversation holder
index e5d4661e148f67e85836530811d2b9e6555c8d47..613c347226d2602253dcdf824a7ab1b87e391b8a 100644 (file)
@@ -357,7 +357,7 @@ public class TestConcurrentSession extends CdmIntegrationTest{
        public void testProofOfDataPersistency(){
                // first conversation
                conversationHolder1.bind();
-               TransactionStatus txStatusOne = transactionManager.getTransaction(definition);
+               conversationHolder1.startTransaction();
                // get a taxon
                TaxonBase taxonBase = taxonService.getTaxonByUuid(taxonUuid1);
                // get a reference
@@ -368,12 +368,12 @@ public class TestConcurrentSession extends CdmIntegrationTest{
                taxonBase.setSec(reference);
                // save and commit
                taxonService.save(taxonBase);
-               transactionManager.commit(txStatusOne);
+               conversationHolder1.commit();
                
                
                // second conversation
                conversationHolder2.bind();
-               TransactionStatus txStatusTwo = transactionManager.getTransaction(definition);
+               conversationHolder2.startTransaction();
                // load the same taxon in a different session
                TaxonBase taxonBaseInSecondTransaction = taxonService.getTaxonByUuid(taxonUuid1);
                // load the reference
@@ -479,6 +479,20 @@ public class TestConcurrentSession extends CdmIntegrationTest{
                conversationHolder1.commit();           
        }
        
+       @Test
+       @DataSet("ConcurrentSessionTest.xml")
+       public void testMultipleTransactionsInMultipleSessions(){
+               conversationHolder1.bind();
+               conversationHolder1.startTransaction();
+               
+               conversationHolder2.bind();
+               conversationHolder2.startTransaction();
+               
+               conversationHolder3.bind();
+               conversationHolder3.startTransaction();
+       }
+       
+       
        @Test
        @DataSet("ConcurrentSessionTest.xml")
        public void testInsert(){
index b30538e45b13974adada9ab99598fe91e76028d9..fca060710209cf10f51e375978893e96d6e25a4c 100644 (file)
 
 package eu.etaxonomy.cdm.test.function;
 
+import java.util.List;
 import java.util.Observable;
 
 import org.apache.log4j.Logger;
 
 import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
 import eu.etaxonomy.cdm.api.conversation.IConversationEnabled;
-import eu.etaxonomy.cdm.persistence.hibernate.CdmCrudEvent;
+import eu.etaxonomy.cdm.persistence.hibernate.CdmDataChangeEvent;
 
 /**
- * @author nho
+ * @author n.hoffmann
  * @created 25.03.2009
  * @version 1.0
  */
@@ -40,8 +41,10 @@ public class TestConversationEnabled implements IConversationEnabled {
        /* (non-Javadoc)
         * @see eu.etaxonomy.cdm.persistence.hibernate.ICdmPostCrudObserver#update(eu.etaxonomy.cdm.persistence.hibernate.CdmCrudEvent)
         */
-       public void update(CdmCrudEvent event) {
-               logger.warn("CdmCrudEvent fired: " + event.getEventType() + " : " + event.getEntity());
+       public void update(List<CdmDataChangeEvent> events) {
+               for(CdmDataChangeEvent event : events){
+                       logger.warn("CdmCrudEvent fired: " + event.getEventType() + " : " + event.getEntity());
+               }
        }
 
        /* (non-Javadoc)
index 363dcf2f5019d13d8386f18c10721c0a6ac3920a..28079ee2b8b0477299e9373e08d982122b7ce028 100644 (file)
        <context:component-scan base-package="eu/etaxonomy/cdm/api"/>\r
     \r
     <!-- enable the configuration of transactional behavior based on annotations -->\r
-<!--    <tx:annotation-driven transaction-manager="transactionManager"/>      -->\r
-  \r
-       <bean id="conversationHolder" class="eu.etaxonomy.cdm.api.conversation.ConversationHolder" scope="prototype"/>\r
-       \r
-
+    <tx:annotation-driven transaction-manager="transactionManager"/>      \r
+  
     <bean id="dataSource" class="org.unitils.database.UnitilsDataSourceFactoryBean"/>\r
     \r
     <bean id="hibernateProperties" \r