com.atomikos.jms.internal.ConsumerProducerSupport Maven / Gradle / Ivy
/**
* Copyright (C) 2000-2023 Atomikos
*
* LICENSE CONDITIONS
*
* See http://www.atomikos.com/Main/WhichLicenseApplies for details.
*/
package com.atomikos.jms.internal;
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 && TransactionManagerImp.isJtaTransaction(ct)) {
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. create a non-transacted session and do session acknowledgment yourself, or" + "\n" +
"3. 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 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();
}
}
}