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

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Thu Mar 4 08:03:01 EST 2010


Author: jhalliday
Date: 2010-03-04 08:03:00 -0500 (Thu, 04 Mar 2010)
New Revision: 31932

Added:
   labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/recovery/arjunacore/JTANodeNameXAResourceOrphanFilter.java
   labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/recovery/arjunacore/JTATransactionLogXAResourceOrphanFilter.java
   labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/recovery/arjunacore/NodeNameXAResourceOrphanFilter.java
   labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/jta/recovery/XAResourceOrphanFilter.java
   labs/jbosstm/trunk/ArjunaJTA/jta/tests/classes/com/hp/mwtests/ts/jta/recovery/XAResourceOrphanFilterTest.java
Modified:
   labs/jbosstm/trunk/ArjunaJTA/jbossts-properties-arjunajta.xml
   labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/recovery/arjunacore/RecoveryXids.java
   labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/recovery/arjunacore/XARecoveryModule.java
   labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/jta/common/JTAEnvironmentBean.java
   labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/jta/common/JTAEnvironmentBeanMBean.java
   labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/jta/xa/XATxConverter.java
   labs/jbosstm/trunk/ArjunaJTA/jta/tests/classes/com/hp/mwtests/ts/jta/recovery/XARecoveryModuleUnitTest.java
   labs/jbosstm/trunk/ArjunaJTS/jbossts-properties-arjunajts.xml
   labs/jbosstm/trunk/atsintegration/transaction-jboss-beans.xml
   labs/jbosstm/trunk/atsintegration/transaction-jboss-beans.xml.jts
Log:
Allow configurable handling of in-doubt xids during recovery. JBTM-723


Modified: labs/jbosstm/trunk/ArjunaJTA/jbossts-properties-arjunajta.xml
===================================================================
--- labs/jbosstm/trunk/ArjunaJTA/jbossts-properties-arjunajta.xml	2010-03-04 12:05:31 UTC (rev 31931)
+++ labs/jbosstm/trunk/ArjunaJTA/jbossts-properties-arjunajta.xml	2010-03-04 13:03:00 UTC (rev 31932)
@@ -66,7 +66,12 @@
 
 	<!-- Which Xid types to recover -->
 	<entry key="JTAEnvironmentBean.xaRecoveryNodes">1</entry>
-	
+
+    <entry key="JTAEnvironmentBean.xaResourceOrphanFilters">
+        com.arjuna.ats.internal.jta.recovery.arjunacore.JTATransactionLogXAResourceOrphanFilter
+        com.arjuna.ats.internal.jta.recovery.arjunacore.JTANodeNameXAResourceOrphanFilter
+    </entry>
+
     <!--
       Base port number for determining a unique number to associate with an instance of the transaction service
       (which is needed in order to support multiple instances on the same machine).

Added: labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/recovery/arjunacore/JTANodeNameXAResourceOrphanFilter.java
===================================================================
--- labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/recovery/arjunacore/JTANodeNameXAResourceOrphanFilter.java	                        (rev 0)
+++ labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/recovery/arjunacore/JTANodeNameXAResourceOrphanFilter.java	2010-03-04 13:03:00 UTC (rev 31932)
@@ -0,0 +1,49 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and/or its affiliates,
+ * 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) 2010,
+ * @author JBoss, by Red Hat.
+ */
+package com.arjuna.ats.internal.jta.recovery.arjunacore;
+
+import com.arjuna.ats.jta.recovery.XAResourceOrphanFilter;
+import com.arjuna.ats.jta.xa.XATxConverter;
+
+import javax.transaction.xa.Xid;
+
+/**
+ * An XAResourceOrphanFilter for JTA top level transactions, which uses node name information
+ * encoded in the xid to determine if they should be rolled back or not.
+ *
+ * @author Jonathan Halliday (jonathan.halliday at redhat.com), 2010-03
+ */
+public class JTANodeNameXAResourceOrphanFilter implements XAResourceOrphanFilter
+{
+    private final XAResourceOrphanFilter nodeNameFilter = new NodeNameXAResourceOrphanFilter();
+
+    protected final int myFormatId = XATxConverter.FORMAT_ID;
+
+    @Override
+    public Vote checkXid(Xid xid)
+    {
+        if(xid.getFormatId() != myFormatId) {
+            return Vote.ABSTAIN;
+        }
+
+        return nodeNameFilter.checkXid(xid);
+    }
+}
\ No newline at end of file

Added: labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/recovery/arjunacore/JTATransactionLogXAResourceOrphanFilter.java
===================================================================
--- labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/recovery/arjunacore/JTATransactionLogXAResourceOrphanFilter.java	                        (rev 0)
+++ labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/recovery/arjunacore/JTATransactionLogXAResourceOrphanFilter.java	2010-03-04 13:03:00 UTC (rev 31932)
@@ -0,0 +1,144 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and/or its affiliates,
+ * 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) 2010,
+ * @author JBoss, by Red Hat.
+ */
+package com.arjuna.ats.internal.jta.recovery.arjunacore;
+
+import com.arjuna.ats.arjuna.common.Uid;
+import com.arjuna.ats.arjuna.coordinator.TxControl;
+import com.arjuna.ats.arjuna.logging.FacilityCode;
+import com.arjuna.ats.arjuna.objectstore.ObjectStore;
+import com.arjuna.ats.arjuna.objectstore.StateStatus;
+import com.arjuna.ats.internal.jta.transaction.arjunacore.AtomicAction;
+import com.arjuna.ats.jta.logging.jtaLogger;
+import com.arjuna.ats.jta.recovery.XAResourceOrphanFilter;
+import com.arjuna.ats.jta.xa.XATxConverter;
+import com.arjuna.ats.jta.xa.XidImple;
+import com.arjuna.common.util.logging.DebugLevel;
+import com.arjuna.common.util.logging.VisibilityLevel;
+
+import javax.transaction.xa.Xid;
+
+/**
+ * An XAResourceOrphanFilter which vetos rollback for xids owned by top level JTA transactions.
+ *
+ * @author Jonathan Halliday (jonathan.halliday at redhat.com), 2010-03
+ */
+public class JTATransactionLogXAResourceOrphanFilter implements XAResourceOrphanFilter
+{
+    @Override
+    public Vote checkXid(Xid xid)
+    {
+        if(xid.getFormatId() != XATxConverter.FORMAT_ID) {
+            // we only care about Xids created by the JTA
+            return Vote.ABSTAIN;
+        }
+
+        if(transactionLog(xid)) {
+            // it's owned by a logged transaction which
+            // will recover it top down in due course
+            return Vote.LEAVE_ALONE;
+        }
+
+        return Vote.ABSTAIN;
+    }
+
+    /**
+	 * Is there a log file for this transaction?
+	 *
+	 * @param xid the transaction to check.
+	 *
+	 * @return <code>boolean</code>true if there is a log file,
+	 *         <code>false</code> if there isn't.
+	 *
+	 * @message com.arjuna.ats.internal.jta.recovery.notaxid {0} not an Arjuna
+	 *          XID
+	 */
+    private boolean transactionLog(Xid xid)
+    {
+        ObjectStore transactionStore = TxControl.getStore();
+        String transactionType = new AtomicAction().type();
+
+        XidImple theXid = new XidImple(xid);
+        Uid u = theXid.getTransactionUid();
+
+        if (jtaLogger.logger.isDebugEnabled())
+        {
+            jtaLogger.logger.debug(DebugLevel.FUNCTIONS,
+                    VisibilityLevel.VIS_PRIVATE,
+                    FacilityCode.FAC_CRASH_RECOVERY,
+                    "Checking whether Xid "
+                            + theXid + " exists in ObjectStore.");
+        }
+
+        if (!u.equals(Uid.nullUid()))
+        {
+            try
+            {
+
+                if (jtaLogger.logger.isDebugEnabled())
+                {
+                    jtaLogger.logger.debug(DebugLevel.FUNCTIONS,
+                            VisibilityLevel.VIS_PRIVATE,
+                            FacilityCode.FAC_CRASH_RECOVERY,
+                            "Looking for "+u+" and "+transactionType);
+                }
+
+                if (transactionStore.currentState(u, transactionType) != StateStatus.OS_UNKNOWN)
+                {
+                    if (jtaLogger.logger.isDebugEnabled())
+                    {
+                        jtaLogger.logger.debug(DebugLevel.FUNCTIONS,
+                                VisibilityLevel.VIS_PRIVATE,
+                                FacilityCode.FAC_CRASH_RECOVERY,
+                                "Found record for "+theXid);
+                    }
+
+                    return true;
+                }
+                else
+                {
+                    if (jtaLogger.logger.isDebugEnabled())
+                    {
+                        jtaLogger.logger.debug(DebugLevel.FUNCTIONS,
+                                VisibilityLevel.VIS_PRIVATE,
+                                FacilityCode.FAC_CRASH_RECOVERY,
+                                "No record found for "+theXid);
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                ex.printStackTrace();
+            }
+        }
+        else
+        {
+            if (jtaLogger.logger.isInfoEnabled())
+            {
+                jtaLogger.loggerI18N.info(
+                        "com.arjuna.ats.internal.jta.recovery.notaxid",
+                        new Object[]
+                                { xid });
+            }
+        }
+
+        return false;
+    }
+}

Added: labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/recovery/arjunacore/NodeNameXAResourceOrphanFilter.java
===================================================================
--- labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/recovery/arjunacore/NodeNameXAResourceOrphanFilter.java	                        (rev 0)
+++ labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/recovery/arjunacore/NodeNameXAResourceOrphanFilter.java	2010-03-04 13:03:00 UTC (rev 31932)
@@ -0,0 +1,103 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and/or its affiliates,
+ * 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) 2010,
+ * @author JBoss, by Red Hat.
+ */
+package com.arjuna.ats.internal.jta.recovery.arjunacore;
+
+import com.arjuna.ats.arjuna.logging.FacilityCode;
+import com.arjuna.ats.internal.jta.utils.XAUtils;
+import com.arjuna.ats.jta.common.jtaPropertyManager;
+import com.arjuna.ats.jta.logging.jtaLogger;
+import com.arjuna.ats.jta.recovery.XAResourceOrphanFilter;
+import com.arjuna.common.util.logging.DebugLevel;
+import com.arjuna.common.util.logging.VisibilityLevel;
+
+import javax.transaction.xa.Xid;
+import java.util.List;
+
+/**
+ * An XAResourceOrphanFilter which uses node name information encoded in the xid to determine if
+ * they should be rolled back or not.
+ *
+ * Note that this filter does not check xid format id, and therefore may attempt to extract node name
+ * information from foreign xids, resulting in random behaviour. Probably best combined with a filter
+ * that verifies formatIds.
+ *
+ * @author Jonathan Halliday (jonathan.halliday at redhat.com), 2010-03
+ */
+public class NodeNameXAResourceOrphanFilter implements XAResourceOrphanFilter
+{
+    private static final String RECOVER_ALL_NODES = "*";
+
+    @Override
+    public Vote checkXid(Xid xid)
+    {
+        List<String> _xaRecoveryNodes = jtaPropertyManager.getJTAEnvironmentBean().getXaRecoveryNodes();
+
+        if(_xaRecoveryNodes == null || _xaRecoveryNodes.size() == 0) {
+            doWarning();
+            return Vote.ABSTAIN;
+        }
+
+        if ((_xaRecoveryNodes.contains(RECOVER_ALL_NODES)))
+        {
+            if (jtaLogger.logger.isDebugEnabled())
+            {
+                jtaLogger.logger.debug(
+                        DebugLevel.FUNCTIONS,
+                        VisibilityLevel.VIS_PRIVATE,
+                        FacilityCode.FAC_CRASH_RECOVERY,
+                        "Ignoring node name. Will recover "+ xid);
+            }
+
+            return Vote.ROLLBACK;
+        }
+
+        String nodeName = XAUtils.getXANodeName(xid);
+
+        if (jtaLogger.logger.isDebugEnabled())
+        {
+            jtaLogger.logger.debug(DebugLevel.FUNCTIONS,
+                    VisibilityLevel.VIS_PRIVATE,
+                    FacilityCode.FAC_CRASH_RECOVERY,
+                    "node name of " + xid +" is "+nodeName);
+        }
+
+        if (_xaRecoveryNodes.contains(nodeName))
+        {
+            return Vote.ROLLBACK;
+        }
+        else
+        {
+            return Vote.ABSTAIN;
+        }
+    }
+
+    /**
+     * @message com.arjuna.ats.internal.jta.recovery.noxanodes No XA recovery
+	 *          nodes specified. May not recover orphans.
+     */
+    private void doWarning() {
+        if (jtaLogger.loggerI18N.isInfoEnabled())
+        {
+            jtaLogger.loggerI18N
+                    .info("com.arjuna.ats.internal.jta.recovery.noxanodes");
+        }
+    }
+}

Modified: labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/recovery/arjunacore/RecoveryXids.java
===================================================================
--- labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/recovery/arjunacore/RecoveryXids.java	2010-03-04 12:05:31 UTC (rev 31931)
+++ labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/recovery/arjunacore/RecoveryXids.java	2010-03-04 13:03:00 UTC (rev 31932)
@@ -110,7 +110,7 @@
      * they won't appear in the next new list of inflight transactions.
      */
 
-    public final java.lang.Object[] toRecover ()
+    public final Xid[] toRecover ()
     {
         final int numScanN = (_scanN == null ? 0 : _scanN.length) ;
         final int numScanM = (_scanM == null ? 0 : _scanM.length) ;
@@ -121,7 +121,7 @@
             return null ;
         }
         
-        final Vector workingVector = new Vector() ;
+        final Vector<Xid> workingVector = new Vector<Xid>() ;
         
         for (int count = 0 ; count < numScan ; count++)
         {
@@ -131,7 +131,7 @@
             }
         }
         
-        return workingVector.toArray();
+        return workingVector.toArray(new Xid[workingVector.size()]);
     }
 
     public final boolean isSameRM (XAResource xares)

Modified: labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/recovery/arjunacore/XARecoveryModule.java
===================================================================
--- labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/recovery/arjunacore/XARecoveryModule.java	2010-03-04 12:05:31 UTC (rev 31931)
+++ labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/recovery/arjunacore/XARecoveryModule.java	2010-03-04 13:03:00 UTC (rev 31932)
@@ -40,14 +40,12 @@
 import com.arjuna.ats.arjuna.logging.FacilityCode;
 
 import com.arjuna.ats.internal.arjuna.common.UidHelper;
-import com.arjuna.ats.internal.jta.utils.XAUtils;
 import com.arjuna.ats.internal.jta.transaction.arjunacore.AtomicAction;
 
 import com.arjuna.ats.jta.logging.jtaLogger;
 import com.arjuna.ats.jta.common.jtaPropertyManager;
 import com.arjuna.ats.jta.recovery.*;
 import com.arjuna.ats.jta.utils.XAHelper;
-import com.arjuna.ats.jta.xa.XidImple;
 
 import com.arjuna.common.util.logging.*;
 
@@ -65,13 +63,7 @@
 
 public class XARecoveryModule implements RecoveryModule
 {
-	// why not in Environment?
-
-	public static final String XARecoveryPropertyNamePrefix = "com.arjuna.ats.jta.recovery.XAResourceRecovery";
-
-	private static final String RECOVER_ALL_NODES = "*";
-
-	public XARecoveryModule()
+    public XARecoveryModule()
 	{
 		this(
 				com.arjuna.ats.internal.jta.recovery.arjunacore.XARecoveryResourceManagerImple.class
@@ -95,7 +87,22 @@
         }
     }
 
+    public void addXAResourceOrphanFilter(XAResourceOrphanFilter xaResourceOrphanFilter) {
+        synchronized (_xaResourceOrphanFilters) {
+            if(!_xaResourceOrphanFilters.contains(xaResourceOrphanFilter)) {
+                _xaResourceOrphanFilters.add(xaResourceOrphanFilter);
+            }
+        }
+    }
+    
+    public void removeXAResourceOrphanFilter(XAResourceOrphanFilter xaResourceOrphanFilter) {
+        synchronized (_xaResourceOrphanFilters) {
+            _xaResourceOrphanFilters.remove(xaResourceOrphanFilter);
+        }
+    }
 
+
+
     /**
 	 * @message com.arjuna.ats.internal.jta.recovery.xafirstpass {0} - first
 	 *          pass
@@ -232,8 +239,7 @@
 	}
 
 	/**
-	 * @param Xid
-	 *            xid The transaction to commit/rollback.
+	 * @param xid The transaction to commit/rollback.
 	 *
 	 * @return the XAResource than can be used to commit/rollback the specified
 	 *         transaction.
@@ -368,19 +374,26 @@
                     }
                 }
             }
-        }
 
-        // Find the node(s) we can recover on behalf of.
-        _xaRecoveryNodes = new Vector<String>(jtaPropertyManager.getJTAEnvironmentBean().getXaRecoveryNodes());
-
-		if ((_xaRecoveryNodes == null) || (_xaRecoveryNodes.size() == 0))
-		{
-			if (jtaLogger.loggerI18N.isInfoEnabled())
-			{
-				jtaLogger.loggerI18N
-						.info("com.arjuna.ats.internal.jta.recovery.noxanodes");
-			}
-		}
+            for(String xaResourceOrphanFilterClassname : jtaPropertyManager.getJTAEnvironmentBean().getXaResourceOrphanFilters())
+            {
+                try
+                {
+                    Class c = Thread.currentThread().getContextClassLoader().loadClass(xaResourceOrphanFilterClassname);
+                    XAResourceOrphanFilter filter = (XAResourceOrphanFilter)c.newInstance();
+                    _xaResourceOrphanFilters.add(filter);
+                }
+                catch(Exception e)
+                {
+                    if (jtaLogger.loggerI18N.isWarnEnabled())
+                    {
+                        jtaLogger.loggerI18N
+                                .warn("com.arjuna.ats.internal.jta.recovery.general",
+                                        new Object[] { e, xaResourceOrphanFilterClassname }, e);
+                    }
+                }
+            }
+        }
 	}
 
 	/**
@@ -395,8 +408,6 @@
 	 *          resource to table: no XID value available.
 	 * @message com.arjuna.ats.internal.jta.recovery.unexpectedrecoveryerror
 	 *          Unexpceted recovery error:
-	 * @message com.arjuna.ats.internal.jta.recovery.noxanodes No XA recovery
-	 *          nodes specified. Will only recover saved states.
 	 */ 
 
 	private final boolean transactionInitiatedRecovery()
@@ -806,7 +817,7 @@
 
 			xidsToRecover.nextScan(trans);
 
-			Object[] xids = xidsToRecover.toRecover();
+			Xid[] xids = xidsToRecover.toRecover();
 
 			if (xids != null)
 			{
@@ -834,7 +845,7 @@
 					{
 						// is the xid known to be one that couldn't be recovered
 
-						recordUid = previousFailure((Xid) xids[j]);
+						recordUid = previousFailure(xids[j]);
 
 						if ((recordUid == null) && (foundTransaction))
 							break; // end
@@ -845,215 +856,16 @@
 						// transaction
 
 						if (recordUid == null)
+                        {
+                            /*
+                            * It wasn't an xid that we couldn't recover, so the
+                            * RM knows about it, but we don't. Therefore it may
+                            * have to be rolled back.
+                            */
+                            doForget = handleOrphan(xares, xids[j]);
+                        }
+                        else
 						{
-							/*
-							 * It wasn't an xid that we couldn't recover, so the
-							 * RM knows about it, but we don't. Therefore it may
-							 * have to be rolled back.
-							 */
-
-							if (jtaLogger.logger.isDebugEnabled())
-							{
-								jtaLogger.logger.debug(DebugLevel.FUNCTIONS,
-										VisibilityLevel.VIS_PRIVATE,
-										FacilityCode.FAC_CRASH_RECOVERY,
-										"Checking node name of "
-												+ ((Xid) xids[j]));
-							}
-
-							String nodeName = XAUtils
-									.getXANodeName((Xid) xids[j]);
-							boolean doRecovery = false;
-
-							if (jtaLogger.logger.isDebugEnabled())
-							{
-								jtaLogger.logger.debug(DebugLevel.FUNCTIONS,
-										VisibilityLevel.VIS_PRIVATE,
-										FacilityCode.FAC_CRASH_RECOVERY,
-										"Node name is " + nodeName);
-							}
-
-							/*
-							 * If there is no node name but we have been told to
-							 * recover everything, then we can roll it back.
-							 */
-
-							if ((nodeName == null)
-									&& (_xaRecoveryNodes != null)
-									&& (_xaRecoveryNodes
-											.contains(RECOVER_ALL_NODES)))
-							{
-								if (jtaLogger.logger.isDebugEnabled())
-								{
-									jtaLogger.logger.debug(
-											DebugLevel.FUNCTIONS,
-											VisibilityLevel.VIS_PRIVATE,
-											FacilityCode.FAC_CRASH_RECOVERY,
-											"Ignoring node name. Will recover "+(Xid) xids[j]);
-								}
-
-								doRecovery = true;
-							}
-							else
-							{
-								if (nodeName != null)
-								{
-									/*
-									 * Check that the node name is in our
-									 * recovery set or that we have been told to
-									 * recover everything.
-									 */
-
-									if (_xaRecoveryNodes != null)
-									{
-										if (_xaRecoveryNodes
-												.contains(RECOVER_ALL_NODES)
-												|| _xaRecoveryNodes
-														.contains(nodeName))
-										{
-											if (jtaLogger.loggerI18N
-													.isDebugEnabled())
-											{
-												jtaLogger.logger
-														.debug(
-																DebugLevel.FUNCTIONS,
-																VisibilityLevel.VIS_PRIVATE,
-																FacilityCode.FAC_CRASH_RECOVERY,
-																"Node name matches. Will recover "+(Xid) xids[j]);
-											}
-
-											doRecovery = true;
-										}
-										else
-										{
-											if (jtaLogger.loggerI18N
-													.isDebugEnabled())
-											{
-												jtaLogger.logger
-														.debug(
-																DebugLevel.FUNCTIONS,
-																VisibilityLevel.VIS_PRIVATE,
-																FacilityCode.FAC_CRASH_RECOVERY,
-																"Node name does not match. Ignoring Xid.");
-											}
-										}
-									}
-									else
-									{
-										if (jtaLogger.loggerI18N
-												.isDebugEnabled())
-										{
-											jtaLogger.logger
-													.debug(
-															DebugLevel.FUNCTIONS,
-															VisibilityLevel.VIS_PRIVATE,
-															FacilityCode.FAC_CRASH_RECOVERY,
-															"Node name not set. Ignoring Xid.");
-										}
-									}
-								}
-								else
-								{
-									if (jtaLogger.logger.isDebugEnabled())
-									{
-										jtaLogger.logger
-												.debug(
-														DebugLevel.FUNCTIONS,
-														VisibilityLevel.VIS_PRIVATE,
-														FacilityCode.FAC_CRASH_RECOVERY,
-														"Will not recover this Xid");
-									}
-								}
-							}
-
-							try
-							{
-								if (doRecovery)
-								{
-									if (!transactionLog((Xid) xids[j]))
-									{
-									    if (jtaLogger.loggerI18N.isInfoEnabled())
-	                                                                        {
-	                                                                                jtaLogger.loggerI18N
-	                                                                                                .info(
-	                                                                                                                "com.arjuna.ats.internal.jta.recovery.info.rollingback",
-	                                                                                                                new Object[]
-	                                                                                                                { XAHelper
-	                                                                                                                                .xidToString((Xid) xids[j]) });
-	                                                                        }
-									    
-										xares.rollback((Xid) xids[j]);
-									}
-									else
-									{
-									    if (jtaLogger.loggerI18N.isInfoEnabled())
-	                                                                        {
-	                                                                                jtaLogger.loggerI18N
-	                                                                                                .info(
-	                                                                                                                "com.arjuna.ats.internal.jta.recovery.info.rollingbackignore",
-	                                                                                                                new Object[]
-	                                                                                                                { XAHelper
-	                                                                                                                                .xidToString((Xid) xids[j]) });
-	                                                                        }
-									    
-										/*
-										 * Ignore it as the transaction system
-										 * will recovery it eventually.
-										 */
-									}
-								}
-								else
-								{
-									if (jtaLogger.loggerI18N.isInfoEnabled())
-									{
-										jtaLogger.loggerI18N
-												.info(
-														"com.arjuna.ats.internal.jta.recovery.info.notrollback",
-														new Object[]
-														{ XAHelper
-																.xidToString((Xid) xids[j]) });
-									}
-								}
-							}
-							catch (XAException e1)
-							{
-								e1.printStackTrace();
-
-								switch (e1.errorCode)
-								{
-								case XAException.XAER_RMERR:
-									break;
-								case XAException.XA_HEURHAZ:
-								case XAException.XA_HEURCOM:
-								case XAException.XA_HEURMIX:
-								case XAException.XA_HEURRB:
-								case XAException.XA_RBROLLBACK:
-								{
-									if (!doForget) // already done?
-										doForget = true;
-								}
-									break;
-								default:
-									break;
-								}
-							}
-							catch (Exception e2)
-							{
-								if (jtaLogger.loggerI18N.isWarnEnabled())
-								{
-									jtaLogger.loggerI18N
-											.warn(
-													"com.arjuna.ats.internal.jta.recovery.xarecovery2",
-													new Object[]
-													{
-															_logName
-																	+ ".xaRecovery ",
-															e2 });
-								}
-							}
-						}
-						else
-						{
 							foundTransaction = true;
 
 							/*
@@ -1089,7 +901,7 @@
 						{
 							try
 							{
-								xares.forget((Xid) xids[j]);
+								xares.forget(xids[j]);
 							}
 							catch (Exception e)
 							{
@@ -1142,6 +954,84 @@
 	}
 
     /**
+     * Apply use configurable filtering to determine how to handle the in-doubt resource.
+     *
+     * @param xares
+     * @param xid
+     * @return true if forget should be called, false otherwise.
+     */
+    private boolean handleOrphan(XAResource xares, Xid xid)
+    {
+        // be default we play it safe and leave resources alone unless a filter explicitly recognizes them.
+        // getting presumed abort behaviour therefore requires appropriate filters to be registered.
+        XAResourceOrphanFilter.Vote votingOutcome = XAResourceOrphanFilter.Vote.LEAVE_ALONE;
+
+        for(XAResourceOrphanFilter filter : _xaResourceOrphanFilters) {
+            XAResourceOrphanFilter.Vote vote = filter.checkXid(xid);
+
+            if(jtaLogger.logger.isDebugEnabled()) {
+                jtaLogger.logger.debug(DebugLevel.FUNCTIONS, VisibilityLevel.VIS_PRIVATE,
+                        FacilityCode.FAC_CRASH_RECOVERY, "XAResourceOrphanFilter "+filter.getClass().getName()+" voted "+vote);
+            }
+
+            if(vote == XAResourceOrphanFilter.Vote.LEAVE_ALONE)
+            {
+                return false;
+            }
+            else if(vote == XAResourceOrphanFilter.Vote.ROLLBACK)
+            {
+                votingOutcome = vote;
+            }
+        }
+
+        try
+        {
+            if(votingOutcome == XAResourceOrphanFilter.Vote.ROLLBACK)
+            {
+                if (jtaLogger.loggerI18N.isInfoEnabled())
+                {
+                    jtaLogger.loggerI18N
+                            .info("com.arjuna.ats.internal.jta.recovery.info.rollingback",
+                                    new Object[] { XAHelper.xidToString(xid) });
+                }
+
+                xares.rollback(xid);
+            }
+        }
+        catch (XAException e1)
+        {
+            e1.printStackTrace();
+
+            switch (e1.errorCode)
+            {
+                case XAException.XAER_RMERR:
+                    break;
+                case XAException.XA_HEURHAZ:
+                case XAException.XA_HEURCOM:
+                case XAException.XA_HEURMIX:
+                case XAException.XA_HEURRB:
+                case XAException.XA_RBROLLBACK:
+                {
+                    return true;
+                }
+                default:
+                    break;
+            }
+        }
+        catch (Exception e2)
+        {
+            if (jtaLogger.loggerI18N.isWarnEnabled())
+            {
+                jtaLogger.loggerI18N
+                        .warn(
+                                "com.arjuna.ats.internal.jta.recovery.xarecovery2",
+                                new Object[] { _logName + ".xaRecovery ", e2 });
+            }
+        }
+        return false;
+    }
+
+    /**
      * For some drivers, isSameRM is connection specific. If we have prev scan results
      * for the same RM but using a different connection, we need to be able to identify them.
      * Look at the data from previous scans, identify any for the same RM but different XAResource
@@ -1175,93 +1065,6 @@
     }
 
 	/**
-	 * Is there a log file for this transaction?
-	 *
-	 * @param Xid
-	 *            xid the transaction to check.
-	 *
-	 * @return <code>boolean</code>true if there is a log file,
-	 *         <code>false</code> if there isn't.
-	 *
-	 * @message com.arjuna.ats.internal.jta.recovery.notaxid {0} not an Arjuna
-	 *          XID
-	 */
-
-	private final boolean transactionLog(Xid xid)
-	{
-		if (_transactionStore == null)
-		{
-			_transactionStore = TxControl.getStore();
-		}
-		
-		XidImple theXid = new XidImple(xid);
-		Uid u = theXid.getTransactionUid();
-
-                if (jtaLogger.logger.isDebugEnabled())
-                {
-                        jtaLogger.logger.debug(DebugLevel.FUNCTIONS,
-                                        VisibilityLevel.VIS_PRIVATE,
-                                        FacilityCode.FAC_CRASH_RECOVERY,
-                                        "Checking whether Xid "
-                                                        + theXid + " exists in ObjectStore.");
-                }
-                
-		if (!u.equals(Uid.nullUid()))
-		{
-			try
-			{
-
-		                if (jtaLogger.logger.isDebugEnabled())
-		                {
-		                        jtaLogger.logger.debug(DebugLevel.FUNCTIONS,
-		                                        VisibilityLevel.VIS_PRIVATE,
-		                                        FacilityCode.FAC_CRASH_RECOVERY,
-		                                        "Looking for "+u+" and "+_transactionType);
-		                }
-		                
-				if (_transactionStore.currentState(u, _transactionType) != StateStatus.OS_UNKNOWN)
-				{
-	                                if (jtaLogger.logger.isDebugEnabled())
-	                                {
-	                                        jtaLogger.logger.debug(DebugLevel.FUNCTIONS,
-	                                                        VisibilityLevel.VIS_PRIVATE,
-	                                                        FacilityCode.FAC_CRASH_RECOVERY,
-	                                                        "Found record for "+theXid);
-	                                }
-	                                
-					return true;
-				}
-				else
-				{
-	                                if (jtaLogger.logger.isDebugEnabled())
-	                                {
-	                                        jtaLogger.logger.debug(DebugLevel.FUNCTIONS,
-	                                                        VisibilityLevel.VIS_PRIVATE,
-	                                                        FacilityCode.FAC_CRASH_RECOVERY,
-	                                                        "No record found for "+theXid);
-	                                }
-				}
-			}
-			catch (Exception ex)
-			{
-				ex.printStackTrace();
-			}
-		}
-		else
-		{
-			if (jtaLogger.logger.isInfoEnabled())
-			{
-				jtaLogger.loggerI18N.info(
-						"com.arjuna.ats.internal.jta.recovery.notaxid",
-						new Object[]
-						{ xid });
-			}
-		}
-
-		return false;
-	}
-
-	/**
 	 * Is the Xid is in the failure list, i.e., the list of those transactions
 	 * we couldn't recover, possibly because of transient failures. If so,
 	 * return the uid of (one of) the records and remove it from the list.
@@ -1369,6 +1172,8 @@
 
     private final List<XAResourceRecoveryHelper> _xaResourceRecoveryHelpers = new LinkedList<XAResourceRecoveryHelper>();
 
+    private final List<XAResourceOrphanFilter> _xaResourceOrphanFilters = new LinkedList<XAResourceOrphanFilter>();
+
     private Hashtable _failures = null;
 
 	private Vector _xaRecoveryNodes = null;
@@ -1385,8 +1190,6 @@
 	// Reference to the Object Store.
 	private static ObjectStore _transactionStore = null;
 
-	// milliseconds
-
 	private static final char BREAKCHARACTER = ';'; // delimiter for xaconnrecov
 	// property
 }

Modified: labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/jta/common/JTAEnvironmentBean.java
===================================================================
--- labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/jta/common/JTAEnvironmentBean.java	2010-03-04 12:05:31 UTC (rev 31931)
+++ labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/jta/common/JTAEnvironmentBean.java	2010-03-04 13:03:00 UTC (rev 31932)
@@ -47,6 +47,8 @@
     @ConcatenationPrefix(prefix = "com.arjuna.ats.jta.recovery.XAResourceRecovery")
     private volatile List<String> xaResourceRecoveryInstances = new ArrayList<String>();
 
+    private volatile List<String> xaResourceOrphanFilters = new ArrayList<String>();
+
     private volatile boolean xaRollbackOptimization = false;
     private volatile boolean xaAssumeRecoveryComplete = false;
 
@@ -218,6 +220,36 @@
     }
 
     /**
+     * Returns a list of names of classes that implement XAResourceOrphanFilter.
+     * The returned list is a copy. May return an empty list, will not return null.
+     *
+     * Default: empty list.
+     * Equivalent deprecated property prefix:
+     *
+     * @return a list of XAResourceOrphanFilter implementation class names.
+     */
+    public List<String> getXaResourceOrphanFilters()
+    {
+        return new ArrayList<String>(xaResourceOrphanFilters);
+    }
+
+    /**
+     * Sets the XAResource orphan filters.
+     * List elements should be names of classes that implement XAResourceOrphanFilter.
+     * The provided list will be copied, not retained.
+     *
+     * @param xaResourceOrphanFilters a list of XAResourceOrphanFilter implementation classes.
+     */
+    public void setXaResourceOrphanFilters(List<String> xaResourceOrphanFilters)
+    {
+        if(xaResourceOrphanFilters == null) {
+            this.xaResourceOrphanFilters = new ArrayList<String>();
+        } else {
+            this.xaResourceOrphanFilters = new ArrayList<String>(xaResourceOrphanFilters);
+        }
+    }
+
+    /**
      * Returns if connections associated to XAResources that fail during prepare should be cleaned up immediately.
      * TODO move to JDBC module as it's only for our own connection manager?
      *

Modified: labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/jta/common/JTAEnvironmentBeanMBean.java
===================================================================
--- labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/jta/common/JTAEnvironmentBeanMBean.java	2010-03-04 12:05:31 UTC (rev 31931)
+++ labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/jta/common/JTAEnvironmentBeanMBean.java	2010-03-04 13:03:00 UTC (rev 31932)
@@ -52,7 +52,11 @@
     List<String> getXaResourceRecoveryInstances();
 
     void setXaResourceRecoveryInstances(List<String> xaResourceRecoveryInstances);
-    
+
+    List<String> getXaResourceOrphanFilters();
+
+    void setXaResourceOrphanFilters(List<String> xaResourceOrphanFilters);
+
     boolean isXaRollbackOptimization();
 
     void setXaRollbackOptimization(boolean xaRollbackOptimization);

Added: labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/jta/recovery/XAResourceOrphanFilter.java
===================================================================
--- labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/jta/recovery/XAResourceOrphanFilter.java	                        (rev 0)
+++ labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/jta/recovery/XAResourceOrphanFilter.java	2010-03-04 13:03:00 UTC (rev 31932)
@@ -0,0 +1,48 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and/or its affiliates,
+ * 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) 2010,
+ * @author JBoss, by Red Hat.
+ */
+package com.arjuna.ats.jta.recovery;
+
+import javax.transaction.xa.Xid;
+
+/**
+ * Interface used by the XARecoveryModule to allow plugins to vote in the handling of in-doubt Xids.
+ *
+ *  @author Jonathan Halliday (jonathan.halliday at redhat.com), 2010-03
+ */
+public interface XAResourceOrphanFilter
+{
+    public enum Vote { ABSTAIN, ROLLBACK, LEAVE_ALONE }
+
+    /**
+     * Called by the XARecoveryModule for each in-doubt Xid.
+     * Implementations should return
+     *   Vote.ROLLBACK if they recognize the xid and believe it should be aborted.
+     *   Vote.LEAVE_ALONE if they recognize the xid and do not want the XARecovery module to roll it back.
+     *   Vote.ABSTAIN if they do not recognize the xid.
+     * Each registered XAResourceOrphanFilter will be consulted before any rollback on each recovery pass,
+     * so they may change their mind over time e.g. if new information becomes available due to other recovery
+     * activity.
+     *
+     * @param xid The in-doubt xid.
+     * @return a Vote in accordance with the guidelines above.
+     */
+    public Vote checkXid(Xid xid);
+}
\ No newline at end of file

Modified: labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/jta/xa/XATxConverter.java
===================================================================
--- labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/jta/xa/XATxConverter.java	2010-03-04 12:05:31 UTC (rev 31931)
+++ labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/jta/xa/XATxConverter.java	2010-03-04 13:03:00 UTC (rev 31932)
@@ -153,10 +153,8 @@
 
     public static String getNodeName(XID xid)
     {
-        if(xid.formatID != FORMAT_ID) {
-            return null;
-        }
-
+        // don't check the formatId - it may differ e.g. JTA vs. JTS.
+        
         // the node name follows the Uid with no separator, so the only
         // way to tell where it starts is to figure out how long the Uid is.
         Uid uid = getUid(xid);

Modified: labs/jbosstm/trunk/ArjunaJTA/jta/tests/classes/com/hp/mwtests/ts/jta/recovery/XARecoveryModuleUnitTest.java
===================================================================
--- labs/jbosstm/trunk/ArjunaJTA/jta/tests/classes/com/hp/mwtests/ts/jta/recovery/XARecoveryModuleUnitTest.java	2010-03-04 12:05:31 UTC (rev 31931)
+++ labs/jbosstm/trunk/ArjunaJTA/jta/tests/classes/com/hp/mwtests/ts/jta/recovery/XARecoveryModuleUnitTest.java	2010-03-04 13:03:00 UTC (rev 31932)
@@ -33,6 +33,8 @@
 
 import java.util.ArrayList;
 
+import com.arjuna.ats.jta.recovery.XAResourceOrphanFilter;
+import com.arjuna.ats.jta.recovery.XAResourceRecoveryHelper;
 import org.junit.Test;
 
 import com.arjuna.ats.arjuna.coordinator.TwoPhaseOutcome;
@@ -41,6 +43,9 @@
 import com.arjuna.ats.jta.common.jtaPropertyManager;
 import com.hp.mwtests.ts.jta.common.RecoveryXAResource;
 
+import javax.transaction.xa.XAResource;
+import javax.transaction.xa.Xid;
+
 import static org.junit.Assert.*;
 
 public class XARecoveryModuleUnitTest
@@ -76,4 +81,48 @@
             xarm.periodicWorkSecondPass();
         }
     }
+
+    @Test
+    public void testXAResourceRecoveryHelperRegistration() {
+
+        XARecoveryModule xaRecoveryModule = new XARecoveryModule();
+        XAResourceRecoveryHelper xaResourceRecoveryHelper = new DummyXAResourceRecoveryHelper();
+
+        xaRecoveryModule.addXAResourceRecoveryHelper(xaResourceRecoveryHelper);
+        xaRecoveryModule.removeXAResourceRecoveryHelper(xaResourceRecoveryHelper);
+    }
+
+    class DummyXAResourceRecoveryHelper implements XAResourceRecoveryHelper {
+        @Override
+        public boolean initialise(String p) throws Exception
+        {
+            return false;  //To change body of implemented methods use File | Settings | File Templates.
+        }
+
+        @Override
+        public XAResource[] getXAResources() throws Exception
+        {
+            return new XAResource[0];  //To change body of implemented methods use File | Settings | File Templates.
+        }
+    }
+
+    @Test
+    public void testXAResourceOrphanFilterRegistration() {
+
+        XARecoveryModule xaRecoveryModule = new XARecoveryModule();
+        XAResourceOrphanFilter xaResourceOrphanFilter = new DummyXAResourceOrphanFilter();
+
+        xaRecoveryModule.addXAResourceOrphanFilter(xaResourceOrphanFilter);
+        xaRecoveryModule.removeXAResourceOrphanFilter(xaResourceOrphanFilter);
+
+    }
+
+    class DummyXAResourceOrphanFilter implements XAResourceOrphanFilter
+    {
+        @Override
+        public Vote checkXid(Xid xid)
+        {
+            return null;  //To change body of implemented methods use File | Settings | File Templates.
+        }
+    }
 }

Added: labs/jbosstm/trunk/ArjunaJTA/jta/tests/classes/com/hp/mwtests/ts/jta/recovery/XAResourceOrphanFilterTest.java
===================================================================
--- labs/jbosstm/trunk/ArjunaJTA/jta/tests/classes/com/hp/mwtests/ts/jta/recovery/XAResourceOrphanFilterTest.java	                        (rev 0)
+++ labs/jbosstm/trunk/ArjunaJTA/jta/tests/classes/com/hp/mwtests/ts/jta/recovery/XAResourceOrphanFilterTest.java	2010-03-04 13:03:00 UTC (rev 31932)
@@ -0,0 +1,90 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and/or its affiliates,
+ * 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) 2010,
+ * @author JBoss, by Red Hat.
+ */
+package com.hp.mwtests.ts.jta.recovery;
+
+import com.arjuna.ats.arjuna.common.Uid;
+import com.arjuna.ats.arjuna.coordinator.TxControl;
+import com.arjuna.ats.internal.jta.recovery.arjunacore.JTANodeNameXAResourceOrphanFilter;
+import com.arjuna.ats.internal.jta.recovery.arjunacore.JTATransactionLogXAResourceOrphanFilter;
+import com.arjuna.ats.jta.common.jtaPropertyManager;
+import com.arjuna.ats.jta.recovery.XAResourceOrphanFilter;
+import com.arjuna.ats.jta.xa.XATxConverter;
+
+import javax.transaction.xa.Xid;
+
+import org.junit.Test;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import static org.junit.Assert.*;
+
+/**
+ * Unit tests for JTA package XAResourceOrphanFilter implementations.
+ *
+ * @author Jonathan Halliday (jonathan.halliday at redhat.com), 2010-03
+ */
+public class XAResourceOrphanFilterTest
+{
+    @Test
+    public void testJTANodeNameXAResourceOrphanFilter()
+    {
+        XAResourceOrphanFilter orphanFilter = new JTANodeNameXAResourceOrphanFilter();
+
+        Xid notJTAFormatId = XATxConverter.getXid(new Uid(), false, 0);
+        assertEquals(XAResourceOrphanFilter.Vote.ABSTAIN, orphanFilter.checkXid(notJTAFormatId));
+
+        List<String> recoveryNodes = new LinkedList<String>();
+        recoveryNodes.add("AA");
+        jtaPropertyManager.getJTAEnvironmentBean().setXaRecoveryNodes(recoveryNodes);
+
+        byte[] notRecoverableNodeName = new byte[] { 'A', 'B' };
+        TxControl.setXANodeName(notRecoverableNodeName);
+        Xid jtaNotRecoverableNodeName = XATxConverter.getXid(new Uid(), false, XATxConverter.FORMAT_ID);
+
+        assertEquals(XAResourceOrphanFilter.Vote.ABSTAIN, orphanFilter.checkXid(jtaNotRecoverableNodeName));
+
+        byte[] recoverableNodeName = new byte[] { 'A', 'A' };
+        TxControl.setXANodeName(recoverableNodeName);
+        Xid jtaRecoverableNodeName = XATxConverter.getXid(new Uid(), false, XATxConverter.FORMAT_ID);
+
+        assertEquals(XAResourceOrphanFilter.Vote.ROLLBACK, orphanFilter.checkXid(jtaRecoverableNodeName));
+
+        recoveryNodes.clear();
+        recoveryNodes.add("*");
+        jtaPropertyManager.getJTAEnvironmentBean().setXaRecoveryNodes(recoveryNodes);
+
+        assertEquals(XAResourceOrphanFilter.Vote.ROLLBACK, orphanFilter.checkXid(jtaNotRecoverableNodeName));
+        assertEquals(XAResourceOrphanFilter.Vote.ROLLBACK, orphanFilter.checkXid(jtaRecoverableNodeName));
+    }
+
+    @Test
+    public void testJTATransactionLogOrphanFilter()
+    {
+        XAResourceOrphanFilter orphanFilter = new JTATransactionLogXAResourceOrphanFilter();
+
+        Xid notJTAFormatId = XATxConverter.getXid(new Uid(), false, 0);
+        assertEquals(XAResourceOrphanFilter.Vote.ABSTAIN, orphanFilter.checkXid(notJTAFormatId));
+
+        Xid jtaFormatId = XATxConverter.getXid(new Uid(), false, XATxConverter.FORMAT_ID);
+        assertEquals(XAResourceOrphanFilter.Vote.ABSTAIN, orphanFilter.checkXid(jtaFormatId));
+    }
+}

Modified: labs/jbosstm/trunk/ArjunaJTS/jbossts-properties-arjunajts.xml
===================================================================
--- labs/jbosstm/trunk/ArjunaJTS/jbossts-properties-arjunajts.xml	2010-03-04 12:05:31 UTC (rev 31931)
+++ labs/jbosstm/trunk/ArjunaJTS/jbossts-properties-arjunajts.xml	2010-03-04 13:03:00 UTC (rev 31932)
@@ -67,6 +67,11 @@
 	<!-- Which Xid types to recover -->
 	<entry key="JTAEnvironmentBean.xaRecoveryNodes">1</entry>
 
+    <entry key="JTAEnvironmentBean.xaResourceOrphanFilters">
+        com.arjuna.ats.internal.jta.recovery.arjunacore.JTATransactionLogXAResourceOrphanFilter
+        com.arjuna.ats.internal.jta.recovery.arjunacore.JTANodeNameXAResourceOrphanFilter
+    </entry>
+
     <!--
       Base port number for determining a unique number to associate with an instance of the transaction service
       (which is needed in order to support multiple instances on the same machine).

Modified: labs/jbosstm/trunk/atsintegration/transaction-jboss-beans.xml
===================================================================
--- labs/jbosstm/trunk/atsintegration/transaction-jboss-beans.xml	2010-03-04 12:05:31 UTC (rev 31931)
+++ labs/jbosstm/trunk/atsintegration/transaction-jboss-beans.xml	2010-03-04 13:03:00 UTC (rev 31932)
@@ -141,6 +141,13 @@
                 <value>1</value>
             </list>
         </property>
+
+        <property name="xaResourceOrphanFilters" preinstantiate="false">
+            <list elementClass="java.lang.String">
+                <value>com.arjuna.ats.internal.jta.recovery.arjunacore.JTATransactionLogXAResourceOrphanFilter</value>
+                <value>com.arjuna.ats.internal.jta.recovery.arjunacore.JTANodeNameXAResourceOrphanFilter</value>
+            </list>
+        </property>
         
     </bean>
 

Modified: labs/jbosstm/trunk/atsintegration/transaction-jboss-beans.xml.jts
===================================================================
--- labs/jbosstm/trunk/atsintegration/transaction-jboss-beans.xml.jts	2010-03-04 12:05:31 UTC (rev 31931)
+++ labs/jbosstm/trunk/atsintegration/transaction-jboss-beans.xml.jts	2010-03-04 13:03:00 UTC (rev 31932)
@@ -147,6 +147,13 @@
             </list>
         </property>
 
+        <property name="xaResourceOrphanFilters" preinstantiate="false">
+            <list elementClass="java.lang.String">
+                <value>com.arjuna.ats.internal.jta.recovery.arjunacore.JTATransactionLogXAResourceOrphanFilter</value>
+                <value>com.arjuna.ats.internal.jta.recovery.arjunacore.JTANodeNameXAResourceOrphanFilter</value>
+            </list>
+        </property>
+
     </bean>
 
     <bean name="RecoveryManager" class="com.arjuna.ats.jbossatx.jts.RecoveryManagerService">



More information about the jboss-svn-commits mailing list