/* * JBoss, Home of Professional Open Source. * Copyright 2017, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY 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 along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.as.txn.integration; import javax.resource.spi.XATerminator; import javax.resource.spi.work.Work; import javax.resource.spi.work.WorkCompletedException; import javax.transaction.InvalidTransactionException; import javax.transaction.SystemException; import javax.transaction.xa.XAException; import javax.transaction.xa.Xid; import org.jboss.as.txn.logging.TransactionLogger; import org.jboss.tm.JBossXATerminator; import org.wildfly.transaction.client.ContextTransactionManager; import org.wildfly.transaction.client.ImportResult; import org.wildfly.transaction.client.LocalTransaction; import org.wildfly.transaction.client.LocalTransactionContext; import com.arjuna.ats.internal.jta.transaction.arjunacore.jca.SubordinationManager; public class JBossContextXATerminator implements JBossXATerminator { private final LocalTransactionContext localTransactionContext; private final XATerminator contextXATerminator; private final JBossXATerminator jbossXATerminator; public JBossContextXATerminator(LocalTransactionContext transactionContext, JBossXATerminator jbossXATerminator) { this.localTransactionContext = transactionContext; this.contextXATerminator = transactionContext.getXATerminator(); this.jbossXATerminator = jbossXATerminator; } @Override public void commit(Xid xid, boolean onePhase) throws XAException { contextXATerminator.commit(xid, onePhase); } @Override public void forget(Xid xid) throws XAException { contextXATerminator.forget(xid); } @Override public int prepare(Xid xid) throws XAException { return contextXATerminator.prepare(xid); } @Override public Xid[] recover(int flag) throws XAException { return contextXATerminator.recover(flag); } @Override public void rollback(Xid xid) throws XAException { contextXATerminator.rollback(xid); } /** * <p> * Interception of register work call to get transaction being imported to wildfly transacton client. * <p> * For importing a transaction Wildfly transaction client eventually calls {@link SubordinationManager} * as Narayana {@link XATerminator}s do. This wrapping then let wildfly transacton client to register the transaction * for itself, wildfly transacton client then import transaction to Narayana too and finally this method * uses Narayana's {@link XATerminator} to register all {@link Work}s binding.<br> * Narayana's {@link XATerminator} tries to import transaction too but as transaction is already * imported it just gets instance of transaction already imported via call of wildfly transacton client. */ @Override public void registerWork(Work work, Xid xid, long timeout) throws WorkCompletedException { try { // jca provides timeout in milliseconds, SubordinationManager expects seconds int timeout_seconds = (int) timeout/1000; // unlimited timeout for jca means -1 which fails in wfly client if(timeout_seconds <= 0) timeout_seconds = ContextTransactionManager.getGlobalDefaultTransactionTimeout(); localTransactionContext.findOrImportTransaction(xid, timeout_seconds); } catch (XAException xae) { throw TransactionLogger.ROOT_LOGGER.cannotFindOrImportInflowTransaction(xid, work, xae); } jbossXATerminator.registerWork(work, xid, timeout); } /** * <p> * Start work gets imported transaction and assign it to current thread. * <p> * This method mimics behavior of Narayana's {@link JBossXATerminator}. */ @Override public void startWork(Work work, Xid xid) throws WorkCompletedException { LocalTransaction transaction = null; try { ImportResult<LocalTransaction> transactionImportResult = localTransactionContext.findOrImportTransaction(xid, 0); transaction = transactionImportResult.getTransaction(); ContextTransactionManager.getInstance().resume(transaction); } catch (XAException xae) { throw TransactionLogger.ROOT_LOGGER.cannotFindOrImportInflowTransaction(xid, work, xae); } catch (InvalidTransactionException ite) { throw TransactionLogger.ROOT_LOGGER.importedInflowTransactionIsInactive(xid, work, ite); } catch (SystemException se) { throw TransactionLogger.ROOT_LOGGER.cannotResumeInflowTransactionUnexpectedError(transaction, work, se); } } /** * <p> * Suspending transaction and canceling the work. * <p> * Suspend transaction has to be called on the wildfly transaction manager * and the we delegate work cancellation to {@link JBossXATerminator}.<br> * First we have to cancel the work for jboss terminator would not work with * suspended transaction. */ @Override public void endWork(Work work, Xid xid) { jbossXATerminator.cancelWork(work, xid); try { ContextTransactionManager.getInstance().suspend(); } catch (SystemException se) { throw TransactionLogger.ROOT_LOGGER.cannotSuspendInflowTransactionUnexpectedError(work, se); } } /** * <p> * Calling {@link JBossXATerminator} to cancel the work for us. * <p> * There should not be need any action to be processed by wildfly transaction client. */ @Override public void cancelWork(Work work, Xid xid) { jbossXATerminator.cancelWork(work, xid); } }