/** * Copyright (C) 2000-2016 Atomikos <info@atomikos.com> * * LICENSE CONDITIONS * * See http://www.atomikos.com/Main/WhichLicenseApplies for details. */ package com.atomikos.jms; import javax.jms.JMSException; import com.atomikos.datasource.xa.session.InvalidSessionHandleStateException; import com.atomikos.datasource.xa.session.SessionHandleState; import com.atomikos.icatch.CompositeTransaction; import com.atomikos.icatch.CompositeTransactionManager; import com.atomikos.icatch.Synchronization; import com.atomikos.icatch.config.Configuration; import com.atomikos.icatch.jta.TransactionManagerImp; import com.atomikos.logging.Logger; import com.atomikos.logging.LoggerFactory; import com.atomikos.recovery.TxState; /** * Support for common logic in producer and consumer. * */ abstract class ConsumerProducerSupport { private static final Logger LOGGER = LoggerFactory.createLogger(ConsumerProducerSupport.class); private SessionHandleState state; protected ConsumerProducerSupport ( SessionHandleState state ) { this.state = state; } protected void handleException ( Exception e ) throws AtomikosJMSException { state.notifySessionErrorOccurred(); AtomikosJMSException.throwAtomikosJMSException ( "Error in proxy" , e ); } private CompositeTransactionManager getCompositeTransactionManager() { CompositeTransactionManager ret = null; ret = Configuration.getCompositeTransactionManager(); return ret; } protected void enlist() throws JMSException { CompositeTransaction ct = null; CompositeTransactionManager ctm = getCompositeTransactionManager(); boolean enlist = false; if ( ctm != null ) { ct = ctm.getCompositeTransaction(); if ( ct != null && ct.getProperty ( TransactionManagerImp.JTA_PROPERTY_NAME ) != null ) { enlist = true; } } if ( enlist ) { registerSynchronization ( ct ); try { state.notifyBeforeUse ( ct ); } catch ( InvalidSessionHandleStateException ex ) { String msg = "error during enlist: " + ex.getMessage(); LOGGER.logWarning ( this + ": " + msg ); AtomikosJMSException.throwAtomikosJMSException ( msg , ex ); } } else { String msg = "The JMS session you are using requires a JTA transaction context for the calling thread and none was found." + "\n" + "Please correct your code to do one of the following: " + "\n" + "1. start a JTA transaction if you want your JMS operations to be subject to JTA commit/rollback, or" + "\n" + "2. increase the maxPoolSize of the AtomikosConnectionFactoryBean to avoid transaction timeout while waiting for a connection, or" + "\n" + "3. create a non-transacted session and do session acknowledgment yourself, or" + "\n" + "4. set localTransactionMode to true so connection-level commit/rollback are enabled."; LOGGER.logWarning ( this + ": " + msg ); AtomikosTransactionRequiredJMSException.throwAtomikosTransactionRequiredJMSException ( msg ); } } private void registerSynchronization ( CompositeTransaction ct ) throws AtomikosJMSException { if ( LOGGER.isTraceEnabled() ) LOGGER.logTrace ( this + ": detected transaction " + ct ); ct.registerSynchronization ( new JmsRequeueSynchronization( ct ) ); } private class JmsRequeueSynchronization implements Synchronization { private static final long serialVersionUID = 1L; private CompositeTransaction compositeTransaction; private boolean afterCompletionDone; public JmsRequeueSynchronization ( CompositeTransaction compositeTransaction) { this.compositeTransaction = compositeTransaction; this.afterCompletionDone = false; } public void afterCompletion(TxState txState) { if ( afterCompletionDone ) return; if ( txState.isHeuristic() || txState == TxState.TERMINATED ) { if ( LOGGER.isTraceEnabled() ) LOGGER.logTrace( "JmsRequeueSynchronization: detected termination of transaction " + compositeTransaction ); state.notifyTransactionTerminated(compositeTransaction); if ( LOGGER.isTraceEnabled() ) LOGGER.logTrace( "JmsRequeueSynchronization: is in terminated state ? " + state.isTerminated() ); afterCompletionDone = true; } } public void beforeCompletion() { } //override equals: synchronizations for the same tx are equal //to avoid receiving double notifications on termination! public boolean equals ( Object other ) { boolean ret = false; if ( other instanceof JmsRequeueSynchronization ) { JmsRequeueSynchronization o = ( JmsRequeueSynchronization ) other; ret = this.compositeTransaction.isSameTransaction ( o.compositeTransaction ); } return ret; } public int hashCode() { return compositeTransaction.hashCode(); } } }