/* * JBoss, Home of Professional Open Source * Copyright 2006, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. * See the copyright.txt in the distribution for a * full listing of individual contributors. * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License, v. 2.1. * This program is distributed in the hope that it will be useful, but WITHOUT A * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public License, * v.2.1 along with this distribution; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * (C) 2005-2006, * @author JBoss Inc. */ /* * Copyright (C) 2005, * * Arjuna Technologies Ltd. * Newcastle upon Tyne, * Tyne and Wear, * UK. * * $Id$ */ package com.arjuna.ats.internal.jbossatx.jta.jca; import javax.resource.spi.work.Work; import javax.resource.spi.work.WorkCompletedException; import javax.resource.spi.work.WorkException; import javax.transaction.InvalidTransactionException; import javax.transaction.Status; import javax.transaction.SystemException; import javax.transaction.Transaction; import javax.transaction.xa.XAException; import javax.transaction.xa.Xid; import com.arjuna.ats.internal.jta.transaction.arjunacore.jca.SubordinationManager; import com.arjuna.ats.internal.jta.transaction.arjunacore.jca.TxWorkManager; import com.arjuna.ats.internal.jta.transaction.arjunacore.jca.WorkSynchronization; import com.arjuna.ats.internal.jta.transaction.arjunacore.jca.XATerminatorImple; import com.arjuna.ats.jbossatx.logging.jbossatxLogger; import com.arjuna.ats.jta.TransactionManager; import org.jboss.tm.JBossXATerminator; /** * The implementation of JBossXATerminator using the purely local (ArjunaCore) * implementation of the JTA. * * The JBossXATerminator is the way in JBoss 4.x for adding work to an inflowed * transaction. JCA 1.5 has the concept of a WorkManager. * * @author mcl */ public class XATerminator extends XATerminatorImple implements JBossXATerminator { private static final Xid[] NO_XIDS = new Xid[0]; /** * Register the unit of work with the specified transaction. The * thread-to-transaction association is not changed yet. Basically this * operation only lets the transaction system know about the work and * nothing else. * * @param work * the work to associate with the transaction. * @param xid * the transaction within which the work will be performed. * @param timeout * the lifetime of the transaction. * * @throws WorkCompletedException * thrown if the work cannot be associated with the transaction. * * */ public void registerWork (Work work, Xid xid, long timeout) throws WorkCompletedException { try { /* * Remember to convert timeout to seconds. */ Transaction tx = SubordinationManager.getTransactionImporter().importTransaction(xid, (int) timeout/1000); switch (tx.getStatus()) { case Status.STATUS_NO_TRANSACTION: case Status.STATUS_UNKNOWN: throw new WorkCompletedException( jbossatxLogger.i18NLogger.get_jta_jca_inactive(), WorkException.TX_RECREATE_FAILED); case Status.STATUS_ACTIVE: break; default: throw new WorkCompletedException( jbossatxLogger.i18NLogger.get_jta_jca_completing(), WorkException.TX_CONCURRENT_WORK_DISALLOWED); } TxWorkManager.addWork(work, tx); /* * TODO currently means one synchronization per work item and that * instance isn't removed when/if the work item is cancelled and * another work item is later added. * * Synchronizations are pretty lightweight and this add/remove/add * scenario will hopefully not happen that much. So, we don't * optimise for it at the moment. Re-evaluate if it does become an * overhead. */ tx.registerSynchronization(new WorkSynchronization(tx)); } catch (WorkCompletedException ex) { throw ex; } catch (XAException ex) { throw new WorkCompletedException(ex); } catch (Exception ex) { ex.printStackTrace(); throw new WorkCompletedException( jbossatxLogger.i18NLogger.get_jta_jca_unknown(), WorkException.INTERNAL); } } /** * Associate the current thread with the specified transaction. In JBoss * 4.x, they assume that the work has already been registered, so we do * likewise, i.e., we don't do a register if it hasn't, but we will throw an * exception (which is more than JBoss does). * * @param work the Work to start * @param xid the transaction to associate with the current thread. * * @throws WorkCompletedException thrown if there are any errors. */ public void startWork (Work work, Xid xid) throws WorkCompletedException { try { Transaction tx = SubordinationManager.getTransactionImporter().importTransaction(xid); // JBoss doesn't seem to use the work parameter! if (!TxWorkManager.getWork(tx).equals(work)) { throw new WorkCompletedException(jbossatxLogger.i18NLogger.get_jta_jca_unknownwork(), WorkException.INTERNAL); } TransactionManager.transactionManager().resume(tx); } catch (XAException ex) { throw new WorkCompletedException(ex); } catch (InvalidTransactionException ex) { throw new WorkCompletedException( jbossatxLogger.i18NLogger.get_jta_jca_inactive(), WorkException.TX_RECREATE_FAILED); } catch (SystemException ex) { throw new WorkCompletedException( jbossatxLogger.i18NLogger.get_jta_jca_unknown(), WorkException.INTERNAL); } } /** * Disassociate the thread from the transaction and remove the * work from the transaction pool of workers. This assumes that * the invoking thread is the one doing the work. * * @param work the Work unit to remove. * @param xid the transaction to remove the work from. */ public void endWork (Work work, Xid xid) { try { Transaction tx = SubordinationManager.getTransactionImporter().importTransaction(xid); TransactionManager.transactionManager().suspend(); TxWorkManager.removeWork(work, tx); } catch (XAException xaException) { throw new RuntimeException(xaException); } catch (SystemException systemException) { throw new RuntimeException(systemException); } } /** * Remove the associated work from the transaction. Do not do * any thread-to-transaction disassociation. * * @param work the unit of work to remove. * @param xid the transaction from which it should be disassociated. */ public void cancelWork (Work work, Xid xid) { try { Transaction tx = SubordinationManager.getTransactionImporter().importTransaction(xid); TxWorkManager.removeWork(work, tx); } catch (XAException xaException) { throw new RuntimeException(xaException); } } }