Return-Path: Delivered-To: apmail-incubator-geronimo-cvs-archive@www.apache.org Received: (qmail 17134 invoked from network); 29 Sep 2003 00:32:44 -0000 Received: from daedalus.apache.org (HELO mail.apache.org) (208.185.179.12) by minotaur-2.apache.org with SMTP; 29 Sep 2003 00:32:44 -0000 Received: (qmail 77651 invoked by uid 500); 29 Sep 2003 00:32:25 -0000 Delivered-To: apmail-incubator-geronimo-cvs-archive@incubator.apache.org Received: (qmail 77623 invoked by uid 500); 29 Sep 2003 00:32:25 -0000 Mailing-List: contact geronimo-cvs-help@incubator.apache.org; run by ezmlm Precedence: bulk list-help: list-unsubscribe: list-post: Reply-To: geronimo-dev@incubator.apache.org Delivered-To: mailing list geronimo-cvs@incubator.apache.org Received: (qmail 77610 invoked from network); 29 Sep 2003 00:32:25 -0000 Received: from unknown (HELO minotaur.apache.org) (209.237.227.194) by daedalus.apache.org with SMTP; 29 Sep 2003 00:32:25 -0000 Received: (qmail 17102 invoked by uid 1716); 29 Sep 2003 00:32:40 -0000 Date: 29 Sep 2003 00:32:40 -0000 Message-ID: <20030929003240.17101.qmail@minotaur.apache.org> From: jboynes@apache.org To: incubator-geronimo-cvs@apache.org Subject: cvs commit: incubator-geronimo/modules/core/src/test/org/apache/geronimo/transaction/manager MockResource.java MockResourceManager.java TestTransactionManager.java X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N X-Spam-Rating: minotaur-2.apache.org 1.6.2 0/1000/N jboynes 2003/09/28 17:32:40 Added: modules/core/src/java/org/apache/geronimo/transaction/log UnrecoverableLog.java modules/core/src/java/org/apache/geronimo/transaction/manager TransactionImpl.java TransactionLog.java TransactionManagerImpl.java XidFactory.java XidImpl.java modules/core/src/test/org/apache/geronimo/transaction/manager MockResource.java MockResourceManager.java TestTransactionManager.java Log: Simple impl of JTA TransactionManager Revision Changes Path 1.1 incubator-geronimo/modules/core/src/java/org/apache/geronimo/transaction/log/UnrecoverableLog.java Index: UnrecoverableLog.java =================================================================== /* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" and * "Apache Geronimo" must not be used to endorse or promote products * derived from this software without prior written permission. For * written permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * "Apache Geronimo", nor may "Apache" appear in their name, without * prior written permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . * * ==================================================================== */ package org.apache.geronimo.transaction.log; import java.io.IOException; import javax.transaction.xa.Xid; import org.apache.geronimo.transaction.manager.TransactionLog; /** * A log sink that doesn't actually do anything. * Not recommended for production use as heuristic recovery will be needed if * the transaction coordinator dies. * * @version $Revision: 1.1 $ $Date: 2003/09/29 00:32:40 $ */ public class UnrecoverableLog implements TransactionLog { public void begin(Xid xid) throws IOException { } public void prepare(Xid xid) throws IOException { } public void commit(Xid xid) throws IOException { } public void rollback(Xid xid) throws IOException { } } 1.1 incubator-geronimo/modules/core/src/java/org/apache/geronimo/transaction/manager/TransactionImpl.java Index: TransactionImpl.java =================================================================== /* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" and * "Apache Geronimo" must not be used to endorse or promote products * derived from this software without prior written permission. For * written permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * "Apache Geronimo", nor may "Apache" appear in their name, without * prior written permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . * * ==================================================================== */ package org.apache.geronimo.transaction.manager; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import javax.transaction.HeuristicMixedException; import javax.transaction.HeuristicRollbackException; import javax.transaction.RollbackException; import javax.transaction.Status; import javax.transaction.Synchronization; import javax.transaction.SystemException; import javax.transaction.Transaction; import javax.transaction.xa.XAException; import javax.transaction.xa.XAResource; import javax.transaction.xa.Xid; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Basic local transaction with support for multiple resources. * * @version $Revision: 1.1 $ $Date: 2003/09/29 00:32:40 $ */ public class TransactionImpl implements Transaction { private static final Log log = LogFactory.getLog("Transaction"); private final XidFactory xidFactory; private final Xid xid; private final TransactionLog txnLog; private int status = Status.STATUS_NO_TRANSACTION; private List syncList = new ArrayList(5); private LinkedList resourceManagers = new LinkedList(); private Map xaResources = new HashMap(3); TransactionImpl(XidFactory xidFactory, TransactionLog txnLog) throws SystemException { this.xidFactory = xidFactory; this.txnLog = txnLog; this.xid = xidFactory.createXid(); try { txnLog.begin(xid); } catch (IOException e) { status = Status.STATUS_MARKED_ROLLBACK; SystemException ex = new SystemException("Error logging begin; transaction marked for roll back)"); ex.initCause(e); throw ex; } status = Status.STATUS_ACTIVE; } public synchronized int getStatus() throws SystemException { return status; } public synchronized void setRollbackOnly() throws IllegalStateException, SystemException { switch (status) { case Status.STATUS_ACTIVE: case Status.STATUS_PREPARING: status = Status.STATUS_MARKED_ROLLBACK; break; case Status.STATUS_MARKED_ROLLBACK: case Status.STATUS_ROLLING_BACK: // nothing to do break; default: throw new IllegalStateException("Cannot set rollback only, status is " + getStateString(status)); } } public synchronized void registerSynchronization(Synchronization synch) throws IllegalStateException, RollbackException, SystemException { if (synch == null) { throw new IllegalArgumentException("Synchronization is null"); } switch (status) { case Status.STATUS_ACTIVE: case Status.STATUS_PREPARING: break; case Status.STATUS_MARKED_ROLLBACK: throw new RollbackException("Transaction is marked for rollback"); default: throw new IllegalStateException("Status is " + getStateString(status)); } syncList.add(synch); } public synchronized boolean enlistResource(XAResource xaRes) throws IllegalStateException, RollbackException, SystemException { if (xaRes == null) { throw new IllegalArgumentException("XAResource is null"); } switch (status) { case Status.STATUS_ACTIVE: break; case Status.STATUS_MARKED_ROLLBACK: throw new RollbackException("Transaction is marked for rollback"); default: throw new IllegalStateException("Status is " + getStateString(status)); } try { for (Iterator i = resourceManagers.iterator(); i.hasNext();) { ResourceManager manager = (ResourceManager) i.next(); boolean sameRM; try { // @todo should we check if xaRes.equals(manager.committer) ? sameRM = xaRes.isSameRM(manager.committer); } catch (XAException e) { log.warn("Unexpected error checking for same RM", e); continue; } if (sameRM) { xaRes.start(manager.branchId, XAResource.TMJOIN); xaResources.put(xaRes, manager); return true; } } Xid branchId = xidFactory.createBranch(xid, resourceManagers.size() + 1); xaRes.start(branchId, XAResource.TMNOFLAGS); ResourceManager manager = new ResourceManager(xaRes, branchId); resourceManagers.add(manager); xaResources.put(xaRes, manager); return true; } catch (XAException e) { log.warn("Unable to enlist XAResource " + xaRes, e); return false; } } public synchronized boolean delistResource(XAResource xaRes, int flag) throws IllegalStateException, SystemException { if (xaRes == null) { throw new IllegalArgumentException("XAResource is null"); } switch (status) { case Status.STATUS_ACTIVE: case Status.STATUS_MARKED_ROLLBACK: break; default: throw new IllegalStateException("Status is " + getStateString(status)); } ResourceManager manager = (ResourceManager) xaResources.remove(xaRes); if (manager == null) { throw new IllegalStateException("Resource not enlisted"); } try { xaRes.end(manager.branchId, flag); return true; } catch (XAException e) { log.warn("Unable to delist XAResource " + xaRes, e); return false; } } public void commit() throws HeuristicMixedException, HeuristicRollbackException, RollbackException, SecurityException, SystemException { synchronized (this) { switch (status) { case Status.STATUS_ACTIVE: case Status.STATUS_MARKED_ROLLBACK: break; default: throw new IllegalStateException("Status is " + getStateString(status)); } } beforeCompletion(); endResources(); try { LinkedList rms; synchronized (this) { if (status == Status.STATUS_ACTIVE) { if (resourceManagers.size() == 0) { // nothing to commit status = Status.STATUS_COMMITTED; } else if (resourceManagers.size() == 1) { // one-phase commit decision status = Status.STATUS_COMMITTING; } else { // start prepare part of two-phase status = Status.STATUS_PREPARING; } } // resourceManagers is now immutable rms = resourceManagers; } // one-phase if (rms.size() == 1) { ResourceManager manager = (ResourceManager) rms.getFirst(); try { manager.committer.commit(manager.branchId, true); synchronized (this) { status = Status.STATUS_COMMITTED; } return; } catch (XAException e) { synchronized (this) { status = Status.STATUS_ROLLEDBACK; } RollbackException ex = new RollbackException("Error during one-phase commit"); ex.initCause(e); throw ex; } } // two-phase try { txnLog.prepare(xid); } catch (IOException e) { try { rollbackResources(rms); } catch (Exception se) { log.error("Unable to rollback after failure to log prepare", se.getCause()); } SystemException ex = new SystemException("Error logging prepare; transaction was rolled back)"); ex.initCause(e); throw ex; } for (Iterator i = rms.iterator(); i.hasNext();) { synchronized (this) { if (status != Status.STATUS_PREPARING) { // we were marked for rollback break; } } ResourceManager manager = (ResourceManager) i.next(); try { int vote = manager.committer.prepare(manager.branchId); if (vote == XAResource.XA_RDONLY) { // we don't need to consider this RM any more i.remove(); } } catch (XAException e) { synchronized (this) { status = Status.STATUS_MARKED_ROLLBACK; } } } // decision time... boolean willCommit; synchronized (this) { willCommit = (status != Status.STATUS_MARKED_ROLLBACK); if (willCommit) { status = Status.STATUS_PREPARED; } } // log our decision try { if (willCommit) { txnLog.commit(xid); } else { txnLog.rollback(xid); } } catch (IOException e) { try { rollbackResources(rms); } catch (Exception se) { log.error("Unable to rollback after failure to log decision", se.getCause()); } SystemException ex = new SystemException("Error logging decision (outcome is unknown)"); ex.initCause(e); throw ex; } // notify the RMs if (willCommit) { commitResources(rms); } else { rollbackResources(rms); throw new RollbackException("Unable to commit"); } } finally { afterCompletion(); synchronized (this) { status = Status.STATUS_NO_TRANSACTION; } } } public void rollback() throws IllegalStateException, SystemException { List rms; synchronized (this) { switch (status) { case Status.STATUS_ACTIVE: status = Status.STATUS_MARKED_ROLLBACK; break; case Status.STATUS_MARKED_ROLLBACK: break; default: throw new IllegalStateException("Status is " + getStateString(status)); } rms = resourceManagers; } beforeCompletion(); endResources(); try { try { txnLog.rollback(xid); } catch (IOException e) { try { rollbackResources(rms); } catch (Exception se) { log.error("Unable to rollback after failure to log decision", se.getCause()); } SystemException ex = new SystemException("Error logging rollback"); ex.initCause(e); throw ex; } rollbackResources(rms); } finally { afterCompletion(); synchronized (this) { status = Status.STATUS_NO_TRANSACTION; } } } private void beforeCompletion() { int i = 0; while (true) { Synchronization synch; synchronized (this) { if (i == syncList.size()) { return; } synch = (Synchronization) syncList.get(i++); } try { synch.beforeCompletion(); } catch (Exception e) { log.warn("Unexpected exception from beforeCompletion; transaction will roll back", e); synchronized (this) { status = Status.STATUS_MARKED_ROLLBACK; } } } } private void afterCompletion() { // this does not synchronize because nothing can modify our state at this time for (Iterator i = syncList.iterator(); i.hasNext();) { Synchronization synch = (Synchronization) i.next(); try { synch.afterCompletion(status); } catch (Exception e) { log.warn("Unexpected exception from afterCompletion; continuing", e); continue; } } } private void endResources() { while (true) { XAResource xaRes; ResourceManager manager; int flags; synchronized (this) { Set entrySet = xaResources.entrySet(); if (entrySet.isEmpty()) { return; } Map.Entry entry = (Map.Entry) entrySet.iterator().next(); xaRes = (XAResource) entry.getKey(); manager = (ResourceManager) entry.getValue(); flags = (status == Status.STATUS_MARKED_ROLLBACK) ? XAResource.TMFAIL : XAResource.TMSUCCESS; xaResources.remove(xaRes); } try { xaRes.end(manager.branchId, flags); } catch (XAException e) { log.warn("Error ending association for XAResource " + xaRes + "; transaction will roll back", e); synchronized (this) { status = Status.STATUS_MARKED_ROLLBACK; } } } } private void rollbackResources(List rms) throws SystemException { SystemException cause = null; synchronized (this) { status = Status.STATUS_ROLLING_BACK; } for (Iterator i = rms.iterator(); i.hasNext();) { ResourceManager manager = (ResourceManager) i.next(); try { manager.committer.rollback(manager.branchId); } catch (XAException e) { log.error("Unexpected exception rolling back " + manager.committer + "; continuing with rollback", e); if (cause == null) { cause = new SystemException(e.errorCode); } continue; } } synchronized (this) { status = Status.STATUS_ROLLEDBACK; } if (cause != null) { throw cause; } } private void commitResources(List rms) throws SystemException { SystemException cause = null; synchronized (this) { status = Status.STATUS_COMMITTING; } for (Iterator i = rms.iterator(); i.hasNext();) { ResourceManager manager = (ResourceManager) i.next(); try { manager.committer.commit(manager.branchId, false); } catch (XAException e) { log.error("Unexpected exception committing" + manager.committer + "; continuing to commit other RMs", e); if (cause == null) { cause = new SystemException(e.errorCode); } continue; } } synchronized (this) { status = Status.STATUS_COMMITTED; } if (cause != null) { throw cause; } } private static String getStateString(int status) { switch (status) { case Status.STATUS_ACTIVE: return "STATUS_ACTIVE"; case Status.STATUS_PREPARING: return "STATUS_PREPARING"; case Status.STATUS_PREPARED: return "STATUS_PREPARED"; case Status.STATUS_MARKED_ROLLBACK: return "STATUS_MARKED_ROLLBACK"; case Status.STATUS_ROLLING_BACK: return "STATUS_ROLLING_BACK"; case Status.STATUS_COMMITTING: return "STATUS_COMMITTING"; case Status.STATUS_COMMITTED: return "STATUS_COMMITTED"; case Status.STATUS_ROLLEDBACK: return "STATUS_ROLLEDBACK"; case Status.STATUS_NO_TRANSACTION: return "STATUS_NO_TRANSACTION"; case Status.STATUS_UNKNOWN: return "STATUS_UNKNOWN"; default: throw new AssertionError(); } } public boolean equals(Object obj) { if (obj instanceof TransactionImpl) { TransactionImpl other = (TransactionImpl) obj; return xid.equals(other.xid); } else { return false; } } private static class ResourceManager { private final XAResource committer; private final Xid branchId; public ResourceManager(XAResource xaRes, Xid branchId) { committer = xaRes; this.branchId = branchId; } } } 1.1 incubator-geronimo/modules/core/src/java/org/apache/geronimo/transaction/manager/TransactionLog.java Index: TransactionLog.java =================================================================== /* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" and * "Apache Geronimo" must not be used to endorse or promote products * derived from this software without prior written permission. For * written permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * "Apache Geronimo", nor may "Apache" appear in their name, without * prior written permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . * * ==================================================================== */ package org.apache.geronimo.transaction.manager; import java.io.IOException; import javax.transaction.xa.Xid; /** * Interface used to notify a logging subsystem of transaction events. * * @version $Revision: 1.1 $ $Date: 2003/09/29 00:32:40 $ */ public interface TransactionLog { public void begin(Xid xid) throws IOException; public void prepare(Xid xid) throws IOException; public void commit(Xid xid) throws IOException; public void rollback(Xid xid) throws IOException; } 1.1 incubator-geronimo/modules/core/src/java/org/apache/geronimo/transaction/manager/TransactionManagerImpl.java Index: TransactionManagerImpl.java =================================================================== /* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" and * "Apache Geronimo" must not be used to endorse or promote products * derived from this software without prior written permission. For * written permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * "Apache Geronimo", nor may "Apache" appear in their name, without * prior written permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . * * ==================================================================== */ package org.apache.geronimo.transaction.manager; import javax.transaction.HeuristicMixedException; import javax.transaction.HeuristicRollbackException; import javax.transaction.InvalidTransactionException; import javax.transaction.NotSupportedException; import javax.transaction.RollbackException; import javax.transaction.Status; import javax.transaction.SystemException; import javax.transaction.Transaction; import javax.transaction.TransactionManager; import org.apache.geronimo.transaction.log.UnrecoverableLog; /** * Simple implementation of a local transaction manager. * * @version $Revision: 1.1 $ $Date: 2003/09/29 00:32:40 $ */ public class TransactionManagerImpl implements TransactionManager { private final TransactionLog txnLog = new UnrecoverableLog(); private final XidFactory xidFactory = new XidFactory(); private volatile int timeout; private ThreadLocal threadTx = new ThreadLocal(); public Transaction getTransaction() throws SystemException { return (Transaction) threadTx.get(); } public void setTransactionTimeout(int seconds) throws SystemException { timeout = seconds; } public int getStatus() throws SystemException { Transaction tx = getTransaction(); return (tx != null) ? tx.getStatus() : Status.STATUS_NO_TRANSACTION; } public void begin() throws NotSupportedException, SystemException { if (getStatus() != Status.STATUS_NO_TRANSACTION) { throw new NotSupportedException("Nested Transactions are not supported"); } TransactionImpl tx = new TransactionImpl(xidFactory, txnLog); threadTx.set(tx); } public Transaction suspend() throws SystemException { Transaction tx = getTransaction(); threadTx.set(null); return tx; } public void resume(Transaction tx) throws IllegalStateException, InvalidTransactionException, SystemException { if (threadTx.get() != null) { throw new IllegalStateException("Transaction already associated with current thread"); } if (tx instanceof TransactionImpl == false) { throw new InvalidTransactionException("Cannot resume foreign transaction: " + tx); } threadTx.set(tx); } public void setRollbackOnly() throws IllegalStateException, SystemException { Transaction tx = getTransaction(); if (tx == null) { throw new IllegalStateException("No transaction associated with current thread"); } tx.setRollbackOnly(); } public void commit() throws HeuristicMixedException, HeuristicRollbackException, IllegalStateException, RollbackException, SecurityException, SystemException { Transaction tx = getTransaction(); if (tx == null) { throw new IllegalStateException("No transaction associated with current thread"); } try { tx.commit(); } finally { threadTx.set(null); } } public void rollback() throws IllegalStateException, SecurityException, SystemException { Transaction tx = getTransaction(); if (tx == null) { throw new IllegalStateException("No transaction associated with current thread"); } try { tx.rollback(); } finally { threadTx.set(null); } } } 1.1 incubator-geronimo/modules/core/src/java/org/apache/geronimo/transaction/manager/XidFactory.java Index: XidFactory.java =================================================================== /* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" and * "Apache Geronimo" must not be used to endorse or promote products * derived from this software without prior written permission. For * written permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * "Apache Geronimo", nor may "Apache" appear in their name, without * prior written permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . * * ==================================================================== */ package org.apache.geronimo.transaction.manager; import java.net.InetAddress; import java.net.UnknownHostException; import javax.transaction.xa.Xid; /** * Factory for transaction ids. * The Xid is constructed of three parts: *
  1. 8 byte count (LSB first)
  2. *
  3. 4 byte system id
  4. *
  5. 4 or 16 byte IP address of host
  6. *
      * @version $Revision: 1.1 $ $Date: 2003/09/29 00:32:40 $ * @todo Should have a way of setting baseId */ public class XidFactory { byte[] baseId = new byte[Xid.MAXGTRIDSIZE]; long count = 1; public XidFactory() { byte[] hostid; try { hostid = InetAddress.getLocalHost().getAddress(); } catch (UnknownHostException e) { hostid = new byte[]{127, 0, 0, 1}; } int uid = System.identityHashCode(this); baseId[8] = (byte) uid; baseId[9] = (byte) (uid >>> 8); baseId[10] = (byte) (uid >>> 16); baseId[11] = (byte) (uid >>> 24); System.arraycopy(hostid, 0, baseId, 12, hostid.length); } public Xid createXid() { byte[] globalId = (byte[]) baseId.clone(); long id; synchronized (this) { id = count++; } globalId[0] = (byte) id; globalId[1] = (byte) (id >>> 8); globalId[2] = (byte) (id >>> 16); globalId[3] = (byte) (id >>> 24); globalId[4] = (byte) (id >>> 32); globalId[5] = (byte) (id >>> 40); globalId[6] = (byte) (id >>> 48); globalId[7] = (byte) (id >>> 56); return new XidImpl(globalId); } public Xid createBranch(Xid globalId, int branch) { return new XidImpl(globalId, branch); } } 1.1 incubator-geronimo/modules/core/src/java/org/apache/geronimo/transaction/manager/XidImpl.java Index: XidImpl.java =================================================================== /* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" and * "Apache Geronimo" must not be used to endorse or promote products * derived from this software without prior written permission. For * written permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * "Apache Geronimo", nor may "Apache" appear in their name, without * prior written permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . * * ==================================================================== */ package org.apache.geronimo.transaction.manager; import java.io.Serializable; import java.util.Arrays; import javax.transaction.xa.Xid; /** * Unique id for a transaction. * * @version $Revision: 1.1 $ $Date: 2003/09/29 00:32:40 $ */ public class XidImpl implements Xid, Serializable { private static int FORMAT_ID = 0x4765526f; // Gero private final byte[] globalId; private final byte[] branchId; private final int hash; /** * Constructor taking a global id (for the main transaction) * @param globalId the global transaction id */ public XidImpl(byte[] globalId) { this.globalId = globalId; this.hash = hash(globalId); branchId = new byte[Xid.MAXBQUALSIZE]; } /** * Constructor for a branch id * @param global the xid of the global transaction this branch belongs to * @param branch the branch id */ public XidImpl(Xid global, int branch) { int hash; if (global instanceof XidImpl) { globalId = ((XidImpl) global).globalId; hash = ((XidImpl) global).hash; } else { globalId = global.getGlobalTransactionId(); hash = hash(globalId); } branchId = new byte[Xid.MAXBQUALSIZE]; branchId[0] = (byte) branch; branchId[1] = (byte) (branch >>> 8); branchId[2] = (byte) (branch >>> 16); branchId[3] = (byte) (branch >>> 24); for (int i = 0; i < 4; i++) { hash = (hash * 37) + branchId[i]; } this.hash = hash; } private int hash(byte[] id) { int hash = 0; for (int i = 0; i < id.length; i++) { hash = (hash * 37) + id[i]; } return hash; } public int getFormatId() { return FORMAT_ID; } public byte[] getGlobalTransactionId() { return (byte[]) globalId.clone(); } public byte[] getBranchQualifier() { return (byte[]) branchId.clone(); } public boolean equals(Object obj) { if (obj instanceof XidImpl == false) { return false; } XidImpl other = (XidImpl) obj; return Arrays.equals(globalId, other.globalId) && Arrays.equals(branchId, other.branchId); } public int hashCode() { return hash; } } 1.1 incubator-geronimo/modules/core/src/test/org/apache/geronimo/transaction/manager/MockResource.java Index: MockResource.java =================================================================== /* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" and * "Apache Geronimo" must not be used to endorse or promote products * derived from this software without prior written permission. For * written permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * "Apache Geronimo", nor may "Apache" appear in their name, without * prior written permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . * * ==================================================================== */ package org.apache.geronimo.transaction.manager; import javax.transaction.xa.XAException; import javax.transaction.xa.XAResource; import javax.transaction.xa.Xid; /** * * * @version $Revision: 1.1 $ $Date: 2003/09/29 00:32:40 $ */ public class MockResource implements XAResource { private Xid xid; private MockResourceManager manager; private int timeout = 0; public MockResource(MockResourceManager manager) { this.manager = manager; } public int getTransactionTimeout() throws XAException { return timeout; } public boolean setTransactionTimeout(int seconds) throws XAException { return false; } public Xid getXid() { return xid; } public void start(Xid xid, int flags) throws XAException { if (this.xid != null) { throw new XAException(XAException.XAER_PROTO); } if ((flags & XAResource.TMJOIN) != 0) { manager.join(xid, this); } else { manager.newTx(xid, this); } this.xid = xid; } public void end(Xid xid, int flags) throws XAException { if (this.xid != xid) { throw new XAException(XAException.XAER_INVAL); } this.xid = null; } public int prepare(Xid xid) throws XAException { return 0; } public void commit(Xid xid, boolean onePhase) throws XAException { } public void rollback(Xid xid) throws XAException { manager.forget(xid, this); } public boolean isSameRM(XAResource xaResource) throws XAException { if (xaResource instanceof MockResource) { return manager == ((MockResource) xaResource).manager; } return false; } public void forget(Xid xid) throws XAException { throw new UnsupportedOperationException(); } public Xid[] recover(int flag) throws XAException { throw new UnsupportedOperationException(); } } 1.1 incubator-geronimo/modules/core/src/test/org/apache/geronimo/transaction/manager/MockResourceManager.java Index: MockResourceManager.java =================================================================== /* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" and * "Apache Geronimo" must not be used to endorse or promote products * derived from this software without prior written permission. For * written permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * "Apache Geronimo", nor may "Apache" appear in their name, without * prior written permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . * * ==================================================================== */ package org.apache.geronimo.transaction.manager; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import javax.transaction.xa.XAException; import javax.transaction.xa.XAResource; import javax.transaction.xa.Xid; /** * * * @version $Revision: 1.1 $ $Date: 2003/09/29 00:32:40 $ */ public class MockResourceManager { private boolean willCommit; private Map xids = new HashMap(); public MockResourceManager(boolean willCommit) { this.willCommit = willCommit; } public MockResource getResource() { return new MockResource(this); } public void join(Xid xid, XAResource xaRes) throws XAException { Set resSet = (Set) xids.get(xid); if (resSet == null) { throw new XAException(XAException.XAER_NOTA); } resSet.add(xaRes); } public void newTx(Xid xid, XAResource xaRes) throws XAException { if (xids.containsKey(xid)) { throw new XAException(XAException.XAER_DUPID); } Set resSet = new HashSet(); resSet.add(xaRes); xids.put(xid, resSet); } public void forget(Xid xid, XAResource xaRes) throws XAException { if (xids.remove(xid) == null) { throw new XAException(XAException.XAER_NOTA); } } } 1.1 incubator-geronimo/modules/core/src/test/org/apache/geronimo/transaction/manager/TestTransactionManager.java Index: TestTransactionManager.java =================================================================== /* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" and * "Apache Geronimo" must not be used to endorse or promote products * derived from this software without prior written permission. For * written permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * "Apache Geronimo", nor may "Apache" appear in their name, without * prior written permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . * * ==================================================================== */ package org.apache.geronimo.transaction.manager; import javax.transaction.Status; import javax.transaction.Transaction; import javax.transaction.TransactionManager; import javax.transaction.xa.XAResource; import junit.framework.TestCase; /** * * * @version $Revision: 1.1 $ $Date: 2003/09/29 00:32:40 $ */ public class TestTransactionManager extends TestCase { TransactionManager tm; MockResourceManager rm1, rm2, rm3; public void testNoTransaction() throws Exception { assertEquals(Status.STATUS_NO_TRANSACTION, tm.getStatus()); assertNull(tm.getTransaction()); } public void testNoResource() throws Exception { Transaction tx; assertEquals(Status.STATUS_NO_TRANSACTION, tm.getStatus()); tm.begin(); assertEquals(Status.STATUS_ACTIVE, tm.getStatus()); tx = tm.getTransaction(); assertNotNull(tx); assertEquals(Status.STATUS_ACTIVE, tx.getStatus()); tm.rollback(); assertEquals(Status.STATUS_NO_TRANSACTION, tm.getStatus()); assertNull(tm.getTransaction()); assertEquals(Status.STATUS_NO_TRANSACTION, tx.getStatus()); tm.begin(); assertEquals(Status.STATUS_ACTIVE, tm.getStatus()); tm.rollback(); assertEquals(Status.STATUS_NO_TRANSACTION, tm.getStatus()); } public void testTxOp() throws Exception { Transaction tx; tm.begin(); tx = tm.getTransaction(); tx.rollback(); assertEquals(Status.STATUS_NO_TRANSACTION, tx.getStatus()); assertEquals(Status.STATUS_NO_TRANSACTION, tm.getStatus()); tm.begin(); assertFalse(tx.equals(tm.getTransaction())); tm.rollback(); } public void testSuspend() throws Exception { Transaction tx; assertEquals(Status.STATUS_NO_TRANSACTION, tm.getStatus()); tm.begin(); assertEquals(Status.STATUS_ACTIVE, tm.getStatus()); tx = tm.getTransaction(); assertNotNull(tx); assertEquals(Status.STATUS_ACTIVE, tx.getStatus()); tx = tm.suspend(); assertEquals(Status.STATUS_NO_TRANSACTION, tm.getStatus()); assertNull(tm.getTransaction()); tm.resume(tx); assertEquals(Status.STATUS_ACTIVE, tm.getStatus()); assertEquals(tx, tm.getTransaction()); tm.rollback(); assertEquals(Status.STATUS_NO_TRANSACTION, tm.getStatus()); assertNull(tm.getTransaction()); } public void testOneResource() throws Exception { Transaction tx; MockResource res1 = rm1.getResource(); tm.begin(); tx = tm.getTransaction(); assertNull(res1.getXid()); assertTrue(tx.enlistResource(res1)); assertNotNull(res1.getXid()); assertTrue(tx.delistResource(res1, XAResource.TMFAIL)); assertNull(res1.getXid()); tm.rollback(); tm.begin(); tx = tm.getTransaction(); assertTrue(tx.enlistResource(res1)); tm.rollback(); assertNull(res1.getXid()); } protected void setUp() throws Exception { tm = new TransactionManagerImpl(); rm1 = new MockResourceManager(true); rm2 = new MockResourceManager(true); rm3 = new MockResourceManager(false); } }