[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