package org.mobicents.slee.runtime.transaction; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import javax.slee.transaction.CommitListener; import javax.slee.transaction.RollbackListener; import javax.slee.transaction.SleeTransaction; import javax.transaction.HeuristicMixedException; import javax.transaction.HeuristicRollbackException; import javax.transaction.RollbackException; import javax.transaction.Status; import javax.transaction.Synchronization; import javax.transaction.SystemException; import javax.transaction.xa.XAResource; import com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionImple; public class SleeTransactionImpl implements SleeTransaction { /** * thread pool for async commit/rollback operations */ private static final ExecutorService executorService = Executors .newCachedThreadPool(); /** * the wrapped JBossTS transaction */ private final TransactionImple transaction; /** * caching the wrapped transaction id */ private final String transactionId; /** * the transaction manager */ private final SleeTransactionManagerImpl transactionManager; private boolean asyncOperationInitiated = false; public SleeTransactionImpl(TransactionImple transaction, SleeTransactionManagerImpl transactionManager) { this.transaction = transaction; this.transactionId = transaction.get_uid().toString(); this.transactionManager = transactionManager; } /** * Some operations require that the transaction be suspended * @throws SystemException */ private void suspendIfAssoaciatedWithThread() throws SystemException { // if there is a tx associated with this thread and it is this one // then suspend it to dissociate the thread SleeTransaction currentThreadTransaction = transactionManager .getSleeTransaction(); if (currentThreadTransaction != null && currentThreadTransaction.equals(this)) { transactionManager.suspend(); } } /** * Verifies if the wrapped transaction is active and if dissociates it from * the thread if needed * * @throws IllegalStateException * @throws SecurityException */ private void beforeAsyncOperation() throws IllegalStateException, SecurityException { try { int status = transaction.getStatus(); if (asyncOperationInitiated || (status != Status.STATUS_ACTIVE && status != Status.STATUS_MARKED_ROLLBACK)) { throw new IllegalStateException( "There is no active tx, tx is in state: " + status); } asyncOperationInitiated = true; suspendIfAssoaciatedWithThread(); } catch (SystemException e) { throw new IllegalStateException(e); } } public void asyncCommit(CommitListener commitListener) throws IllegalStateException, SecurityException { beforeAsyncOperation(); executorService.submit(new AsyncTransactionCommitRunnable( commitListener, transaction)); } public void asyncRollback(RollbackListener rollbackListener) throws IllegalStateException, SecurityException { beforeAsyncOperation(); executorService.submit(new AsyncTransactionRollbackRunnable( rollbackListener, transaction)); } public boolean delistResource(XAResource arg0, int arg1) throws IllegalStateException, SystemException { return transaction.delistResource(arg0, arg1); } public boolean enlistResource(XAResource arg0) throws IllegalStateException, RollbackException { try { return transaction.enlistResource(arg0); } catch (SystemException e) { // this should be a bug in slee 1.1 api, the exceptions thrown // should match jta transaction interface throw new RuntimeException(e); } } public void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException, SecurityException, IllegalStateException, SystemException { if (asyncOperationInitiated) { throw new IllegalStateException(); } try { transaction.commit(); } finally { suspendIfAssoaciatedWithThread(); } } public int getStatus() throws SystemException { return transaction.getStatus(); } public void registerSynchronization(Synchronization sync) throws RollbackException, IllegalStateException, SystemException { transaction.registerSynchronization(sync); } public void rollback() throws IllegalStateException, SystemException { if (asyncOperationInitiated) { throw new IllegalStateException(); } try { transaction.rollback(); } finally { suspendIfAssoaciatedWithThread(); } } public void setRollbackOnly() throws IllegalStateException, SystemException { transaction.setRollbackOnly(); } @Override public String toString() { return transactionId; } @Override public int hashCode() { return transactionId.hashCode(); } @Override public boolean equals(Object obj) { if (obj != null && obj.getClass() == this.getClass()) { return ((SleeTransactionImpl) obj).transactionId .equals(this.transactionId); } else { return false; } } }