[jboss-svn-commits] JBL Code SVN: r26793 - in labs/jbosstm/trunk: ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/resources/spi and 6 other directories.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Sun May 31 13:12:43 EDT 2009


Author: mark.little at jboss.com
Date: 2009-05-31 13:12:42 -0400 (Sun, 31 May 2009)
New Revision: 26793

Added:
   labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/resources/spi/
   labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/resources/spi/XATerminatorExtensions.java
Modified:
   labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/transaction/arjunacore/jca/SubordinateTransaction.java
   labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/transaction/arjunacore/jca/SubordinationManager.java
   labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/transaction/arjunacore/jca/XATerminatorImple.java
   labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/transaction/arjunacore/subordinate/SubordinateAtomicAction.java
   labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/transaction/arjunacore/subordinate/TransactionImple.java
   labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/jta/exceptions/UnexpectedConditionException.java
   labs/jbosstm/trunk/ArjunaJTS/jtax/classes/com/arjuna/ats/internal/jta/transaction/jts/jca/XATerminatorImple.java
   labs/jbosstm/trunk/ArjunaJTS/jtax/classes/com/arjuna/ats/internal/jta/transaction/jts/subordinate/SubordinateAtomicTransaction.java
   labs/jbosstm/trunk/ArjunaJTS/jtax/classes/com/arjuna/ats/internal/jta/transaction/jts/subordinate/TransactionImple.java
   labs/jbosstm/trunk/atsintegration/classes/com/arjuna/ats/internal/jbossatx/jta/jca/XATerminator.java
Log:
https://jira.jboss.org/jira/browse/JBTM-560

Added: labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/resources/spi/XATerminatorExtensions.java
===================================================================
--- labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/resources/spi/XATerminatorExtensions.java	                        (rev 0)
+++ labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/resources/spi/XATerminatorExtensions.java	2009-05-31 17:12:42 UTC (rev 26793)
@@ -0,0 +1,67 @@
+/*
+ * 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) 2004,
+ * 
+ * Arjuna Technologies Ltd, Newcastle upon Tyne, Tyne and Wear, UK.
+ * 
+ * $Id: XAResourceErrorHandler.java 2342 2006-03-30 13:06:17Z  $
+ */
+
+package com.arjuna.ats.internal.jta.resources.spi;
+
+import javax.transaction.xa.Xid;
+
+/**
+ * Extensions to the basic XATerminator spi interface. It is important that
+ * these extensions aren't relied on to drive the normal JCA protocol in case
+ * we're ever embedded in a foreign implementation.
+ * 
+ * It would be nice to have these non-XA specific extensions managed by a different
+ * class than the one that deals with the standard XATerminator interface methods,
+ * c.f. JTS/OTS for 2PC and Synchronizations. However, it's a lot easier to just bundle
+ * these together in the same implementation because of the way JCA works. Of course that can
+ * be changed later if necessary and the user(s) won't notice anyway.
+ * 
+ * @author marklittle
+ */
+
+public interface XATerminatorExtensions
+{
+    /*
+     * Synchronizations aren't part of XA, so that's why it would be nice to have these
+     * handled by a separate instance, as well as being architecturally symmetrical with
+     * OTS. But it's not a big deal.
+     */
+    
+    public boolean beforeCompletion (Xid xid) throws javax.transaction.SystemException;
+    
+    /**
+     * Status should be in JTA status values.
+     * 
+     * @param xid
+     * @param status
+     * @return
+     * @throws javax.transaction.SystemException
+     */
+    
+    public boolean afterCompletion (Xid xid, int status) throws javax.transaction.SystemException;
+}

Modified: labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/transaction/arjunacore/jca/SubordinateTransaction.java
===================================================================
--- labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/transaction/arjunacore/jca/SubordinateTransaction.java	2009-05-31 11:32:25 UTC (rev 26792)
+++ labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/transaction/arjunacore/jca/SubordinateTransaction.java	2009-05-31 17:12:42 UTC (rev 26793)
@@ -89,6 +89,22 @@
 	 */
     public void doForget () throws IllegalStateException;
 
+    /**
+     * Run beforeCompletion on Synchronizations.
+     * 
+     * @return outcome
+     */
+    
+    public boolean doBeforeCompletion () throws SystemException;
+    
+    /**
+     * Run afterCompletion on Synchronizations.
+     * 
+     * @return outcome
+     */
+    
+    public boolean doAfterCompletion (int status) throws SystemException;
+    
     public boolean activated();
     
     public void recover();

Modified: labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/transaction/arjunacore/jca/SubordinationManager.java
===================================================================
--- labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/transaction/arjunacore/jca/SubordinationManager.java	2009-05-31 11:32:25 UTC (rev 26792)
+++ labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/transaction/arjunacore/jca/SubordinationManager.java	2009-05-31 17:12:42 UTC (rev 26793)
@@ -144,7 +144,7 @@
     }
 
     /**
-     * Its rather tricky to figure out if we are running in JTA or JTAX(JTS) mode. We can make a resonable guess
+     * Its rather tricky to figure out if we are running in JTA or JTAX(JTS) mode. We can make a reasonable guess
      * based on the transaction manager implementation that is running, but it's going to break if some unknown
      * or derived impl comes along. It's therefore safer to use setTxType explicitly in such cases.
      * 

Modified: labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/transaction/arjunacore/jca/XATerminatorImple.java
===================================================================
--- labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/transaction/arjunacore/jca/XATerminatorImple.java	2009-05-31 11:32:25 UTC (rev 26792)
+++ labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/transaction/arjunacore/jca/XATerminatorImple.java	2009-05-31 17:12:42 UTC (rev 26793)
@@ -42,401 +42,474 @@
 import com.arjuna.ats.arjuna.coordinator.TxControl;
 import com.arjuna.ats.arjuna.objectstore.ObjectStore;
 import com.arjuna.ats.arjuna.state.InputObjectState;
+import com.arjuna.ats.internal.jta.resources.spi.XATerminatorExtensions;
 import com.arjuna.ats.internal.jta.transaction.arjunacore.subordinate.jca.SubordinateAtomicAction;
+import com.arjuna.ats.jta.exceptions.UnexpectedConditionException;
 
 /**
  * The XATerminator implementation.
- *
+ * 
  * @author mcl
- *
  */
 
-public class XATerminatorImple implements javax.resource.spi.XATerminator
+public class XATerminatorImple implements javax.resource.spi.XATerminator, XATerminatorExtensions
 {
-	/**
-	 * Commit the transaction identified and hence any inflow-associated work.
-	 *
-	 * @param xid
-	 *            the transaction to commit
-	 * @param onePhase
-	 *            whether or not this is a one-phase commit (should only be
-	 *            <code>true</code> if there is a single resource associated
-	 *            with the transaction).
-	 *
-	 * @exception XAException
-	 *                thrown if there are any errors, including if the
-	 *                transaction cannot commit and has to roll back.
-	 */
+    /**
+     * Commit the transaction identified and hence any inflow-associated work.
+     * 
+     * @param xid
+     *            the transaction to commit
+     * @param onePhase
+     *            whether or not this is a one-phase commit (should only be
+     *            <code>true</code> if there is a single resource associated
+     *            with the transaction).
+     * @exception XAException
+     *                thrown if there are any errors, including if the
+     *                transaction cannot commit and has to roll back.
+     */
 
-	public void commit(Xid xid, boolean onePhase) throws XAException
-	{
-		try
-		{
-			SubordinateTransaction tx = SubordinationManager.getTransactionImporter().getImportedTransaction(xid);
+    public void commit (Xid xid, boolean onePhase) throws XAException
+    {
+        try
+        {
+            SubordinateTransaction tx = SubordinationManager
+                    .getTransactionImporter().getImportedTransaction(xid);
 
-			if (tx == null)
-				throw new XAException(XAException.XAER_INVAL);
+            if (tx == null)
+                throw new XAException(XAException.XAER_INVAL);
 
-			if (tx.activated())
-			{
-				if (onePhase)
-					tx.doOnePhaseCommit();
-				else
-					tx.doCommit();
+            if (tx.activated())
+            {
+                if (onePhase)
+                    tx.doOnePhaseCommit();
+                else
+                    tx.doCommit();
 
-				SubordinationManager.getTransactionImporter().removeImportedTransaction(xid);
-			}
-			else
-				throw new XAException(XAException.XA_RETRY);
-		}
-        catch(RollbackException e) {
-            SubordinationManager.getTransactionImporter().removeImportedTransaction(xid);
+                SubordinationManager.getTransactionImporter()
+                        .removeImportedTransaction(xid);
+            }
+            else
+                throw new XAException(XAException.XA_RETRY);
+        }
+        catch (RollbackException e)
+        {
+            SubordinationManager.getTransactionImporter()
+                    .removeImportedTransaction(xid);
             XAException xaException = new XAException(XAException.XA_RBROLLBACK);
             xaException.initCause(e);
             throw xaException;
         }
-		catch (XAException ex)
-		{
-			// resource hasn't had a chance to recover yet
+        catch (XAException ex)
+        {
+            // resource hasn't had a chance to recover yet
 
-			if (ex.errorCode != XAException.XA_RETRY)
-			{
-				SubordinationManager.getTransactionImporter().removeImportedTransaction(xid);
-			}
+            if (ex.errorCode != XAException.XA_RETRY)
+            {
+                SubordinationManager.getTransactionImporter()
+                        .removeImportedTransaction(xid);
+            }
 
-			throw ex;
-		}
-		catch (HeuristicRollbackException ex)
-		{
+            throw ex;
+        }
+        catch (HeuristicRollbackException ex)
+        {
             XAException xaException = new XAException(XAException.XA_HEURRB);
             xaException.initCause(ex);
-			throw xaException;
-		}
-		catch (HeuristicMixedException ex)
-		{
+            throw xaException;
+        }
+        catch (HeuristicMixedException ex)
+        {
             XAException xaException = new XAException(XAException.XA_HEURMIX);
             xaException.initCause(ex);
-			throw xaException;
-		}
-		catch (final HeuristicCommitException ex)
-		{
+            throw xaException;
+        }
+        catch (final HeuristicCommitException ex)
+        {
             XAException xaException = new XAException(XAException.XA_HEURCOM);
             xaException.initCause(ex);
-			throw xaException;
-		}
-		catch (final IllegalStateException ex)
+            throw xaException;
+        }
+        catch (final IllegalStateException ex)
         {
-            SubordinationManager.getTransactionImporter().removeImportedTransaction(xid);
+            SubordinationManager.getTransactionImporter()
+                    .removeImportedTransaction(xid);
 
             XAException xaException = new XAException(XAException.XAER_NOTA);
             xaException.initCause(ex);
             throw xaException;
         }
-		catch (SystemException ex)
-		{
-			SubordinationManager.getTransactionImporter().removeImportedTransaction(xid);
+        catch (SystemException ex)
+        {
+            SubordinationManager.getTransactionImporter()
+                    .removeImportedTransaction(xid);
 
             XAException xaException = new XAException(XAException.XAER_RMERR);
             xaException.initCause(ex);
             throw xaException;
-		}
-	}
+        }
+    }
 
-	/**
-	 * If the transaction subordinate generated a heuristic, then this operation
-	 * will be called later once that heuristic has been resolved.
-	 *
-	 * @param xid
-	 *            the transaction.
-	 *
-	 * @throws XAException
-	 *             if any error happens.
-	 */
+    /**
+     * If the transaction subordinate generated a heuristic, then this operation
+     * will be called later once that heuristic has been resolved.
+     * 
+     * @param xid
+     *            the transaction.
+     * @throws XAException
+     *             if any error happens.
+     */
 
-	public void forget(Xid xid) throws XAException
-	{
-		try
-		{
-			SubordinateTransaction tx = SubordinationManager.getTransactionImporter().getImportedTransaction(xid);
+    public void forget (Xid xid) throws XAException
+    {
+        try
+        {
+            SubordinateTransaction tx = SubordinationManager
+                    .getTransactionImporter().getImportedTransaction(xid);
 
-			if (tx == null)
-				throw new XAException(XAException.XAER_INVAL);
+            if (tx == null)
+                throw new XAException(XAException.XAER_INVAL);
 
-			tx.doForget();
-		}
-		catch (Exception ex)
-		{
+            tx.doForget();
+        }
+        catch (Exception ex)
+        {
             XAException xaException = new XAException(XAException.XAER_RMERR);
             xaException.initCause(ex);
             throw xaException;
-		}
-		finally
-		{
-			SubordinationManager.getTransactionImporter().removeImportedTransaction(xid);
-		}
-	}
+        }
+        finally
+        {
+            SubordinationManager.getTransactionImporter()
+                    .removeImportedTransaction(xid);
+        }
+    }
 
-	/**
-	 * Prepare the imported transaction.
-	 *
-	 * @param xid
-	 *            the transaction to prepare.
-	 *
-	 * @throws XAException
-	 *             thrown if any error occurs, including if the transaction has
-	 *             rolled back.
-	 *
-	 * @return either XAResource.XA_OK if the transaction prepared, or
-	 *         XAResource.XA_RDONLY if it was a read-only transaction (and in
-	 *         which case, a second phase message is not expected/required.)
-	 */
+    /**
+     * Prepare the imported transaction.
+     * 
+     * @param xid
+     *            the transaction to prepare.
+     * @throws XAException
+     *             thrown if any error occurs, including if the transaction has
+     *             rolled back.
+     * @return either XAResource.XA_OK if the transaction prepared, or
+     *         XAResource.XA_RDONLY if it was a read-only transaction (and in
+     *         which case, a second phase message is not expected/required.)
+     */
 
-	public int prepare(Xid xid) throws XAException
-	{
-		try
-		{
-			SubordinateTransaction tx = SubordinationManager.getTransactionImporter().getImportedTransaction(xid);
+    public int prepare (Xid xid) throws XAException
+    {
+        try
+        {
+            SubordinateTransaction tx = SubordinationManager
+                    .getTransactionImporter().getImportedTransaction(xid);
 
-			if (tx == null)
-				throw new XAException(XAException.XAER_INVAL);
+            if (tx == null)
+                throw new XAException(XAException.XAER_INVAL);
 
-			switch (tx.doPrepare())
-			{
-			case TwoPhaseOutcome.PREPARE_READONLY:
-				SubordinationManager.getTransactionImporter().removeImportedTransaction(xid);
-				return XAResource.XA_RDONLY;
-			case TwoPhaseOutcome.PREPARE_NOTOK:
-                // the JCA API spec limits what we can do in terms of reporting problems.
-                // try to use the exception code and cause to provide info whilst
-                // remaining API compliant.  JBTM-427.
+            switch (tx.doPrepare())
+            {
+            case TwoPhaseOutcome.PREPARE_READONLY:
+                SubordinationManager.getTransactionImporter()
+                        .removeImportedTransaction(xid);
+                return XAResource.XA_RDONLY;
+            case TwoPhaseOutcome.PREPARE_NOTOK:
+                // the JCA API spec limits what we can do in terms of reporting
+                // problems.
+                // try to use the exception code and cause to provide info
+                // whilst
+                // remaining API compliant. JBTM-427.
                 Exception initCause = null;
                 int xaExceptionCode = XAException.XA_RBROLLBACK;
-                try {
+                try
+                {
                     tx.doRollback();
-                } catch(HeuristicCommitException e) {
+                }
+                catch (HeuristicCommitException e)
+                {
                     initCause = e;
                     xaExceptionCode = XAException.XAER_RMERR;
-                } catch (HeuristicMixedException e) {
+                }
+                catch (HeuristicMixedException e)
+                {
                     initCause = e;
                     xaExceptionCode = XAException.XAER_RMERR;
-                } catch (SystemException e) {
+                }
+                catch (SystemException e)
+                {
                     initCause = e;
                     xaExceptionCode = XAException.XAER_RMERR;
                 }
-                catch (final HeuristicRollbackException e) {
+                catch (final HeuristicRollbackException e)
+                {
                     initCause = e;
                     xaExceptionCode = XAException.XAER_RMERR;
                 }
 
-                SubordinationManager.getTransactionImporter().removeImportedTransaction(xid);
+                SubordinationManager.getTransactionImporter()
+                        .removeImportedTransaction(xid);
                 XAException xaException = new XAException(xaExceptionCode);
-                if(initCause != null) {
+                if (initCause != null)
+                {
                     xaException.initCause(initCause);
                 }
-				throw xaException;
-			case TwoPhaseOutcome.PREPARE_OK:
-				return XAResource.XA_OK;
-			case TwoPhaseOutcome.INVALID_TRANSACTION:
-			    throw new XAException(XAException.XAER_NOTA);
-			default:
-				throw new XAException(XAException.XA_RBOTHER);
-			}
-		}
-		catch (XAException ex)
-		{
-			throw ex;
-		}
-	}
+                throw xaException;
+            case TwoPhaseOutcome.PREPARE_OK:
+                return XAResource.XA_OK;
+            case TwoPhaseOutcome.INVALID_TRANSACTION:
+                throw new XAException(XAException.XAER_NOTA);
+            default:
+                throw new XAException(XAException.XA_RBOTHER);
+            }
+        }
+        catch (XAException ex)
+        {
+            throw ex;
+        }
+    }
 
-	/**
-	 * Return a list of indoubt transactions. This may include those
-	 * transactions that are currently in-flight and running 2PC and do not need
-	 * recovery invoked on them.
-	 *
-	 * @param flag
-	 *            either XAResource.TMSTARTRSCAN to indicate the start of a
-	 *            recovery scan, or XAResource.TMENDRSCAN to indicate the end of
-	 *            the recovery scan.
-	 *
-	 * @throws XAException
-	 *             thrown if any error occurs.
-	 *
-	 * @return a list of potentially indoubt transactions or <code>null</code>.
-	 */
+    /**
+     * Return a list of indoubt transactions. This may include those
+     * transactions that are currently in-flight and running 2PC and do not need
+     * recovery invoked on them.
+     * 
+     * @param flag
+     *            either XAResource.TMSTARTRSCAN to indicate the start of a
+     *            recovery scan, or XAResource.TMENDRSCAN to indicate the end of
+     *            the recovery scan.
+     * @throws XAException
+     *             thrown if any error occurs.
+     * @return a list of potentially indoubt transactions or <code>null</code>.
+     */
 
-	public Xid[] recover(int flag) throws XAException
-	{
-		/*
-		 * Requires going through the objectstore for the states of imported
-		 * transactions. Our own crash recovery takes care of transactions
-		 * imported via CORBA, Web Services etc.
-		 */
+    public Xid[] recover (int flag) throws XAException
+    {
+        /*
+         * Requires going through the objectstore for the states of imported
+         * transactions. Our own crash recovery takes care of transactions
+         * imported via CORBA, Web Services etc.
+         */
 
-		switch (flag)
-		{
-		case XAResource.TMSTARTRSCAN: // check the object store
-			if (_recoveryStarted)
-				throw new XAException(XAException.XAER_PROTO);
-			else
-				_recoveryStarted = true;
-			break;
-		case XAResource.TMENDRSCAN: // null op for us
-			if (_recoveryStarted)
-				_recoveryStarted = false;
-			else
-				throw new XAException(XAException.XAER_PROTO);
-			return null;
-		case XAResource.TMNOFLAGS:
-			if (_recoveryStarted)
-				break;
-		default:
-			throw new XAException(XAException.XAER_PROTO);
-		}
+        switch (flag)
+        {
+        case XAResource.TMSTARTRSCAN: // check the object store
+            if (_recoveryStarted)
+                throw new XAException(XAException.XAER_PROTO);
+            else
+                _recoveryStarted = true;
+            break;
+        case XAResource.TMENDRSCAN: // null op for us
+            if (_recoveryStarted)
+                _recoveryStarted = false;
+            else
+                throw new XAException(XAException.XAER_PROTO);
+            return null;
+        case XAResource.TMNOFLAGS:
+            if (_recoveryStarted)
+                break;
+        default:
+            throw new XAException(XAException.XAER_PROTO);
+        }
 
-		// if we are here, then check the object store
+        // if we are here, then check the object store
 
-		Xid[] indoubt = null;
+        Xid[] indoubt = null;
 
-		try
-		{
-			ObjectStore objStore = new ObjectStore(TxControl
-					.getActionStoreType());
-			InputObjectState states = new InputObjectState();
+        try
+        {
+            ObjectStore objStore = new ObjectStore(TxControl
+                    .getActionStoreType());
+            InputObjectState states = new InputObjectState();
 
-			// only look in the JCA section of the object store
+            // only look in the JCA section of the object store
 
-			if (objStore.allObjUids(SubordinateAtomicAction.getType(), states)
-					&& (states.notempty()))
-			{
-				Stack values = new Stack();
-				boolean finished = false;
+            if (objStore.allObjUids(SubordinateAtomicAction.getType(), states)
+                    && (states.notempty()))
+            {
+                Stack values = new Stack();
+                boolean finished = false;
 
-				do
-				{
-					Uid uid = new Uid(Uid.nullUid());
+                do
+                {
+                    Uid uid = new Uid(Uid.nullUid());
 
-					try
-					{
-						uid.unpack(states);
-					}
-					catch (IOException ex)
-					{
-						ex.printStackTrace();
+                    try
+                    {
+                        uid.unpack(states);
+                    }
+                    catch (IOException ex)
+                    {
+                        ex.printStackTrace();
 
-						finished = true;
-					}
+                        finished = true;
+                    }
 
-					if (uid.notEquals(Uid.nullUid()))
-					{
-						Transaction tx = SubordinationManager.getTransactionImporter()
-								.recoverTransaction(uid);
+                    if (uid.notEquals(Uid.nullUid()))
+                    {
+                        Transaction tx = SubordinationManager
+                                .getTransactionImporter().recoverTransaction(
+                                        uid);
 
-						if (tx != null)
-							values.push(tx);
-					}
-					else
-						finished = true;
+                        if (tx != null)
+                            values.push(tx);
+                    }
+                    else
+                        finished = true;
 
-				} while (!finished);
+                }
+                while (!finished);
 
-				if (values.size() > 0)
-				{
-					int index = 0;
+                if (values.size() > 0)
+                {
+                    int index = 0;
 
-					indoubt = new Xid[values.size()];
+                    indoubt = new Xid[values.size()];
 
-					while (!values.empty())
-					{
-						com.arjuna.ats.internal.jta.transaction.arjunacore.subordinate.jca.TransactionImple tx = (com.arjuna.ats.internal.jta.transaction.arjunacore.subordinate.jca.TransactionImple) values
-								.pop();
+                    while (!values.empty())
+                    {
+                        com.arjuna.ats.internal.jta.transaction.arjunacore.subordinate.jca.TransactionImple tx = (com.arjuna.ats.internal.jta.transaction.arjunacore.subordinate.jca.TransactionImple) values
+                                .pop();
 
-						indoubt[index] = tx.baseXid();
-						index++;
-					}
-				}
-			}
-		}
-		catch (Exception ex)
-		{
-			ex.printStackTrace();
-		}
+                        indoubt[index] = tx.baseXid();
+                        index++;
+                    }
+                }
+            }
+        }
+        catch (Exception ex)
+        {
+            ex.printStackTrace();
+        }
 
-		return indoubt;
-	}
+        return indoubt;
+    }
 
-	/**
-	 * Rollback the imported transaction subordinate.
-	 *
-	 * @param xid
-	 *            the transaction to roll back.
-	 *
-	 * @throws XAException
-	 *             thrown if there are any errors.
-	 */
+    /**
+     * Rollback the imported transaction subordinate.
+     * 
+     * @param xid
+     *            the transaction to roll back.
+     * @throws XAException
+     *             thrown if there are any errors.
+     */
 
-	public void rollback(Xid xid) throws XAException
-	{
-		try
-		{
-			SubordinateTransaction tx = SubordinationManager.getTransactionImporter().getImportedTransaction(xid);
+    public void rollback (Xid xid) throws XAException
+    {
+        try
+        {
+            SubordinateTransaction tx = SubordinationManager
+                    .getTransactionImporter().getImportedTransaction(xid);
 
-			if (tx == null)
-				throw new XAException(XAException.XAER_INVAL);
+            if (tx == null)
+                throw new XAException(XAException.XAER_INVAL);
 
-			if (tx.activated())
-			{
-				tx.doRollback();
+            if (tx.activated())
+            {
+                tx.doRollback();
 
-				SubordinationManager.getTransactionImporter().removeImportedTransaction(xid);
-			}
-			else
-				throw new XAException(XAException.XA_RETRY);
-		}
-		catch (XAException ex)
-		{
-			// resource hasn't had a chance to recover yet
+                SubordinationManager.getTransactionImporter()
+                        .removeImportedTransaction(xid);
+            }
+            else
+                throw new XAException(XAException.XA_RETRY);
+        }
+        catch (XAException ex)
+        {
+            // resource hasn't had a chance to recover yet
 
-			if (ex.errorCode != XAException.XA_RETRY)
-			{
-				SubordinationManager.getTransactionImporter().removeImportedTransaction(xid);
-			}
+            if (ex.errorCode != XAException.XA_RETRY)
+            {
+                SubordinationManager.getTransactionImporter()
+                        .removeImportedTransaction(xid);
+            }
 
-			throw ex;
-		}
-		catch (final HeuristicRollbackException ex)
-		{
+            throw ex;
+        }
+        catch (final HeuristicRollbackException ex)
+        {
             XAException xaException = new XAException(XAException.XA_HEURRB);
             xaException.initCause(ex);
             throw xaException;
-		}
-		catch (HeuristicCommitException ex)
-		{
+        }
+        catch (HeuristicCommitException ex)
+        {
             XAException xaException = new XAException(XAException.XA_HEURCOM);
             xaException.initCause(ex);
             throw xaException;
-		}
-		catch (HeuristicMixedException ex)
-		{
+        }
+        catch (HeuristicMixedException ex)
+        {
             XAException xaException = new XAException(XAException.XA_HEURMIX);
             xaException.initCause(ex);
             throw xaException;
-		}
-		catch (final IllegalStateException ex)
-		{
-            SubordinationManager.getTransactionImporter().removeImportedTransaction(xid);
+        }
+        catch (final IllegalStateException ex)
+        {
+            SubordinationManager.getTransactionImporter()
+                    .removeImportedTransaction(xid);
 
             XAException xaException = new XAException(XAException.XAER_NOTA);
             xaException.initCause(ex);
             throw xaException;
         }
-		catch (SystemException ex)
-		{
-			SubordinationManager.getTransactionImporter().removeImportedTransaction(xid);
+        catch (SystemException ex)
+        {
+            SubordinationManager.getTransactionImporter()
+                    .removeImportedTransaction(xid);
 
-			throw new XAException(XAException.XAER_RMERR);
-		}
-	}
+            throw new XAException(XAException.XAER_RMERR);
+        }
+    }
+    
+    public boolean beforeCompletion (Xid xid) throws javax.transaction.SystemException
+    {
+        try
+        {
+            SubordinateTransaction tx = SubordinationManager
+                    .getTransactionImporter().getImportedTransaction(xid);
 
-	private boolean _recoveryStarted = false;
+            if (tx == null)
+                throw new UnexpectedConditionException();
 
+           return tx.doBeforeCompletion();
+        }
+        catch (final Exception ex)
+        {
+            UnexpectedConditionException e = new UnexpectedConditionException();
+            
+            e.initCause(ex);
+            
+            throw e;
+        }
+    }
+    
+    /*
+     * Remember that status is JTS status.
+     * @see com.arjuna.ats.internal.jta.resources.spi.XATerminatorExtensions#afterCompletion(javax.transaction.xa.Xid, int)
+     */
+    
+    public boolean afterCompletion (Xid xid, int status) throws javax.transaction.SystemException
+    {
+        try
+        {
+            SubordinateTransaction tx = SubordinationManager
+                    .getTransactionImporter().getImportedTransaction(xid);
+
+            if (tx == null)
+                throw new UnexpectedConditionException();
+
+           return tx.doAfterCompletion(status);
+        }
+        catch (final Exception ex)
+        {
+            UnexpectedConditionException e = new UnexpectedConditionException();
+            
+            e.initCause(ex);
+            
+            throw e;
+        }
+    }
+
+    private boolean _recoveryStarted = false;
+
 }

Modified: labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/transaction/arjunacore/subordinate/SubordinateAtomicAction.java
===================================================================
--- labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/transaction/arjunacore/subordinate/SubordinateAtomicAction.java	2009-05-31 11:32:25 UTC (rev 26792)
+++ labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/transaction/arjunacore/subordinate/SubordinateAtomicAction.java	2009-05-31 17:12:42 UTC (rev 26793)
@@ -129,7 +129,7 @@
         // note it's not perfect- async timeout/rollback means there is a race condition in which we
         // can still call beforeCompletion on rollbacks, but that's not too bad as skipping it is really
         // just an optimization anyhow.  JBTM-429
-        if ( !(status == ActionStatus.ABORT_ONLY || status == ActionStatus.ABORTING) && super.beforeCompletion())
+        if ( !(status == ActionStatus.ABORT_ONLY || status == ActionStatus.ABORTING) && doBeforeCompletion())
         {
             int outcome = super.prepare(true);
             if(outcome == TwoPhaseOutcome.PREPARE_READONLY) {
@@ -213,33 +213,70 @@
 	}
 
 	public int doOnePhaseCommit ()
-    {
-        int status = super.status();
+	{
+	    int status = super.status();
+	    
+	    // In JTA spec, beforeCompletions are run on commit attempts only, not rollbacks.
+	    // We attempt to mimic that here, even though we are outside the scope of the spec.
+	    // note it's not perfect- async timeout/rollback means there is a race condition in which we
+	    // can still call beforeCompletion on rollbacks, but that's not too bad as skipping it is really
+	    // just an optimization anyhow. JBTM-429
 
-        // In JTA spec, beforeCompletions are run on commit attempts only, not rollbacks.
-        // We attempt to mimic that here, even though we are outside the scope of the spec.
-        // note it's not perfect- async timeout/rollback means there is a race condition in which we
-        // can still call beforeCompletion on rollbacks, but that's not too bad as skipping it is really
-        // just an optimization anyhow. JBTM-429
-        // behaviour relies on java's lazy evaluation of the if clause:
-        if (status == ActionStatus.ABORT_ONLY || super.beforeCompletion())
-        {
-            status = super.End(true);
-        }
-        else
-        {
-            status = ActionStatus.ABORTED;
-        }
+	    if (status == ActionStatus.ABORT_ONLY || doBeforeCompletion())
+	    {
+	        status = super.End(true);
+	    }
+	    else
+	    {
+	        status = ActionStatus.ABORTED;
+	    }
 
-        afterCompletion(status);
-        return status;
-    }
+	    afterCompletion(status);
+	    
+	    return status;
+	}
 
 	public void doForget ()
 	{
 		super.forgetHeuristics();
 	}
 
+	public boolean doBeforeCompletion ()
+	{
+	    // should not need synchronizing at this level
+	    
+	    if (!_doneBefore)
+	    {
+	        _beforeOutcome = super.beforeCompletion();
+	        
+	        _doneBefore = true;
+	    }
+	    
+	    return _beforeOutcome;
+	}
+	
+	public boolean doAfterCompletion (int status)
+	{
+	    if (!_doneAfter)
+	    {
+	        /*
+	         * We don't need to convert from JTA status to AC status because
+	         * the interpretation of the status is left up to the
+	         * Synchronization instance and not the transaction.
+	         * 
+	         * TODO this is a potential problem in the case where we
+	         * allow mixtures of Synchronization types in the same transaction
+	         * and they expect status values that conflict.
+	         */
+	        
+	        _afterOutcome = super.afterCompletion(status);
+	        
+	        _doneAfter = true;
+	    }
+	    
+	    return _afterOutcome;
+	}
+	
 	/**
 	 * For crash recovery purposes.
 	 *
@@ -269,4 +306,17 @@
     {
     	return true;
     }
+    
+    /*
+     * We have these here because it's possible that synchronizations aren't
+     * called explicitly either side of commit/rollback due to JCA API not supporting
+     * them directly. We do though and in which case it's possible that they
+     * can be driven through two routes and we don't want to get into a mess
+     * due to that.
+     */
+    
+    private boolean _doneBefore = false;
+    private boolean _beforeOutcome = false;
+    private boolean _doneAfter = false;
+    private boolean _afterOutcome = false;
 }

Modified: labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/transaction/arjunacore/subordinate/TransactionImple.java
===================================================================
--- labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/transaction/arjunacore/subordinate/TransactionImple.java	2009-05-31 11:32:25 UTC (rev 26792)
+++ labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/transaction/arjunacore/subordinate/TransactionImple.java	2009-05-31 17:12:42 UTC (rev 26793)
@@ -309,7 +309,45 @@
 			throw unexpectedConditionException;
 		}
 	}
+	
+	public boolean doBeforeCompletion () throws javax.transaction.SystemException
+	{
+	    try
+	    {
+	        SubordinateAtomicAction subAct = (SubordinateAtomicAction) super._theTransaction;
+	        
+	        return subAct.doBeforeCompletion();
+	    }
+	    catch (final Exception ex)
+	    {
+	        ex.printStackTrace();
 
+	        UnexpectedConditionException unexpectedConditionException = new UnexpectedConditionException(ex.toString());
+	        unexpectedConditionException.initCause(ex);
+	        
+	        throw unexpectedConditionException;
+	    }
+	}
+	
+	public boolean doAfterCompletion (int status) throws javax.transaction.SystemException
+	{
+	    try
+            {
+                SubordinateAtomicAction subAct = (SubordinateAtomicAction) super._theTransaction;
+                
+                return subAct.doAfterCompletion(status);
+            }
+            catch (final Exception ex)
+            {
+                ex.printStackTrace();
+
+                UnexpectedConditionException unexpectedConditionException = new UnexpectedConditionException(ex.toString());
+                unexpectedConditionException.initCause(ex);
+                
+                throw unexpectedConditionException;
+            }
+	}
+
 	public String toString ()
 	{
 		if (super._theTransaction == null)
@@ -350,4 +388,5 @@
     {
     	return true;
     }
+
 }

Modified: labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/jta/exceptions/UnexpectedConditionException.java
===================================================================
--- labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/jta/exceptions/UnexpectedConditionException.java	2009-05-31 11:32:25 UTC (rev 26792)
+++ labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/jta/exceptions/UnexpectedConditionException.java	2009-05-31 17:12:42 UTC (rev 26793)
@@ -54,6 +54,5 @@
     {
 	super(s);
     }
-
 }
 

Modified: labs/jbosstm/trunk/ArjunaJTS/jtax/classes/com/arjuna/ats/internal/jta/transaction/jts/jca/XATerminatorImple.java
===================================================================
--- labs/jbosstm/trunk/ArjunaJTS/jtax/classes/com/arjuna/ats/internal/jta/transaction/jts/jca/XATerminatorImple.java	2009-05-31 11:32:25 UTC (rev 26792)
+++ labs/jbosstm/trunk/ArjunaJTS/jtax/classes/com/arjuna/ats/internal/jta/transaction/jts/jca/XATerminatorImple.java	2009-05-31 17:12:42 UTC (rev 26793)
@@ -42,328 +42,399 @@
 import com.arjuna.ats.arjuna.coordinator.TxControl;
 import com.arjuna.ats.arjuna.objectstore.ObjectStore;
 import com.arjuna.ats.arjuna.state.InputObjectState;
+import com.arjuna.ats.internal.jta.resources.spi.XATerminatorExtensions;
 import com.arjuna.ats.internal.jta.transaction.jts.subordinate.jca.TransactionImple;
 import com.arjuna.ats.internal.jta.transaction.jts.subordinate.jca.coordinator.ServerTransaction;
 import com.arjuna.ats.internal.jta.transaction.arjunacore.jca.SubordinationManager;
 import com.arjuna.ats.internal.jta.transaction.arjunacore.jca.SubordinateTransaction;
+import com.arjuna.ats.jta.exceptions.UnexpectedConditionException;
 
 /**
  * The XATerminator implementation.
- *
+ * 
  * @author mcl
- *
  */
 
-public class XATerminatorImple implements javax.resource.spi.XATerminator
+public class XATerminatorImple implements javax.resource.spi.XATerminator, XATerminatorExtensions
 {
 
-	public void commit (Xid xid, boolean onePhase) throws XAException
-	{
-		try
-		{
-			SubordinateTransaction tx = SubordinationManager.getTransactionImporter().getImportedTransaction(xid);
+    public void commit (Xid xid, boolean onePhase) throws XAException
+    {
+        try
+        {
+            SubordinateTransaction tx = SubordinationManager
+                    .getTransactionImporter().getImportedTransaction(xid);
 
-			if (tx == null)
-				throw new XAException(XAException.XAER_INVAL);
+            if (tx == null)
+                throw new XAException(XAException.XAER_INVAL);
 
-			if (tx.baseXid() != null)  // activate failed?
-			{
-				if (onePhase)
-					tx.doOnePhaseCommit();
-				else
-					tx.doCommit();
+            if (tx.baseXid() != null) // activate failed?
+            {
+                if (onePhase)
+                    tx.doOnePhaseCommit();
+                else
+                    tx.doCommit();
 
-				SubordinationManager.getTransactionImporter().removeImportedTransaction(xid);
-			}
-			else
-				throw new XAException(XAException.XA_RETRY);
-		}
-        catch(RollbackException e)
+                SubordinationManager.getTransactionImporter()
+                        .removeImportedTransaction(xid);
+            }
+            else
+                throw new XAException(XAException.XA_RETRY);
+        }
+        catch (RollbackException e)
         {
-            SubordinationManager.getTransactionImporter().removeImportedTransaction(xid);
+            SubordinationManager.getTransactionImporter()
+                    .removeImportedTransaction(xid);
             XAException xaException = new XAException(XAException.XA_RBROLLBACK);
             xaException.initCause(e);
             throw xaException;
         }
-		catch (XAException ex)
-		{
-			// resource hasn't had a chance to recover yet
+        catch (XAException ex)
+        {
+            // resource hasn't had a chance to recover yet
 
-			if (ex.errorCode != XAException.XA_RETRY)
-			{
-				SubordinationManager.getTransactionImporter().removeImportedTransaction(xid);
-			}
+            if (ex.errorCode != XAException.XA_RETRY)
+            {
+                SubordinationManager.getTransactionImporter()
+                        .removeImportedTransaction(xid);
+            }
 
-			throw ex;
-		}
-		catch (final HeuristicCommitException ex)
-		{
+            throw ex;
+        }
+        catch (final HeuristicCommitException ex)
+        {
             XAException xaException = new XAException(XAException.XA_HEURCOM);
             xaException.initCause(ex);
             throw xaException;
-		}
-		catch (HeuristicRollbackException ex)
-		{
+        }
+        catch (HeuristicRollbackException ex)
+        {
             XAException xaException = new XAException(XAException.XA_HEURRB);
             xaException.initCause(ex);
             throw xaException;
-		}
-		catch (HeuristicMixedException ex)
-		{
+        }
+        catch (HeuristicMixedException ex)
+        {
             XAException xaException = new XAException(XAException.XA_HEURMIX);
             xaException.initCause(ex);
             throw xaException;
-		}
-		catch (final IllegalStateException ex)
-		{
-	        SubordinationManager.getTransactionImporter().removeImportedTransaction(xid);
+        }
+        catch (final IllegalStateException ex)
+        {
+            SubordinationManager.getTransactionImporter()
+                    .removeImportedTransaction(xid);
 
             XAException xaException = new XAException(XAException.XAER_NOTA);
             xaException.initCause(ex);
             throw xaException;
-		}
-		catch (SystemException ex)
-		{
-			SubordinationManager.getTransactionImporter().removeImportedTransaction(xid);
+        }
+        catch (SystemException ex)
+        {
+            SubordinationManager.getTransactionImporter()
+                    .removeImportedTransaction(xid);
 
             XAException xaException = new XAException(XAException.XAER_RMERR);
             xaException.initCause(ex);
             throw xaException;
-		}
-	}
+        }
+    }
 
-	public void forget (Xid xid) throws XAException
-	{
-		try
-		{
-			SubordinateTransaction tx = SubordinationManager.getTransactionImporter().getImportedTransaction(xid);
+    public void forget (Xid xid) throws XAException
+    {
+        try
+        {
+            SubordinateTransaction tx = SubordinationManager
+                    .getTransactionImporter().getImportedTransaction(xid);
 
-			if (tx == null)
-				throw new XAException(XAException.XAER_INVAL);
+            if (tx == null)
+                throw new XAException(XAException.XAER_INVAL);
 
-			tx.doForget();
-		}
-		catch (Exception ex)
-		{
+            tx.doForget();
+        }
+        catch (Exception ex)
+        {
             XAException xaException = new XAException(XAException.XAER_RMERR);
             xaException.initCause(ex);
             throw xaException;
-		}
-		finally
-		{
-			SubordinationManager.getTransactionImporter().removeImportedTransaction(xid);
-		}
-	}
+        }
+        finally
+        {
+            SubordinationManager.getTransactionImporter()
+                    .removeImportedTransaction(xid);
+        }
+    }
 
-	public int prepare (Xid xid) throws XAException
-	{
-		try
-		{
-			SubordinateTransaction tx = SubordinationManager.getTransactionImporter().getImportedTransaction(xid);
+    public int prepare (Xid xid) throws XAException
+    {
+        try
+        {
+            SubordinateTransaction tx = SubordinationManager
+                    .getTransactionImporter().getImportedTransaction(xid);
 
-			if (tx == null)
-				throw new XAException(XAException.XAER_INVAL);
+            if (tx == null)
+                throw new XAException(XAException.XAER_INVAL);
 
-			switch (tx.doPrepare())
-			{
-			case TwoPhaseOutcome.PREPARE_READONLY:
-				SubordinationManager.getTransactionImporter().removeImportedTransaction(xid);
+            switch (tx.doPrepare())
+            {
+            case TwoPhaseOutcome.PREPARE_READONLY:
+                SubordinationManager.getTransactionImporter()
+                        .removeImportedTransaction(xid);
 
-				return XAResource.XA_RDONLY;
-			case TwoPhaseOutcome.PREPARE_NOTOK:
-			    try
-			    {
-			        rollback(xid);
-			    }
-			    catch (final Throwable ex)
-			    {
-			        // if we failed to prepare then rollback should not fail!
-			    }
+                return XAResource.XA_RDONLY;
+            case TwoPhaseOutcome.PREPARE_NOTOK:
+                try
+                {
+                    rollback(xid);
+                }
+                catch (final Throwable ex)
+                {
+                    // if we failed to prepare then rollback should not fail!
+                }
 
-				SubordinationManager.getTransactionImporter().removeImportedTransaction(xid);
+                SubordinationManager.getTransactionImporter()
+                        .removeImportedTransaction(xid);
 
-				throw new XAException(XAException.XA_RBROLLBACK);
-			case TwoPhaseOutcome.PREPARE_OK:
-				return XAResource.XA_OK;
-			case TwoPhaseOutcome.INVALID_TRANSACTION:
-			    throw new XAException(XAException.XAER_NOTA);
-			default:
-				throw new XAException(XAException.XA_RBOTHER);
-			}
-		}
-		catch (XAException ex)
-		{
-			throw ex;
-		}
-	}
+                throw new XAException(XAException.XA_RBROLLBACK);
+            case TwoPhaseOutcome.PREPARE_OK:
+                return XAResource.XA_OK;
+            case TwoPhaseOutcome.INVALID_TRANSACTION:
+                throw new XAException(XAException.XAER_NOTA);
+            default:
+                throw new XAException(XAException.XA_RBOTHER);
+            }
+        }
+        catch (XAException ex)
+        {
+            throw ex;
+        }
+    }
 
-	public Xid[] recover (int flag) throws XAException
-	{
-		/*
-		 * Requires going through the objectstore for the states of imported
-		 * transactions. Our own crash recovery takes care of transactions imported
-		 * via CORBA, Web Services etc.
-		 */
+    public Xid[] recover (int flag) throws XAException
+    {
+        /*
+         * Requires going through the objectstore for the states of imported
+         * transactions. Our own crash recovery takes care of transactions
+         * imported via CORBA, Web Services etc.
+         */
 
-		/*
-		 * Requires going through the objectstore for the states of imported
-		 * transactions. Our own crash recovery takes care of transactions imported
-		 * via CORBA, Web Services etc.
-		 */
+        /*
+         * Requires going through the objectstore for the states of imported
+         * transactions. Our own crash recovery takes care of transactions
+         * imported via CORBA, Web Services etc.
+         */
 
-		switch (flag)
-		{
-		case XAResource.TMSTARTRSCAN: // check the object store
-			if (_recoveryStarted)
-				throw new XAException(XAException.XAER_PROTO);
-			else
-				_recoveryStarted = true;
-			break;
-		case XAResource.TMENDRSCAN: // null op for us
-			if (_recoveryStarted)
-				_recoveryStarted = false;
-			else
-				throw new XAException(XAException.XAER_PROTO);
-			return null;
-		case XAResource.TMNOFLAGS:
-			if (_recoveryStarted)
-				break;
-		default:
-			throw new XAException(XAException.XAER_PROTO);
-		}
+        switch (flag)
+        {
+        case XAResource.TMSTARTRSCAN: // check the object store
+            if (_recoveryStarted)
+                throw new XAException(XAException.XAER_PROTO);
+            else
+                _recoveryStarted = true;
+            break;
+        case XAResource.TMENDRSCAN: // null op for us
+            if (_recoveryStarted)
+                _recoveryStarted = false;
+            else
+                throw new XAException(XAException.XAER_PROTO);
+            return null;
+        case XAResource.TMNOFLAGS:
+            if (_recoveryStarted)
+                break;
+        default:
+            throw new XAException(XAException.XAER_PROTO);
+        }
 
-		// if we are here, then check the object store
+        // if we are here, then check the object store
 
-		Xid[] indoubt = null;
+        Xid[] indoubt = null;
 
-		try
-		{
-			ObjectStore objStore = new ObjectStore(TxControl.getActionStoreType());
-			InputObjectState states = new InputObjectState();
+        try
+        {
+            ObjectStore objStore = new ObjectStore(TxControl
+                    .getActionStoreType());
+            InputObjectState states = new InputObjectState();
 
-			// only look in the JCA section of the object store
+            // only look in the JCA section of the object store
 
-			if (objStore.allObjUids(ServerTransaction.getType(), states) && (states.notempty()))
-			{
-				Stack values = new Stack();
-				boolean finished = false;
+            if (objStore.allObjUids(ServerTransaction.getType(), states)
+                    && (states.notempty()))
+            {
+                Stack values = new Stack();
+                boolean finished = false;
 
-				do
-				{
-					Uid uid = new Uid(Uid.nullUid());
+                do
+                {
+                    Uid uid = new Uid(Uid.nullUid());
 
-					try
-					{
-						uid.unpack(states);
-					}
-					catch (IOException ex)
-					{
-						ex.printStackTrace();
+                    try
+                    {
+                        uid.unpack(states);
+                    }
+                    catch (IOException ex)
+                    {
+                        ex.printStackTrace();
 
-						finished = true;
-					}
+                        finished = true;
+                    }
 
-					if (uid.notEquals(Uid.nullUid()))
-					{
-						Transaction tx = SubordinationManager.getTransactionImporter().recoverTransaction(uid);
+                    if (uid.notEquals(Uid.nullUid()))
+                    {
+                        Transaction tx = SubordinationManager
+                                .getTransactionImporter().recoverTransaction(
+                                        uid);
 
-						values.push(tx);
-					}
-					else
-						finished = true;
+                        values.push(tx);
+                    }
+                    else
+                        finished = true;
 
-				} while (!finished);
+                }
+                while (!finished);
 
-				if (values.size() > 0)
-				{
-					int index = 0;
+                if (values.size() > 0)
+                {
+                    int index = 0;
 
-					indoubt = new Xid[values.size()];
+                    indoubt = new Xid[values.size()];
 
-					while (!values.empty())
-					{
-						TransactionImple id = (TransactionImple) values.pop();
+                    while (!values.empty())
+                    {
+                        TransactionImple id = (TransactionImple) values.pop();
 
-						indoubt[index] = id.baseXid();
+                        indoubt[index] = id.baseXid();
 
-						index++;
-					}
-				}
-			}
-		}
-		catch (Exception ex)
-		{
-			ex.printStackTrace();
-		}
+                        index++;
+                    }
+                }
+            }
+        }
+        catch (Exception ex)
+        {
+            ex.printStackTrace();
+        }
 
-		return indoubt;
-	}
+        return indoubt;
+    }
 
-	public void rollback (Xid xid) throws XAException
-	{
-		try
-		{
-			SubordinateTransaction tx = SubordinationManager.getTransactionImporter().getImportedTransaction(xid);
+    public void rollback (Xid xid) throws XAException
+    {
+        try
+        {
+            SubordinateTransaction tx = SubordinationManager
+                    .getTransactionImporter().getImportedTransaction(xid);
 
-			if (tx == null)
-				throw new XAException(XAException.XAER_INVAL);
+            if (tx == null)
+                throw new XAException(XAException.XAER_INVAL);
 
-			if (tx.baseXid() != null)
-			{
-				tx.doRollback();
+            if (tx.baseXid() != null)
+            {
+                tx.doRollback();
 
-				SubordinationManager.getTransactionImporter().removeImportedTransaction(xid);
-			}
-			else
-				throw new XAException(XAException.XA_RETRY);
-		}
-		catch (XAException ex)
-		{
-			// resource hasn't had a chance to recover yet
+                SubordinationManager.getTransactionImporter()
+                        .removeImportedTransaction(xid);
+            }
+            else
+                throw new XAException(XAException.XA_RETRY);
+        }
+        catch (XAException ex)
+        {
+            // resource hasn't had a chance to recover yet
 
-			if (ex.errorCode != XAException.XA_RETRY)
-			{
-				SubordinationManager.getTransactionImporter().removeImportedTransaction(xid);
-			}
+            if (ex.errorCode != XAException.XA_RETRY)
+            {
+                SubordinationManager.getTransactionImporter()
+                        .removeImportedTransaction(xid);
+            }
 
-			throw ex;
-		}
-		catch (HeuristicCommitException ex)
-		{
+            throw ex;
+        }
+        catch (HeuristicCommitException ex)
+        {
             XAException xaException = new XAException(XAException.XA_HEURCOM);
             xaException.initCause(ex);
             throw xaException;
-		}
-		catch (final HeuristicRollbackException ex)
-		{
-		    XAException xaException = new XAException(XAException.XA_HEURRB);
+        }
+        catch (final HeuristicRollbackException ex)
+        {
+            XAException xaException = new XAException(XAException.XA_HEURRB);
             xaException.initCause(ex);
             throw xaException;
-		}
-		catch (HeuristicMixedException ex)
-		{
-			XAException xaException = new XAException(XAException.XA_HEURMIX);
+        }
+        catch (HeuristicMixedException ex)
+        {
+            XAException xaException = new XAException(XAException.XA_HEURMIX);
             xaException.initCause(ex);
             throw xaException;
-		}
-		catch (final IllegalStateException ex)
-		{
-		    SubordinationManager.getTransactionImporter().removeImportedTransaction(xid);
+        }
+        catch (final IllegalStateException ex)
+        {
+            SubordinationManager.getTransactionImporter()
+                    .removeImportedTransaction(xid);
 
-		    XAException xaException = new XAException(XAException.XAER_NOTA);
+            XAException xaException = new XAException(XAException.XAER_NOTA);
             xaException.initCause(ex);
             throw xaException;
-		}
-		catch (SystemException ex)
-		{
-			SubordinationManager.getTransactionImporter().removeImportedTransaction(xid);
+        }
+        catch (SystemException ex)
+        {
+            SubordinationManager.getTransactionImporter()
+                    .removeImportedTransaction(xid);
 
-			XAException xaException = new XAException(XAException.XAER_RMERR);
+            XAException xaException = new XAException(XAException.XAER_RMERR);
             xaException.initCause(ex);
             throw xaException;
-		}
-	}
+        }
+    }
 
-	private boolean _recoveryStarted = false;
+    public boolean beforeCompletion (Xid xid) throws javax.transaction.SystemException
+    {
+        try
+        {
+            SubordinateTransaction tx = SubordinationManager
+                    .getTransactionImporter().getImportedTransaction(xid);
 
+            if (tx == null)
+                throw new UnexpectedConditionException();
+
+           return tx.doBeforeCompletion();
+        }
+        catch (final Exception ex)
+        {
+            UnexpectedConditionException e = new UnexpectedConditionException();
+            
+            e.initCause(ex);
+            
+            throw e;
+        }
+    }
+    
+    /*
+     * Remember that status is JTS status.
+     * @see com.arjuna.ats.internal.jta.resources.spi.XATerminatorExtensions#afterCompletion(javax.transaction.xa.Xid, int)
+     */
+    
+    public boolean afterCompletion (Xid xid, int status) throws javax.transaction.SystemException
+    {
+        try
+        {
+            SubordinateTransaction tx = SubordinationManager
+                    .getTransactionImporter().getImportedTransaction(xid);
+
+            if (tx == null)
+                throw new UnexpectedConditionException();
+
+           return tx.doAfterCompletion(status);
+        }
+        catch (final Exception ex)
+        {
+            UnexpectedConditionException e = new UnexpectedConditionException();
+            
+            e.initCause(ex);
+            
+            throw e;
+        }
+    }
+    
+    private boolean _recoveryStarted = false;
+
 }

Modified: labs/jbosstm/trunk/ArjunaJTS/jtax/classes/com/arjuna/ats/internal/jta/transaction/jts/subordinate/SubordinateAtomicTransaction.java
===================================================================
--- labs/jbosstm/trunk/ArjunaJTS/jtax/classes/com/arjuna/ats/internal/jta/transaction/jts/subordinate/SubordinateAtomicTransaction.java	2009-05-31 11:32:25 UTC (rev 26792)
+++ labs/jbosstm/trunk/ArjunaJTS/jtax/classes/com/arjuna/ats/internal/jta/transaction/jts/subordinate/SubordinateAtomicTransaction.java	2009-05-31 17:12:42 UTC (rev 26793)
@@ -28,6 +28,8 @@
 
 package com.arjuna.ats.internal.jta.transaction.jts.subordinate;
 
+import javax.transaction.Status;
+
 import org.omg.CORBA.SystemException;
 import org.omg.CosTransactions.HeuristicHazard;
 import org.omg.CosTransactions.HeuristicMixed;
@@ -99,9 +101,9 @@
 		// require registration of synchronization interposed resource as well!
 		
 		if (stx != null)
-			return stx.doPrepare();
-		else
-			return TwoPhaseOutcome.INVALID_TRANSACTION;
+                    return stx.doPrepare();
+            else
+                    return TwoPhaseOutcome.INVALID_TRANSACTION;
 	}
 	
 	/**
@@ -113,18 +115,18 @@
 	public int doCommit () throws SystemException
 	{	
 		ServerTransaction stx = getTransaction();
+		int outcome = ActionStatus.INVALID;
 		
 		try
 		{
-			if (stx != null)
-				return stx.doPhase2Commit();
+		    if (stx != null)
+                        return stx.doPhase2Commit();
 		}
-		catch (Exception ex)
+		catch (final Exception ex)
 		{
+		    ex.printStackTrace();
 		}
-		
-		// TODO error
-		
+
 		return ActionStatus.H_HAZARD;
 	}
 	
@@ -137,46 +139,48 @@
 	public int doRollback () throws SystemException
 	{
 		ServerTransaction stx = getTransaction();
+		int outcome = ActionStatus.INVALID;
 		
 		try
 		{	
-			if (stx != null)
-				return stx.doPhase2Abort();
+		    if (stx != null)
+                        return stx.doPhase2Abort();
 		}
-		catch (Exception ex)
+		catch (final Exception ex)
 		{
+		    ex.printStackTrace();
 		}
-			
-		// TODO error
 		
-		return ActionStatus.H_HAZARD;
+                return ActionStatus.H_HAZARD;
 	}
 	
 	public int doOnePhaseCommit () throws SystemException
 	{
 	    // https://jira.jboss.org/jira/browse/JBTM-504
 	    
-		try
-		{
-		    ServerTransaction stx = getTransaction();
-   
-		        if (stx != null)
-		            stx.doCommit(true);
-		}
-		catch (final INVALID_TRANSACTION ex)
-		{
-		    return ActionStatus.INVALID;
-		}
-		catch (final TRANSACTION_ROLLEDBACK ex)
-		{
-		    return ActionStatus.ABORTED;
-		}
-		catch (final Exception ex)
-		{
-			return ActionStatus.H_HAZARD;
-		}
-		
-		return ActionStatus.COMMITTED;
+	    try
+	    {
+	        // TODO check if we should be using TxControl.isBeforeCompletionWhenRollbackOnly in local JTA too.
+	        
+	        ServerTransaction stx = getTransaction();
+
+	        if (stx != null)
+	            stx.doCommit(true);
+	    }
+	    catch (final INVALID_TRANSACTION ex)
+	    {
+	        return ActionStatus.INVALID;
+	    }
+	    catch (final TRANSACTION_ROLLEDBACK ex)
+	    {
+	        return ActionStatus.ABORTED;
+	    }
+	    catch (final Exception ex)
+	    {
+	        return ActionStatus.H_HAZARD;
+	    }
+
+	    return ActionStatus.COMMITTED;
 	}
 	
 	public void doForget () throws SystemException
@@ -188,11 +192,61 @@
 			if (stx != null)
 				stx.doForget();
 		}
-		catch (Exception ex)
+		catch (final Exception ex)
 		{
+		    ex.printStackTrace();
 		}
 	}
 	
+	public boolean doBeforeCompletion () throws SystemException
+	{
+	    ServerTransaction stx = getTransaction();
+	    
+	    try
+	    {
+	        if (stx != null)
+	        {
+	            stx.doBeforeCompletion();
+	            
+	            return true;
+	        }
+	    }
+	    catch (final Exception ex)
+	    {
+	        ex.printStackTrace();
+	    }
+	           
+            return false;
+	}
+	
+	public boolean doAfterCompletion (int status) throws SystemException
+	{
+	    ServerTransaction stx = getTransaction();
+            
+            try
+            {
+                if (stx != null)
+                {
+                    /*
+                     * Convert from JTA status to OTS status.
+                     */
+                    
+                    org.omg.CosTransactions.Status s = ((status == Status.STATUS_COMMITTED) ? org.omg.CosTransactions.Status.StatusCommitted : 
+                                                                                              org.omg.CosTransactions.Status.StatusRolledBack);
+                    
+                    stx.doAfterCompletion(s);
+                    
+                    return true;
+                }
+            }
+            catch (final Exception ex)
+            {
+                ex.printStackTrace();
+            }
+                   
+            return false;
+	}
+	
 	/**
 	 * By default the BasicAction class only allows the termination of a
 	 * transaction if it's the one currently associated with the thread. We
@@ -215,4 +269,17 @@
 		return (ServerTransaction) sc.getImplHandle();
 	}
 	
+	    /*
+	     * We have these here because it's possible that synchronizations aren't
+	     * called explicitly either side of commit/rollback due to JCA API not supporting
+	     * them directly. We do though and in which case it's possible that they
+	     * can be driven through two routes and we don't want to get into a mess
+	     * due to that.
+	     */
+	    
+	    private boolean _doneBefore = false;
+	    private boolean _beforeOutcome = false;
+	    private boolean _doneAfter = false;
+	    private boolean _afterOutcome = false;
+	
 }

Modified: labs/jbosstm/trunk/ArjunaJTS/jtax/classes/com/arjuna/ats/internal/jta/transaction/jts/subordinate/TransactionImple.java
===================================================================
--- labs/jbosstm/trunk/ArjunaJTS/jtax/classes/com/arjuna/ats/internal/jta/transaction/jts/subordinate/TransactionImple.java	2009-05-31 11:32:25 UTC (rev 26792)
+++ labs/jbosstm/trunk/ArjunaJTS/jtax/classes/com/arjuna/ats/internal/jta/transaction/jts/subordinate/TransactionImple.java	2009-05-31 17:12:42 UTC (rev 26793)
@@ -375,7 +375,45 @@
                         throw new IllegalStateException(ex);
                 }
         }
+        
+        public boolean doBeforeCompletion () throws javax.transaction.SystemException
+        {
+            try
+            {
+                SubordinateAtomicTransaction subAct = (SubordinateAtomicTransaction) super._theTransaction;
+                
+                return subAct.doBeforeCompletion();
+            }
+            catch (final Exception ex)
+            {
+                ex.printStackTrace();
 
+                UnexpectedConditionException unexpectedConditionException = new UnexpectedConditionException(ex.toString());
+                unexpectedConditionException.initCause(ex);
+                
+                throw unexpectedConditionException;
+            }
+        }
+        
+        public boolean doAfterCompletion (int status) throws javax.transaction.SystemException
+        {
+            try
+            {
+                SubordinateAtomicTransaction subAct = (SubordinateAtomicTransaction) super._theTransaction;
+                
+                return subAct.doAfterCompletion(status);
+            }
+            catch (final Exception ex)
+            {
+                ex.printStackTrace();
+
+                UnexpectedConditionException unexpectedConditionException = new UnexpectedConditionException(ex.toString());
+                unexpectedConditionException.initCause(ex);
+                
+                throw unexpectedConditionException;
+            }
+        }
+
         public String toString ()
         {
                 if (super._theTransaction == null)

Modified: labs/jbosstm/trunk/atsintegration/classes/com/arjuna/ats/internal/jbossatx/jta/jca/XATerminator.java
===================================================================
--- labs/jbosstm/trunk/atsintegration/classes/com/arjuna/ats/internal/jbossatx/jta/jca/XATerminator.java	2009-05-31 11:32:25 UTC (rev 26792)
+++ labs/jbosstm/trunk/atsintegration/classes/com/arjuna/ats/internal/jbossatx/jta/jca/XATerminator.java	2009-05-31 17:12:42 UTC (rev 26793)
@@ -69,8 +69,6 @@
  *          com.arjuna.ats.jbossatx.jta.jca.unknownwork] Work not registered!
  */
 
-// what is the timeout period (seconds or milliseconds)?
-
 public class XATerminator extends XATerminatorImple implements
 		JBossXATerminator
 {




More information about the jboss-svn-commits mailing list