[jboss-svn-commits] JBL Code SVN: r37631 - in labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example: server and 1 other directories.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Thu Oct 20 08:37:52 EDT 2011


Author: tomjenkinson
Date: 2011-10-20 08:37:51 -0400 (Thu, 20 Oct 2011)
New Revision: 37631

Modified:
   labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/ExampleDistributedJTATestCase.java
   labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/TestResource.java
   labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/TestResourceRecovery.java
   labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/TestSynchronization.java
   labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/DummyRemoteException.java
   labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/IsolatableServersClassLoader.java
   labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/LocalServer.java
   labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/LookupProvider.java
   labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/RemoteServer.java
   labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/impl/ProxySynchronization.java
   labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/impl/ProxyXAResource.java
   labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/impl/ProxyXAResourceRecovery.java
   labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/impl/ServerImpl.java
Log:
JBTM-895 added some more documentation for the example

Modified: labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/ExampleDistributedJTATestCase.java
===================================================================
--- labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/ExampleDistributedJTATestCase.java	2011-10-20 10:11:51 UTC (rev 37630)
+++ labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/ExampleDistributedJTATestCase.java	2011-10-20 12:37:51 UTC (rev 37631)
@@ -47,123 +47,266 @@
 import com.arjuna.jta.distributed.example.server.LookupProvider;
 import com.arjuna.jta.distributed.example.server.RemoteServer;
 
+/**
+ * This example shows how to use the JTA in a distributed manner.
+ * 
+ * In this example, LocalServer references should be considered to be activities
+ * that are performed on a local application server.
+ * 
+ * The method propagateTransaction is used to simulate invoking a remote server
+ * and should be considered the socket boundary between servers. If you look
+ * closely what I do to simulate this is use ClassLoaders so that servers dont
+ * share the same address space in the VM and won't therefore interfere with
+ * each other - inspired!
+ * 
+ * Note the use of LocalServer and RemoteServer is just an example, the
+ * transport is responsible for creating objects that perform similar
+ * capabilities to these.
+ */
 public class ExampleDistributedJTATestCase {
+	/**
+	 * This is to simulate JNDI.
+	 */
 	private static LookupProvider lookupProvider = new MyLookupProvider();
+
+	/**
+	 * The example stores a reference to all local servers as a convenience
+	 */
 	private static LocalServer[] localServers = new LocalServer[3];
+
+	/**
+	 * The example stores a reference to all remote servers as a convenience
+	 */
 	private static RemoteServer[] remoteServers = new RemoteServer[3];
 
+	/**
+	 * Initialise references to the local and remote servers.
+	 * 
+	 * @throws SecurityException
+	 * @throws NoSuchMethodException
+	 * @throws InstantiationException
+	 * @throws IllegalAccessException
+	 * @throws ClassNotFoundException
+	 * @throws CoreEnvironmentBeanException
+	 * @throws IOException
+	 * @throws IllegalArgumentException
+	 * @throws NoSuchFieldException
+	 */
 	@BeforeClass
 	public static void setup() throws SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException, ClassNotFoundException,
 			CoreEnvironmentBeanException, IOException, IllegalArgumentException, NoSuchFieldException {
 		for (int i = 0; i < localServers.length; i++) {
+			// Create each instance of a server with its own private
+			// classloader, ensure all access to the local server instance is
+			// done within the scope of this classloader, this is to simulate a
+			// transports different address space
 			ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
 			IsolatableServersClassLoader classLoader = new IsolatableServersClassLoader("com.arjuna.jta.distributed.example.server", contextClassLoader);
 			localServers[i] = (LocalServer) classLoader.loadClass("com.arjuna.jta.distributed.example.server.impl.ServerImpl").newInstance();
 			Thread.currentThread().setContextClassLoader(localServers[i].getClass().getClassLoader());
 			localServers[i].initialise(lookupProvider, (i + 1) * 1000);
+			// This is a short cut, normally remote servers would not be the
+			// same as the local servers and would be a tranport layer
+			// abstraction
 			remoteServers[i] = localServers[i].connectTo();
 			Thread.currentThread().setContextClassLoader(contextClassLoader);
 		}
 	}
 
+	/**
+	 * This example starts a transaction at the local server, it then performs
+	 * the steps required to propagate the transaction to a chain of remote
+	 * servers.
+	 * 
+	 * The nodesToFlowTo is a test abstraction that allows the example to
+	 * simulate conditional business logic that would propagate requests around
+	 * the cluster to access various business logic silos.
+	 * 
+	 * @throws NotSupportedException
+	 * @throws SystemException
+	 * @throws IllegalStateException
+	 * @throws RollbackException
+	 * @throws XAException
+	 * @throws SecurityException
+	 * @throws HeuristicMixedException
+	 * @throws HeuristicRollbackException
+	 * @throws IOException
+	 */
 	@Test
 	public void testMigrateTransaction() throws NotSupportedException, SystemException, IllegalStateException, RollbackException, XAException,
 			SecurityException, HeuristicMixedException, HeuristicRollbackException, IOException {
 
+		// The example does not set a timeout for transactions, we have unit
+		// tests that do
 		int startingTimeout = 0;
-		List<Integer> nodesToFlowTo = new LinkedList<Integer>(Arrays.asList(new Integer[] { 1000, 2000, 3000, 2000, 1000, 2000, 3000, 1000, 3000 }));
 
+		// The list of further nodes to propagate this transaction through
+		// These names are the transport allocated names, they happen to be
+		// string forms of the transaction manager node name but if you follow
+		// the code through you will see they could have been anything
+		List<String> nodesToFlowTo = new LinkedList<String>(Arrays.asList(new String[] { "2000", "3000", "2000", "1000", "2000", "3000", "1000", "3000" }));
+
 		// Start out at the first server
-		int startingServer = nodesToFlowTo.remove(0);
-		LocalServer originalServer = getLocalServer(startingServer);
+		LocalServer originalServer = localServers[0];
+		// Access to this local server must be done by its own classloader to
+		// ensure the servers remain separate
 		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
 		Thread.currentThread().setContextClassLoader(originalServer.getClass().getClassLoader());
+
+		// Get a reference on the transaction manager and create a transaction
 		TransactionManager transactionManager = originalServer.getTransactionManager();
 		transactionManager.setTransactionTimeout(startingTimeout);
 		transactionManager.begin();
 
+		// Do some simulated local work on the TestResource and register a
+		// TestSynchronization
 		Transaction originalTransaction = transactionManager.getTransaction();
 		originalTransaction.registerSynchronization(new TestSynchronization(originalServer.getNodeName()));
 		originalTransaction.enlistResource(new TestResource(originalServer.getNodeName()));
 
+		// This is where we start to propagate the transaction - watch closely
+		// ;)
 		if (!nodesToFlowTo.isEmpty()) {
-			Integer nextServerNodeName = nodesToFlowTo.get(0);
+			// Stash away the root transaction, this is needed in case a
+			// subordinate naughtily comes back to this server part way through
+			// so we can return the original transaction to them
+			originalServer.storeRootTransaction(originalTransaction);
 
-			// FLOW THE TRANSACTION
+			// Peek at the next node - this is just a test abstraction to
+			// simulate where business logic might decide to access an EJB at a
+			// server with a remoting name
+			String nextServerNodeName = nodesToFlowTo.get(0);
+
+			// Check the remaining timeout
 			int remainingTimeout = (int) (((TransactionTimeoutConfiguration) transactionManager).getTimeLeftBeforeTransactionTimeout(false) / 1000);
-
-			// SUSPEND THE TRANSACTION
+			// Get the Xid to propagate
 			Xid currentXid = originalServer.getCurrentXid();
-			originalServer.storeRootTransaction();
+			// Generate a ProxyXAresource, this is transport specific but it
+			// should at least have stored the currentXid in a temporary
+			// location or the name of the remote server so that we can recover
+			// orphan subordinate transactions
 			XAResource proxyXAResource = originalServer.generateProxyXAResource(lookupProvider, nextServerNodeName);
+			// Suspend the transaction locally
 			transactionManager.suspend();
-			performTransactionalWork(nodesToFlowTo, remainingTimeout, currentXid);
+
+			// WE CAN NOW PROPAGATE THE TRANSACTION
+			propagateTransaction(nodesToFlowTo, remainingTimeout, currentXid);
+
+			// After the call retuns, resume the local transaction
 			transactionManager.resume(originalTransaction);
-
+			// Enlist the proxy XA resource with the local transaction so that
+			// it can propagate the transaction completion events to the
+			// subordinate
 			originalTransaction.enlistResource(proxyXAResource);
-			originalTransaction.registerSynchronization(originalServer.generateProxySynchronization(lookupProvider, originalServer.getNodeName(),
-					nextServerNodeName, currentXid));
+			// Register a synchronization that can proxy the beforeCompletion
+			// event to the remote side, after completion events are the
+			// responsibility of the remote server to initiate
+			originalTransaction.registerSynchronization(originalServer.generateProxySynchronization(lookupProvider, nextServerNodeName, currentXid));
 
+			// Deference the local copy of the current transaction so the GC can
+			// free it
 			originalServer.removeRootTransaction(currentXid);
 		}
+		// Commit the local transaction!
+		// This should propagate to the nodes required!
 		transactionManager.commit();
+		// Reset the test classloader
 		Thread.currentThread().setContextClassLoader(classLoader);
 	}
 
-	private boolean performTransactionalWork(List<Integer> nodesToFlowTo, int remainingTimeout, Xid toMigrate) throws RollbackException, IllegalStateException,
+	/**
+	 * This work is simulated to be performed in a remote server.
+	 * 
+	 * @param nodesToFlowTo
+	 * @param remainingTimeout
+	 * @param toMigrate
+	 * @return
+	 * @throws RollbackException
+	 * @throws IllegalStateException
+	 * @throws XAException
+	 * @throws SystemException
+	 * @throws NotSupportedException
+	 * @throws IOException
+	 */
+	private boolean propagateTransaction(List<String> nodesToFlowTo, int remainingTimeout, Xid toMigrate) throws RollbackException, IllegalStateException,
 			XAException, SystemException, NotSupportedException, IOException {
-		Integer currentServerName = nodesToFlowTo.remove(0);
-		LocalServer currentServer = getLocalServer(currentServerName);
-
+		// Do some test setup to initialize this method as it if was being
+		// invoked in a remote server
+		String currentServerName = nodesToFlowTo.remove(0);
+		// Do some work to convert the remote server name to an index against
+		// the cache of local servers - clearly IRL this is not required as we
+		// are at the server :)
+		int index = (Integer.valueOf(currentServerName) / 1000) - 1;
+		LocalServer currentServer = localServers[index];
 		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
 		Thread.currentThread().setContextClassLoader(currentServer.getClass().getClassLoader());
 
+		// Check if this server has seen this transaction before - this is
+		// crucial to ensure that calling servers will only lay down a proxy if
+		// they are the first visitor to this server.
 		boolean requiresProxyAtPreviousServer = !currentServer.getAndResumeTransaction(remainingTimeout, toMigrate);
 		// Perform work on the migrated transaction
 		TransactionManager transactionManager = currentServer.getTransactionManager();
 		Transaction transaction = transactionManager.getTransaction();
+		// Do some simple work on local dummy resources and synchronizations
 		transaction.registerSynchronization(new TestSynchronization(currentServer.getNodeName()));
 		transaction.enlistResource(new TestResource(currentServer.getNodeName()));
 
+		// If there are any more nodes to simulate a flow to
 		if (!nodesToFlowTo.isEmpty()) {
-			Integer nextServerNodeName = nodesToFlowTo.get(0);
+			// Get the transport specific representation of the remote server
+			// name
+			String nextServerNodeName = nodesToFlowTo.get(0);
 
-			// FLOW THE TRANSACTION
+			// Determine the remaining timeout to propagate
 			remainingTimeout = (int) (((TransactionTimeoutConfiguration) transactionManager).getTimeLeftBeforeTransactionTimeout(false) / 1000);
-
-			// SUSPEND THE TRANSACTION
+			// Get the XID to propagate
 			Xid currentXid = currentServer.getCurrentXid();
+			// Generate the proxy (which saves a temporary copy of the XID in
+			// case the remote server was to be orphaned, this could just save a
+			// proxy that knows to contact the remote server but then it will
+			// force rollbacks on recovery - not ideal)
 			XAResource proxyXAResource = currentServer.generateProxyXAResource(lookupProvider, nextServerNodeName);
+			// Suspend the transaction ready for propagation
 			transactionManager.suspend();
-			boolean proxyRequired = performTransactionalWork(nodesToFlowTo, remainingTimeout, currentXid);
+			// Propagate the transaction - in the example I return a boolean to
+			// indicate whether this caller is the first client to establish the
+			// subordinate transaction at the remote node
+			boolean proxyRequired = propagateTransaction(nodesToFlowTo, remainingTimeout, currentXid);
+			// Resume the transaction locally, ready for any more local work and
+			// to add the proxy resource and sync if needed
 			transactionManager.resume(transaction);
-
+			// If this caller was the first entity to propagate the transaction
+			// to the remote server
 			if (proxyRequired) {
+				// Formally enlist the resource
 				transaction.enlistResource(proxyXAResource);
-				transaction.registerSynchronization(currentServer.generateProxySynchronization(lookupProvider, currentServer.getNodeName(), nextServerNodeName,
-						toMigrate));
+				// Register a sync
+				transaction.registerSynchronization(currentServer.generateProxySynchronization(lookupProvider, nextServerNodeName, toMigrate));
 			} else {
+				// This will discard the state of this resource, i.e. the file
+				// containing the temporary unprepared XID
 				currentServer.cleanupProxyXAResource(proxyXAResource);
 			}
 		}
 
 		// SUSPEND THE TRANSACTION WHEN YOU ARE READY TO RETURN TO YOUR CALLER
 		transactionManager.suspend();
-
+		// Return to the previous caller back over the transport/classloader
+		// boundary in this case
 		Thread.currentThread().setContextClassLoader(classLoader);
 		return requiresProxyAtPreviousServer;
 	}
 
-	private static LocalServer getLocalServer(Integer jndiName) {
-		int index = (jndiName / 1000) - 1;
-		return localServers[index];
-	}
-
+	/**
+	 * A simple class that simulates JNDI to lookup references to remote servers
+	 * for this in memory transport.
+	 */
 	private static class MyLookupProvider implements LookupProvider {
 
 		@Override
-		public RemoteServer lookup(Integer jndiName) {
-			int index = (jndiName / 1000) - 1;
+		public RemoteServer lookup(String jndiName) {
+			int index = (new Integer(jndiName) / 1000) - 1;
 			return remoteServers[index];
 		}
 

Modified: labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/TestResource.java
===================================================================
--- labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/TestResource.java	2011-10-20 10:11:51 UTC (rev 37630)
+++ labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/TestResource.java	2011-10-20 12:37:51 UTC (rev 37631)
@@ -35,6 +35,10 @@
 
 import com.arjuna.ats.arjuna.common.Uid;
 
+/**
+ * This is a simple TestResource, any knowledge it has of the rest of the
+ * example is purely for debugging. It should be considered a black box.
+ */
 public class TestResource implements XAResource {
 	private Xid xid;
 
@@ -42,14 +46,14 @@
 
 	private File file;
 
-	private int serverId;
+	private Integer localServerName;
 
-	public TestResource(int serverId) {
-		this.serverId = serverId;
+	public TestResource(Integer localServerName) {
+		this.localServerName = localServerName;
 	}
 
-	public TestResource(int serverId, File file) throws IOException {
-		this.serverId = serverId;
+	public TestResource(Integer localServerName, File file) throws IOException {
+		this.localServerName = localServerName;
 		this.file = file;
 		DataInputStream fis = new DataInputStream(new FileInputStream(file));
 		final int formatId = fis.readInt();
@@ -79,9 +83,9 @@
 	}
 
 	public synchronized int prepare(Xid xid) throws XAException {
-		System.out.println("        TestResource (" + serverId + ")      XA_PREPARE [" + xid + "]");
+		System.out.println("        TestResource (" + localServerName + ")      XA_PREPARE [" + xid + "]");
 
-		File dir = new File(System.getProperty("user.dir") + "/distributedjta-example/TestResource/" + serverId + "/");
+		File dir = new File(System.getProperty("user.dir") + "/distributedjta-example/TestResource/" + localServerName + "/");
 		dir.mkdirs();
 		file = new File(dir, new Uid().fileStringForm() + "_");
 		try {
@@ -108,7 +112,7 @@
 	}
 
 	public synchronized void commit(Xid id, boolean onePhase) throws XAException {
-		System.out.println("        TestResource (" + serverId + ")      XA_COMMIT  [" + id + "]");
+		System.out.println("        TestResource (" + localServerName + ")      XA_COMMIT  [" + id + "]");
 		if (file != null) {
 			// String absoluteFile = file.getAbsolutePath();
 			// String newName = absoluteFile.substring(0, absoluteFile.length()
@@ -122,7 +126,7 @@
 	}
 
 	public synchronized void rollback(Xid xid) throws XAException {
-		System.out.println("        TestResource (" + serverId + ")      XA_ROLLBACK[" + xid + "]");
+		System.out.println("        TestResource (" + localServerName + ")      XA_ROLLBACK[" + xid + "]");
 		if (file != null) {
 			file.delete();
 		}
@@ -130,11 +134,11 @@
 	}
 
 	public void end(Xid xid, int flags) throws XAException {
-		System.out.println("        TestResource (" + serverId + ")      XA_END     [" + xid + "] Flags=" + flags);
+		System.out.println("        TestResource (" + localServerName + ")      XA_END     [" + xid + "] Flags=" + flags);
 	}
 
 	public void forget(Xid xid) throws XAException {
-		System.out.println("        TestResource (" + serverId + ")      XA_FORGET[" + xid + "]");
+		System.out.println("        TestResource (" + localServerName + ")      XA_FORGET[" + xid + "]");
 	}
 
 	public int getTransactionTimeout() throws XAException {
@@ -160,16 +164,16 @@
 	public Xid[] recover(int flag) throws XAException {
 		Xid[] toReturn = null;
 		if ((flag & XAResource.TMSTARTRSCAN) == XAResource.TMSTARTRSCAN) {
-			System.out.println("        TestResource (" + serverId + ")      RECOVER[XAResource.TMSTARTRSCAN]: " + serverId);
+			System.out.println("        TestResource (" + localServerName + ")      RECOVER[XAResource.TMSTARTRSCAN]: " + localServerName);
 			if (xid != null) {
 				toReturn = new Xid[] { xid };
 			}
 		}
 		if ((flag & XAResource.TMENDRSCAN) == XAResource.TMENDRSCAN) {
-			System.out.println("        TestResource (" + serverId + ")      RECOVER[XAResource.TMENDRSCAN]: " + serverId);
+			System.out.println("        TestResource (" + localServerName + ")      RECOVER[XAResource.TMENDRSCAN]: " + localServerName);
 		}
 		if (flag == XAResource.TMNOFLAGS) {
-			System.out.println("        TestResource (" + serverId + ")      RECOVER[XAResource.TMENDRSCAN]: " + serverId);
+			System.out.println("        TestResource (" + localServerName + ")      RECOVER[XAResource.TMENDRSCAN]: " + localServerName);
 		}
 		return toReturn;
 	}
@@ -180,6 +184,6 @@
 	}
 
 	public void start(Xid xid, int flags) throws XAException {
-		System.out.println("        TestResource (" + serverId + ")      XA_START   [" + xid + "] Flags=" + flags);
+		System.out.println("        TestResource (" + localServerName + ")      XA_START   [" + xid + "] Flags=" + flags);
 	}
 }

Modified: labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/TestResourceRecovery.java
===================================================================
--- labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/TestResourceRecovery.java	2011-10-20 10:11:51 UTC (rev 37630)
+++ labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/TestResourceRecovery.java	2011-10-20 12:37:51 UTC (rev 37631)
@@ -30,6 +30,11 @@
 
 import org.jboss.tm.XAResourceRecovery;
 
+/**
+ * This is a simple TestResource XAResourceRecovery helper, any knowledge it has
+ * of the rest of the example is purely for debugging. It should be considered a
+ * black box.
+ */
 public class TestResourceRecovery implements XAResourceRecovery {
 
 	private List<TestResource> resources = new ArrayList<TestResource>();

Modified: labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/TestSynchronization.java
===================================================================
--- labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/TestSynchronization.java	2011-10-20 10:11:51 UTC (rev 37630)
+++ labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/TestSynchronization.java	2011-10-20 12:37:51 UTC (rev 37631)
@@ -23,20 +23,25 @@
 
 import javax.transaction.Synchronization;
 
+/**
+ * This is a simple Synchronization, any knowledge (such as the server name) it
+ * has of the rest of the example is purely for debugging. It should be
+ * considered a black box.
+ */
 public class TestSynchronization implements Synchronization {
-	private int serverId;
+	private int localServerName;
 
-	public TestSynchronization(int serverId) {
-		this.serverId = serverId;
+	public TestSynchronization(Integer localServerName) {
+		this.localServerName = localServerName;
 	}
 
 	@Override
 	public void beforeCompletion() {
-		System.out.println(" TestSynchronization (" + serverId + ")      beforeCompletion");
+		System.out.println(" TestSynchronization (" + localServerName + ")      beforeCompletion");
 	}
 
 	@Override
 	public void afterCompletion(int status) {
-		System.out.println(" TestSynchronization (" + serverId + ")      afterCompletion");
+		System.out.println(" TestSynchronization (" + localServerName + ")      afterCompletion");
 	}
 }

Modified: labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/DummyRemoteException.java
===================================================================
--- labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/DummyRemoteException.java	2011-10-20 10:11:51 UTC (rev 37630)
+++ labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/DummyRemoteException.java	2011-10-20 12:37:51 UTC (rev 37631)
@@ -21,8 +21,9 @@
  */
 package com.arjuna.jta.distributed.example.server;
 
+/**
+ * This is a dummy exception - it is not used in the example but is to reinforce
+ * the idea that this example can be considered a simulation of a transport.
+ */
 public class DummyRemoteException extends Exception {
-	public DummyRemoteException(String message) {
-		super(message);
-	}
 }

Modified: labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/IsolatableServersClassLoader.java
===================================================================
--- labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/IsolatableServersClassLoader.java	2011-10-20 10:11:51 UTC (rev 37630)
+++ labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/IsolatableServersClassLoader.java	2011-10-20 12:37:51 UTC (rev 37631)
@@ -30,12 +30,29 @@
 import sun.misc.Resource;
 import sun.misc.URLClassPath;
 
+/**
+ * This classloader will reload copies of classes (except a package that is
+ * configured for ignoring - the interfaces that the root example requires
+ * basically).
+ */
 public class IsolatableServersClassLoader extends ClassLoader {
 
 	private Map<String, Class<?>> clazzMap = new HashMap<String, Class<?>>();
 	private URLClassPath ucp;
 	private String ignoredPackage;
 
+	/**
+	 * Create the classloader.
+	 * 
+	 * @param ignoredPackage
+	 *            This package will be ignored by this classloader and delegated
+	 *            to its parent so that the example testcase can access required
+	 *            interfaces of its test.
+	 * @param parent
+	 * @throws SecurityException
+	 * @throws NoSuchMethodException
+	 * @throws MalformedURLException
+	 */
 	public IsolatableServersClassLoader(String ignoredPackage, ClassLoader parent) throws SecurityException, NoSuchMethodException, MalformedURLException {
 		super(parent);
 		this.ignoredPackage = ignoredPackage;

Modified: labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/LocalServer.java
===================================================================
--- labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/LocalServer.java	2011-10-20 10:11:51 UTC (rev 37630)
+++ labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/LocalServer.java	2011-10-20 12:37:51 UTC (rev 37631)
@@ -21,13 +21,13 @@
  */
 package com.arjuna.jta.distributed.example.server;
 
-import java.io.File;
 import java.io.IOException;
 
 import javax.transaction.InvalidTransactionException;
 import javax.transaction.NotSupportedException;
 import javax.transaction.Synchronization;
 import javax.transaction.SystemException;
+import javax.transaction.Transaction;
 import javax.transaction.TransactionManager;
 import javax.transaction.xa.XAException;
 import javax.transaction.xa.XAResource;
@@ -35,29 +35,117 @@
 
 import com.arjuna.ats.arjuna.common.CoreEnvironmentBeanException;
 
+/**
+ * This is the local interface of the server, operations invoked here should be
+ * considered to be called on local objects. The are sat behind this interface
+ * though in order to allow multiple copies of a server to be loaded into
+ * memory.
+ */
 public interface LocalServer {
 
+	/**
+	 * Initialize this server, this will create a transaction manager service
+	 * and a recovery manager service.
+	 * 
+	 * @param lookupProvider
+	 * @param nodeName
+	 * @throws CoreEnvironmentBeanException
+	 * @throws IOException
+	 * @throws SecurityException
+	 * @throws NoSuchFieldException
+	 * @throws IllegalArgumentException
+	 * @throws IllegalAccessException
+	 */
 	public void initialise(LookupProvider lookupProvider, Integer nodeName) throws CoreEnvironmentBeanException, IOException, SecurityException,
 			NoSuchFieldException, IllegalArgumentException, IllegalAccessException;
 
+	/**
+	 * Get the local transaction managers node name.
+	 */
 	public Integer getNodeName();
 
+	/**
+	 * Get a reference on the local transaction manager.
+	 * 
+	 * @return
+	 * @throws NotSupportedException
+	 * @throws SystemException
+	 */
 	public TransactionManager getTransactionManager() throws NotSupportedException, SystemException;
 
-	public void storeRootTransaction() throws SystemException;
+	/**
+	 * Store the current transaction, this is so if a subordinate comes back
+	 * here we have a hashmap to locate the transaction in.
+	 * 
+	 * @throws SystemException
+	 */
+	public void storeRootTransaction(Transaction transaction) throws SystemException;
 
+	/**
+	 * Remove the parent transaction from the local cache. It is indexed on XID.
+	 * 
+	 * @param toMigrate
+	 */
 	public void removeRootTransaction(Xid toMigrate);
 
+	/**
+	 * Either create or locate a subordinate (or root) transaction for a given
+	 * Xid.
+	 * 
+	 * @param remainingTimeout
+	 * @param toImport
+	 * @return
+	 * @throws XAException
+	 * @throws InvalidTransactionException
+	 * @throws IllegalStateException
+	 * @throws SystemException
+	 */
 	public boolean getAndResumeTransaction(int remainingTimeout, Xid toImport) throws XAException, InvalidTransactionException, IllegalStateException,
 			SystemException;
 
-	public RemoteServer connectTo();
+	/**
+	 * Transport specific function to generate a proxy for a remote server.
+	 * 
+	 * @param lookupProvider
+	 * @param remoteServerName
+	 * @return
+	 * @throws IOException
+	 * @throws SystemException
+	 */
+	public XAResource generateProxyXAResource(LookupProvider lookupProvider, String remoteServerName) throws IOException, SystemException;
 
-	public XAResource generateProxyXAResource(LookupProvider lookupProvider, Integer remoteServerName) throws IOException, SystemException;
-
+	/**
+	 * Discard the proxy if it turns out the remote server was already part of
+	 * the transaction
+	 * 
+	 * @param proxyXAResource
+	 */
 	public void cleanupProxyXAResource(XAResource proxyXAResource);
 
-	public Synchronization generateProxySynchronization(LookupProvider lookupProvider, Integer localServerName, Integer remoteServerName, Xid toRegisterAgainst);
+	/**
+	 * Generate a proxy synchronization
+	 * 
+	 * @param lookupProvider
+	 * @param remoteServerName
+	 * @param toRegisterAgainst
+	 * @return
+	 */
+	public Synchronization generateProxySynchronization(LookupProvider lookupProvider, String remoteServerName, Xid toRegisterAgainst);
 
+	/**
+	 * Get the current Xid - this is what will be propagated to the remote
+	 * servers.
+	 * 
+	 * @return
+	 * @throws SystemException
+	 */
 	public Xid getCurrentXid() throws SystemException;
+
+	/**
+	 * Test code to create a reference of this server as a remote endpoint for
+	 * other servers to communicate with.
+	 * 
+	 * @return
+	 */
+	public RemoteServer connectTo();
 }

Modified: labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/LookupProvider.java
===================================================================
--- labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/LookupProvider.java	2011-10-20 10:11:51 UTC (rev 37630)
+++ labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/LookupProvider.java	2011-10-20 12:37:51 UTC (rev 37631)
@@ -21,6 +21,9 @@
  */
 package com.arjuna.jta.distributed.example.server;
 
+/**
+ * Simulates a simple JNDI inorder to resolve remote servers.
+ */
 public interface LookupProvider {
-	public RemoteServer lookup(Integer jndiName);
+	public RemoteServer lookup(String remotingNodeName);
 }

Modified: labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/RemoteServer.java
===================================================================
--- labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/RemoteServer.java	2011-10-20 10:11:51 UTC (rev 37630)
+++ labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/RemoteServer.java	2011-10-20 12:37:51 UTC (rev 37631)
@@ -25,18 +25,79 @@
 import javax.transaction.xa.XAException;
 import javax.transaction.xa.Xid;
 
+/**
+ * This interface is to simulate most remote calls to a server (except where
+ * classloader separation is used in
+ * <class>ExampelDistributedJTATestCase</class>
+ * 
+ * Most of the calls are fairly innocuous, however two need special explanation.
+ * 
+ * Firstly the before completion takes an XID, check out
+ * <class>ProxySynchronization</class> for more details on that.
+ * 
+ * More interesting is the propagate recover call - see it's Javadoc for
+ * details.
+ */
 public interface RemoteServer {
 
+	/**
+	 * Atypical for a recover call we need to pass over the node name of the
+	 * caller. This will ensure that all Xids for the caller coordinated
+	 * Subordinates are returned.
+	 * 
+	 * @param callingServerNodeName
+	 * @return
+	 * @throws XAException
+	 * @throws DummyRemoteException
+	 */
+	public Xid[] propagateRecover(Integer callingServerNodeName) throws XAException, DummyRemoteException;
+
+	/**
+	 * Relay the propagate completion.
+	 * 
+	 * @param xid
+	 * @throws XAException
+	 * @throws SystemException
+	 * @throws DummyRemoteException
+	 */
+	public void propagateBeforeCompletion(Xid xid) throws XAException, SystemException, DummyRemoteException;
+
+	/**
+	 * Relay a prepare to the remote side for a specific Xid.
+	 * 
+	 * @param xid
+	 * @return
+	 * @throws XAException
+	 * @throws DummyRemoteException
+	 */
 	public int propagatePrepare(Xid xid) throws XAException, DummyRemoteException;
 
+	/**
+	 * Relay the commit.
+	 * 
+	 * @param xid
+	 * @param onePhase
+	 * @throws XAException
+	 * @throws DummyRemoteException
+	 */
 	public void propagateCommit(Xid xid, boolean onePhase) throws XAException, DummyRemoteException;
 
+	/**
+	 * Relay the rollback
+	 * 
+	 * @param xid
+	 * @throws XAException
+	 * @throws DummyRemoteException
+	 */
 	public void propagateRollback(Xid xid) throws XAException, DummyRemoteException;
 
-	public Xid[] propagateRecover(Integer nodeName) throws XAException, DummyRemoteException;
-
+	/**
+	 * Relay the forget.
+	 * 
+	 * @param xid
+	 * @throws XAException
+	 * @throws DummyRemoteException
+	 */
 	public void propagateForget(Xid xid) throws XAException, DummyRemoteException;
 
-	public void propagateBeforeCompletion(Xid xid) throws XAException, SystemException, DummyRemoteException;
-
 }

Modified: labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/impl/ProxySynchronization.java
===================================================================
--- labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/impl/ProxySynchronization.java	2011-10-20 10:11:51 UTC (rev 37630)
+++ labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/impl/ProxySynchronization.java	2011-10-20 12:37:51 UTC (rev 37631)
@@ -29,14 +29,19 @@
 import com.arjuna.jta.distributed.example.server.DummyRemoteException;
 import com.arjuna.jta.distributed.example.server.LookupProvider;
 
+/**
+ * Proxy the before completion call to the remote servers. Unusual for a
+ * synchronization it must be created with a reference to an Xid in order to be
+ * able to propate this information to a remote server.
+ */
 public class ProxySynchronization implements Synchronization {
 
 	private int localServerName;
-	private int remoteServerName;
+	private String remoteServerName;
 	private Xid toRegisterAgainst;
 	private LookupProvider lookupProvider;
 
-	public ProxySynchronization(LookupProvider lookupProvider, int localServerName, int remoteServerName, Xid toRegisterAgainst) {
+	public ProxySynchronization(LookupProvider lookupProvider, Integer localServerName, String remoteServerName, Xid toRegisterAgainst) {
 		this.lookupProvider = lookupProvider;
 		this.localServerName = localServerName;
 		this.remoteServerName = remoteServerName;

Modified: labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/impl/ProxyXAResource.java
===================================================================
--- labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/impl/ProxyXAResource.java	2011-10-20 10:11:51 UTC (rev 37630)
+++ labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/impl/ProxyXAResource.java	2011-10-20 12:37:51 UTC (rev 37631)
@@ -36,20 +36,18 @@
 import javax.transaction.xa.XAResource;
 import javax.transaction.xa.Xid;
 
-import org.jboss.tm.XAResourceWrapper;
-
 import com.arjuna.ats.arjuna.common.Uid;
 import com.arjuna.jta.distributed.example.server.DummyRemoteException;
 import com.arjuna.jta.distributed.example.server.LookupProvider;
 
 /**
- * I chose for this class to implement XAResourceWrapper so that I can provide a
- * name to the Transaction manager for it to store in its XID.
+ * The XA resource that the transport must provide inorder to proxy directives
+ * from the root transaction coordinator.
  */
-public class ProxyXAResource implements XAResource, XAResourceWrapper {
+public class ProxyXAResource implements XAResource {
 
 	private int transactionTimeout;
-	private Integer remoteServerName = -1;
+	private String remoteServerName = null;
 	private Map<Xid, File> map;
 	private Integer localServerName;
 	private LookupProvider lookupProvider;
@@ -62,7 +60,7 @@
 	 * @param localServerName
 	 * @param remoteServerName
 	 */
-	public ProxyXAResource(LookupProvider lookupProvider, Integer localServerName, Integer remoteServerName, File file) {
+	public ProxyXAResource(LookupProvider lookupProvider, Integer localServerName, String remoteServerName, File file) {
 		this.lookupProvider = lookupProvider;
 		this.localServerName = localServerName;
 		this.remoteServerName = remoteServerName;
@@ -80,7 +78,7 @@
 	 * @param file
 	 * @throws IOException
 	 */
-	public ProxyXAResource(LookupProvider lookupProvider, Integer localServerName, Integer remoteServerName, Map<Xid, File> map) throws IOException {
+	public ProxyXAResource(LookupProvider lookupProvider, Integer localServerName, String remoteServerName, Map<Xid, File> map) throws IOException {
 		this.lookupProvider = lookupProvider;
 		this.localServerName = localServerName;
 		this.remoteServerName = remoteServerName;
@@ -126,7 +124,9 @@
 			File file = new File(dir, new Uid().fileStringForm());
 			file.createNewFile();
 			DataOutputStream fos = new DataOutputStream(new FileOutputStream(file));
-			fos.writeInt(remoteServerName);
+
+			fos.writeInt(remoteServerName.length());
+			fos.writeBytes(remoteServerName);
 			fos.writeInt(xid.getFormatId());
 			fos.writeInt(xid.getGlobalTransactionId().length);
 			fos.write(xid.getGlobalTransactionId());
@@ -306,37 +306,4 @@
 		}
 		return toReturn;
 	}
-
-	/**
-	 * Not used by the TM.
-	 */
-	@Override
-	public XAResource getResource() {
-		return null;
-	}
-
-	/**
-	 * Not used by the TM.
-	 */
-	@Override
-	public String getProductName() {
-		return null;
-	}
-
-	/**
-	 * Not used by the TM.
-	 */
-	@Override
-	public String getProductVersion() {
-		return null;
-	}
-
-	/**
-	 * This allows the proxy to contain meaningful information in the XID in
-	 * case of failure to recover.
-	 */
-	@Override
-	public String getJndiName() {
-		return "ProxyXAResource: " + localServerName + " " + remoteServerName;
-	}
 }
\ No newline at end of file

Modified: labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/impl/ProxyXAResourceRecovery.java
===================================================================
--- labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/impl/ProxyXAResourceRecovery.java	2011-10-20 10:11:51 UTC (rev 37630)
+++ labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/impl/ProxyXAResourceRecovery.java	2011-10-20 12:37:51 UTC (rev 37631)
@@ -45,13 +45,16 @@
 
 	public ProxyXAResourceRecovery(LookupProvider lookupProvider, Integer id) throws IOException {
 		File directory = new File(System.getProperty("user.dir") + "/distributedjta/ProxyXAResource/" + id + "/");
-		Map<Integer, Map<Xid, File>> savedData = new HashMap<Integer, Map<Xid, File>>();
+		Map<String, Map<Xid, File>> savedData = new HashMap<String, Map<Xid, File>>();
 		if (directory.exists() && directory.isDirectory()) {
 			File[] listFiles = directory.listFiles();
 			for (int i = 0; i < listFiles.length; i++) {
 				File file = listFiles[i];
 				DataInputStream fis = new DataInputStream(new FileInputStream(file));
-				int remoteServerName = fis.readInt();
+				int read = fis.read();
+				byte[] nameB = new byte[read];
+				fis.read(nameB, 0, read);
+				String remoteServerName = new String(nameB);
 
 				Map<Xid, File> map = savedData.get(remoteServerName);
 				if (map == null) {
@@ -85,9 +88,9 @@
 				map.put(xid, file);
 			}
 		}
-		Iterator<Integer> iterator = savedData.keySet().iterator();
+		Iterator<String> iterator = savedData.keySet().iterator();
 		while (iterator.hasNext()) {
-			Integer remoteServerName = iterator.next();
+			String remoteServerName = iterator.next();
 			Map<Xid, File> map = savedData.get(remoteServerName);
 			resources.add(new ProxyXAResource(lookupProvider, id, remoteServerName, map));
 		}

Modified: labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/impl/ServerImpl.java
===================================================================
--- labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/impl/ServerImpl.java	2011-10-20 10:11:51 UTC (rev 37630)
+++ labs/jbosstm/branches/JBOSSTS_4_15_0_Final/atsintegration/examples/classes/com/arjuna/jta/distributed/example/server/impl/ServerImpl.java	2011-10-20 12:37:51 UTC (rev 37631)
@@ -182,10 +182,10 @@
 	}
 
 	@Override
-	public void storeRootTransaction() throws SystemException {
-		TransactionImple transaction = ((TransactionImple) transactionManagerService.getTransactionManager().getTransaction());
-		Xid txId = transaction.getTxId();
-		transactions.put(new SubordinateXidImple(txId), transaction);
+	public void storeRootTransaction(Transaction transaction) throws SystemException {
+		TransactionImple transactionI = ((TransactionImple) transaction);
+		Xid txId = transactionI.getTxId();
+		transactions.put(new SubordinateXidImple(txId), transactionI);
 	}
 
 	@Override
@@ -200,24 +200,25 @@
 	}
 
 	@Override
-	public ProxyXAResource generateProxyXAResource(LookupProvider lookupProvider, Integer remoteServerName) throws IOException, SystemException {
+	public ProxyXAResource generateProxyXAResource(LookupProvider lookupProvider, String remoteServerName) throws IOException, SystemException {
 		// Persist a proxy for the remote server this can mean we try to recover
 		// transactions at a remote server that did not get chance to
 		// prepare but the alternative is to orphan a prepared server
 
 		Xid currentXid = getCurrentXid();
-		File dir = new File(System.getProperty("user.dir") + "/distributedjta/ProxyXAResource/" + getNodeName());
+		File dir = new File(System.getProperty("user.dir") + "/distributedjta/ProxyXAResource/" + nodeName);
 		dir.mkdirs();
 		File file = new File(dir, new Uid().fileStringForm());
 		file.createNewFile();
 		DataOutputStream fos = new DataOutputStream(new FileOutputStream(file));
-		fos.writeInt(remoteServerName);
+		fos.writeInt(remoteServerName.length());
+		fos.writeBytes(remoteServerName);
 		fos.writeInt(currentXid.getFormatId());
 		fos.writeInt(currentXid.getGlobalTransactionId().length);
 		fos.write(currentXid.getGlobalTransactionId());
 		fos.writeInt(currentXid.getBranchQualifier().length);
 		fos.write(currentXid.getBranchQualifier());
-		
+
 		return new ProxyXAResource(lookupProvider, nodeName, remoteServerName, file);
 	}
 
@@ -227,8 +228,8 @@
 	}
 
 	@Override
-	public Synchronization generateProxySynchronization(LookupProvider lookupProvider, Integer localServerName, Integer remoteServerName, Xid toRegisterAgainst) {
-		return new ProxySynchronization(lookupProvider, localServerName, remoteServerName, toRegisterAgainst);
+	public Synchronization generateProxySynchronization(LookupProvider lookupProvider, String remoteServerName, Xid toRegisterAgainst) {
+		return new ProxySynchronization(lookupProvider, nodeName, remoteServerName, toRegisterAgainst);
 	}
 
 	@Override



More information about the jboss-svn-commits mailing list