*/
package eu.etaxonomy.cdm.api.conversation;
+import java.util.Map;
+
import javax.sql.DataSource;
import org.apache.log4j.Logger;
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
private PlatformTransactionManager transactionManager;
+
/**
* The persistence context for this conversation
*/
*/
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;
}
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 + "]");
}
// commit the changes
transactionManager.commit(transactionStatus);
-
+
+ // propagate transaction end
+ CdmPostDataChangeObservableListener.getDefault().delayedNotify();
+
// Reset the transactionStatus.
transactionStatus = null;
* @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;
}
* Register to get updated after any interaction with the datastore
*/
public void registerForDataStoreChanges(IConversationEnabled observer) {
- CdmPostCrudObservableListener.getDefault().register(observer);
+ CdmPostDataChangeObservableListener.getDefault().register(observer);
}
}
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
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
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(){