[jboss-svn-commits] JBL Code SVN: r18374 - in labs/jbosstm/trunk: atsintegration/classes/com/arjuna/ats/jbossatx and 2 other directories.
jboss-svn-commits at lists.jboss.org
jboss-svn-commits at lists.jboss.org
Thu Feb 7 08:38:53 EST 2008
Author: jhalliday
Date: 2008-02-07 08:38:53 -0500 (Thu, 07 Feb 2008)
New Revision: 18374
Removed:
labs/jbosstm/trunk/atsintegration/classes/com/arjuna/ats/jbossatx/TransactionLocalDelegateImpl.java
Modified:
labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/jta/transaction/Transaction.java
labs/jbosstm/trunk/atsintegration/classes/com/arjuna/ats/jbossatx/BaseTransactionManagerDelegate.java
labs/jbosstm/trunk/atsintegration/classes/com/arjuna/ats/jbossatx/jta/TransactionManagerDelegate.java
labs/jbosstm/trunk/atsintegration/classes/com/arjuna/ats/jbossatx/jts/TransactionManagerService.java
Log:
Added TransactionSynchronizationRegistry implementation to the JTS for JTA 1.1 API compliance. Removed the now obsolete TransactionLocalDelegateImpl. JBTM-289.
Modified: labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/jta/transaction/Transaction.java
===================================================================
--- labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/jta/transaction/Transaction.java 2008-02-07 13:31:56 UTC (rev 18373)
+++ labs/jbosstm/trunk/ArjunaJTA/jta/classes/com/arjuna/ats/jta/transaction/Transaction.java 2008-02-07 13:38:53 UTC (rev 18374)
@@ -1,20 +1,20 @@
/*
* JBoss, Home of Professional Open Source
- * Copyright 2006, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags.
+ * Copyright 2006, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags.
* See the copyright.txt in the distribution for a
- * full listing of individual contributors.
+ * full listing of individual contributors.
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License, v. 2.1.
- * This program is distributed in the hope that it will be useful, but WITHOUT A
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * This program is distributed in the hope that it will be useful, but WITHOUT A
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License,
* v.2.1 along with this distribution; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
- *
+ *
* (C) 2005-2006,
* @author JBoss Inc.
*/
@@ -41,7 +41,7 @@
* Extended methods.
*/
-public interface Transaction
+public interface Transaction extends javax.transaction.Transaction
{
public static final int XACONNECTION = 0;
@@ -50,5 +50,9 @@
public boolean enlistResource (XAResource xaRes, Object[] params) throws RollbackException, IllegalStateException, javax.transaction.SystemException;
public int getXAResourceState (XAResource xaRes);
-
+
+ // Methods used to support JTA 1.1 TransactionSynchronizationRegistry implementation
+ public Object getTxLocalResource(Object key);
+ public void putTxLocalResource(Object key, Object value);
+ public boolean isAlive();
}
Modified: labs/jbosstm/trunk/atsintegration/classes/com/arjuna/ats/jbossatx/BaseTransactionManagerDelegate.java
===================================================================
--- labs/jbosstm/trunk/atsintegration/classes/com/arjuna/ats/jbossatx/BaseTransactionManagerDelegate.java 2008-02-07 13:31:56 UTC (rev 18373)
+++ labs/jbosstm/trunk/atsintegration/classes/com/arjuna/ats/jbossatx/BaseTransactionManagerDelegate.java 2008-02-07 13:38:53 UTC (rev 18374)
@@ -1,20 +1,20 @@
/*
* JBoss, Home of Professional Open Source
- * Copyright 2006, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags.
+ * Copyright 2006, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags.
* See the copyright.txt in the distribution for a
- * full listing of individual contributors.
+ * full listing of individual contributors.
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License, v. 2.1.
- * This program is distributed in the hope that it will be useful, but WITHOUT A
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * This program is distributed in the hope that it will be useful, but WITHOUT A
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License,
* v.2.1 along with this distribution; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
- *
+ *
* (C) 2005-2006,
* @author JBoss Inc.
*/
@@ -33,6 +33,9 @@
import org.jboss.tm.TransactionLocalDelegate;
import org.jboss.tm.TransactionTimeoutConfiguration;
+import java.util.Map;
+import java.util.HashMap;
+
/**
* Delegate for JBoss TransactionManager/TransactionLocalDelegate.
* @author kevin
@@ -43,29 +46,14 @@
* Delegate transaction manager.
*/
private final TransactionManager transactionManager ;
+
/**
- * Delegate transaction local delegate.
- */
- private final TransactionLocalDelegate transactionLocalDelegate ;
-
- /**
* Construct the delegate using the specified transaction manager.
* @param transactionManager The delegate transaction manager.
*/
protected BaseTransactionManagerDelegate(final TransactionManager transactionManager)
{
- this(transactionManager, new TransactionLocalDelegateImpl()) ;
- }
-
- /**
- * Construct the delegate using the specified transaction manager and transaction local delegate.
- * @param transactionManager The delegate transaction manager.
- * @param transactionLocalDelegate The delegate transaction local delegate.
- */
- protected BaseTransactionManagerDelegate(final TransactionManager transactionManager, final TransactionLocalDelegate transactionLocalDelegate)
- {
this.transactionManager = transactionManager ;
- this.transactionLocalDelegate = transactionLocalDelegate ;
}
/**
@@ -155,56 +143,227 @@
return transactionManager.suspend() ;
}
+ /////////////////////////
+
+ // TransactionLocalDelegate implementation methods. This part is basically
+ // stateless, we just delegate down to the object storage on the TransactionImple
+
+ // Note this has some interesting effects around Transaction termination. The TransactionImple instance
+ // lifetime is up to tx termination only. After that getTransaction() on the tm returns a new instance
+ // representing the same tx. Hence TransactionLocal state goes away magically at tx termination time
+ // since it's part of the TransactionImple instance. That's what we want and saves writing cleanup code.
+ // On the down side, since locks use the same storage they go away too. This causes us to have to
+ // jump through some hoops to deal with locks vanishing and maybe never getting unlocked, see below.
+
/**
* Does the specified transaction contain a value for the transaction local.
+ *
* @param transactionLocal The associated transaction local.
- * @param transaction The associated transaction.
+ * @param transaction The associated transaction.
* @return true if a value exists within the specified transaction, false otherwise.
*/
- public boolean containsValue(final TransactionLocal transactionLocal, final Transaction transaction)
- {
- return transactionLocalDelegate.containsValue(transactionLocal, transaction) ;
+ public boolean containsValue(final TransactionLocal transactionLocal, final Transaction transaction) {
+ com.arjuna.ats.jta.transaction.Transaction transactionImple = (com.arjuna.ats.jta.transaction.Transaction) transaction;
+ if(transactionImple.isAlive()) {
+ return (transactionImple.getTxLocalResource(transactionLocal) != null ? true : false);
+ } else {
+ return false;
+ }
}
/**
* Get value of the transaction local in the specified transaction.
+ *
* @param transactionLocal The associated transaction local.
- * @param transaction The associated transaction.
+ * @param transaction The associated transaction.
* @return The value of the transaction local.
*/
- public Object getValue(final TransactionLocal transactionLocal, final Transaction transaction)
- {
- return transactionLocalDelegate.getValue(transactionLocal, transaction) ;
+ public Object getValue(final TransactionLocal transactionLocal, final Transaction transaction) {
+ com.arjuna.ats.jta.transaction.Transaction transactionImple = (com.arjuna.ats.jta.transaction.Transaction) transaction;
+ if(transactionImple.isAlive()) {
+ return transactionImple.getTxLocalResource(transactionLocal);
+ } else {
+ return null;
+ }
}
/**
* Store the value of the transaction local in the specified transaction.
+ *
* @param transactionLocal The associated transaction local.
- * @param transaction The associated transaction.
- * @param value The value of the transaction local.
+ * @param transaction The associated transaction.
+ * @param value The value of the transaction local.
*/
public void storeValue(final TransactionLocal transactionLocal, final Transaction transaction,
- final Object value)
- {
- transactionLocalDelegate.storeValue(transactionLocal, transaction, value) ;
+ final Object value) {
+ com.arjuna.ats.jta.transaction.Transaction transactionImple = (com.arjuna.ats.jta.transaction.Transaction) transaction;
+ if(transactionImple.isAlive()) {
+ transactionImple.putTxLocalResource(transactionLocal, value);
+ } else {
+ throw new IllegalStateException("Can't store value in a TransactionLocal after the Transaction has ended");
+ }
}
-
+
/**
* Lock the transaction local in the context of this transaction.
+ *
* @throws IllegalStateException if the transaction is not active
- * @throws InterruptedException if the thread is interrupted
+ * @throws InterruptedException if the thread is interrupted
*/
- public void lock(final TransactionLocal local, final Transaction tx)
- throws InterruptedException
- {
- transactionLocalDelegate.lock(local, tx) ;
+ public void lock(final TransactionLocal local, final Transaction transaction)
+ throws InterruptedException {
+ com.arjuna.ats.jta.transaction.Transaction transactionImple = (com.arjuna.ats.jta.transaction.Transaction) transaction;
+ if(transactionImple.isAlive()) {
+ // There is a race here, as the transaction may terminate between the check
+ // and the lock attempt. See lock() implementation below.
+ // It's still possible to lock a dead transaction, but that does no real harm.
+ TransactionLocalLock lock = findLock(local, transaction);
+ if(lock.lock(transactionImple)) {
+ return;
+ }
+ }
+
+ throw new IllegalStateException("Can't lock a TransactionLocal after the Transaction has ended");
}
-
+
/**
* Unlock the transaction local in the context of this transaction
*/
- public void unlock(final TransactionLocal local, final Transaction tx)
+ public void unlock(final TransactionLocal local, final Transaction transaction) {
+ TransactionLocalLock lock = findLock(local, transaction);
+ lock.unlock();
+ }
+
+ // Lock implementation: This used to use a Synchronization for lock storage, but
+ // we need to be able to lock things in some states where registration of
+ // Synchronizations is not permitted. Besides, the JTA 1.1 work gives us a nice
+ // general object storage mechanism on a TransactionImple, so we use that.
+
+ // This is the key under which the map of TransactionLocals to locks is stored.
+ // Bad things will probably happen if users ever use this key themselves
+ private final String LOCKS_MAP = "__LOCKS_MAP";
+
+ // locate and return the lock for a given TransactionLocal+Transaction tuple.
+ // create it if it does not exist.
+ private TransactionLocalLock findLock(final TransactionLocal local, final Transaction transaction) {
+
+ com.arjuna.ats.jta.transaction.Transaction transactionImple = (com.arjuna.ats.jta.transaction.Transaction) transaction;
+ Map locks; // <TransactionLocal, TransactionLocalLock>
+ // ideally for performance we should sync on the tx instance itself but that may have nasty
+ // side effects so we use something else as the lock object for the sync block
+ synchronized (LOCKS_MAP) {
+ // ensure there is a holder for lock storage on the given tx instance.
+ locks = (Map) transactionImple.getTxLocalResource(LOCKS_MAP);
+ if (locks == null) {
+ locks = new HashMap(); // <TransactionLocal, TransactionLocalLock>
+ transactionImple.putTxLocalResource(LOCKS_MAP, locks);
+ }
+ }
+
+ TransactionLocalLock transactionLocalLock;
+ synchronized (locks) {
+ // ensure there is a lock for the specified local+tx tuple
+ transactionLocalLock = (TransactionLocalLock)locks.get(local);
+ if (transactionLocalLock == null) {
+ transactionLocalLock = new TransactionLocalLock();
+ locks.put(local, transactionLocalLock);
+ }
+ }
+
+ return transactionLocalLock;
+ }
+
+ // A class for the storage of individual lock state:
+
+ private class TransactionLocalLock
{
- transactionLocalDelegate.unlock(local, tx) ;
+ /**
+ * The locking thread.
+ */
+ private Thread lockingThread ;
+ /**
+ * The lock count.
+ */
+ private int lockCount ;
+ /**
+ * The lock.
+ */
+ private byte[] lock = new byte[0] ;
+
+ /**
+ * Lock the transaction local within the current thread context.
+ * true on lock acquired, false otherwise
+ */
+ public boolean lock(com.arjuna.ats.jta.transaction.Transaction tx)
+ {
+ // The current code in the app server locks the transaction for all, we follow that practice
+ synchronized(lock)
+ {
+ final Thread currentThread = Thread.currentThread() ;
+ if (currentThread == lockingThread)
+ {
+ lockCount++ ;
+ return true;
+ }
+
+ while (lockingThread != null)
+ {
+ try
+ {
+ // lock object instances get thrown away at Transaction termination. That makes it impossible
+ // to call unlock() on them. Searching through them and unlocking them from the transaction
+ // termination code is a pain and finalizers suck.
+ // Hence we need to make sure we don't wait forever for a notify
+ // that will never come. Probably the only thing that will terminate a Transaction in another
+ // Thread is the transaction reaper, so we wait not longer than the tx timeout plus a fudge factor.
+ long timeout = 0;
+ try {
+ timeout = getTransactionTimeout();
+ } catch(SystemException e) {}
+
+ lock.wait(timeout+1000);
+ if(!tx.isAlive()) {
+ // transaction is dead, can't be locked, cleanup
+ lockingThread = null;
+ lockCount = 0;
+ return false;
+ }
+ }
+ catch (final InterruptedException ie) {}
+ }
+
+ lockingThread = currentThread ;
+ lockCount ++ ;
+ return true;
+ }
+ }
+
+ /**
+ * Unlock the transaction local within the current thread context.
+ */
+ public void unlock()
+ {
+ synchronized(lock)
+ {
+ if(lockCount == 0 && lockingThread == null) {
+ // the lock was probably reset by a transaction termination.
+ // we fail silent to save the caller having to deal with race condition.
+ return;
+ }
+
+ final Thread currentThread = Thread.currentThread() ;
+ if (currentThread != lockingThread)
+ {
+ throw new IllegalStateException("Unlock called from wrong thread. Locking thread: " + lockingThread +
+ ", current thread: " + currentThread) ;
+ }
+
+ if (--lockCount == 0)
+ {
+ lockingThread = null ;
+ lock.notify() ;
+ }
+ }
+ }
}
}
Deleted: labs/jbosstm/trunk/atsintegration/classes/com/arjuna/ats/jbossatx/TransactionLocalDelegateImpl.java
===================================================================
--- labs/jbosstm/trunk/atsintegration/classes/com/arjuna/ats/jbossatx/TransactionLocalDelegateImpl.java 2008-02-07 13:31:56 UTC (rev 18373)
+++ labs/jbosstm/trunk/atsintegration/classes/com/arjuna/ats/jbossatx/TransactionLocalDelegateImpl.java 2008-02-07 13:38:53 UTC (rev 18374)
@@ -1,289 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- * Copyright 2006, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags.
- * See the copyright.txt in the distribution for a
- * full listing of individual contributors.
- * This copyrighted material is made available to anyone wishing to use,
- * modify, copy, or redistribute it subject to the terms and conditions
- * of the GNU Lesser General Public License, v. 2.1.
- * This program is distributed in the hope that it will be useful, but WITHOUT A
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
- * You should have received a copy of the GNU Lesser General Public License,
- * v.2.1 along with this distribution; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- *
- * (C) 2005-2006,
- * @author JBoss Inc.
- */
-package com.arjuna.ats.jbossatx;
-
-import java.lang.ref.WeakReference;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.WeakHashMap;
-
-import javax.transaction.Status;
-import javax.transaction.Synchronization;
-import javax.transaction.SystemException;
-import javax.transaction.Transaction;
-
-import org.jboss.tm.TransactionLocal;
-import org.jboss.tm.TransactionLocalDelegate;
-import org.jboss.util.NestedRuntimeException;
-
-/**
- * An implementation of the transaction local delegate using weak references.
- * @author kevin
- */
-public class TransactionLocalDelegateImpl implements TransactionLocalDelegate
-{
- /**
- * The transaction local map.
- */
- private Map transactionMap = Collections.synchronizedMap(new WeakHashMap()) ;
-
- /**
- * Does the specified transaction contain a value for the transaction local.
- * @param transactionLocal The associated transaction local.
- * @param transaction The associated transaction.
- * @return true if a value exists within the specified transaction, false otherwise.
- */
- public boolean containsValue(final TransactionLocal transactionLocal, final Transaction transaction)
- {
- final Map map = getMap(transaction, false) ;
- return ((map != null) && map.containsKey(transactionLocal)) ;
- }
-
- /**
- * Get value of the transaction local in the specified transaction.
- * @param transactionLocal The associated transaction local.
- * @param transaction The associated transaction.
- * @return The value of the transaction local.
- */
- public Object getValue(final TransactionLocal transactionLocal, final Transaction transaction)
- {
- final Map map = getMap(transaction, false) ;
- return (map == null ? null : map.get(transactionLocal)) ;
- }
-
- /**
- * Store the value of the transaction local in the specified transaction.
- * @param transactionLocal The associated transaction local.
- * @param transaction The associated transaction.
- * @param value The value of the transaction local.
- */
- public void storeValue(final TransactionLocal transactionLocal, final Transaction transaction,
- final Object value)
- {
- final int status ;
- try
- {
- status = transaction.getStatus() ;
- }
- catch (final SystemException se)
- {
- throw new NestedRuntimeException(se) ;
- }
- if (status == Status.STATUS_ACTIVE)
- {
- final Map map = getMap(transaction, true) ;
- map.put(transactionLocal, value) ;
- }
- }
-
- /**
- * Lock the transaction local in the context of this transaction.
- * @param transactionLocal The associated transaction local.
- * @param transaction The associated transaction.
- * @throws IllegalStateException if the transaction is not active
- * @throws InterruptedException if the thread is interrupted
- */
- public void lock(final TransactionLocal transactionLocal, final Transaction transaction)
- throws InterruptedException
- {
- final int status ;
- try
- {
- status = transaction.getStatus() ;
- }
- catch (final SystemException se)
- {
- throw new NestedRuntimeException(se) ;
- }
- if (status != Status.STATUS_ACTIVE)
- {
- throw new IllegalStateException("Transaction not active") ;
- }
- final TransactionLocalSynchronization synchronization = getSynchronization(transaction, true) ;
- synchronization.lock(transactionLocal) ;
- }
-
- /**
- * Unlock the transaction local in the context of this transaction
- * @param transactionLocal The associated transaction local.
- * @param transaction The associated transaction.
- */
- public void unlock(final TransactionLocal transactionLocal, final Transaction transaction)
- {
- final TransactionLocalSynchronization synchronization = getSynchronization(transaction, true) ;
- if (synchronization != null)
- {
- synchronization.unlock(transactionLocal) ;
- }
- }
-
- /**
- * Get the value map for the transaction.
- * @param transaction The transaction.
- * @param create true if the transaction information should be created, false otherwise.
- * @return The value map or null.
- */
- private Map getMap(final Transaction transaction, final boolean create)
- {
- final TransactionLocalSynchronization synchronization = getSynchronization(transaction, create) ;
- return (synchronization == null ? null : synchronization.getMap()) ;
- }
-
- /**
- * Get the synchronization for the transaction.
- * @param transaction The transaction.
- * @param create true if the transaction information should be created, false otherwise.
- * @return The synchronization or null.
- */
- private TransactionLocalSynchronization getSynchronization(final Transaction transaction, final boolean create)
- {
- final WeakReference reference = (WeakReference)transactionMap.get(transaction) ;
- if (reference != null)
- {
- final TransactionLocalSynchronization synchronization = (TransactionLocalSynchronization)reference.get() ;
- if (synchronization != null)
- {
- return synchronization ;
- }
- }
-
- if (!create)
- {
- return null ;
- }
-
- final TransactionLocalSynchronization synchronization = new TransactionLocalSynchronization() ;
- try
- {
- transaction.registerSynchronization(synchronization) ;
- }
- catch (final Exception ex)
- {
- throw new NestedRuntimeException(ex) ;
- }
- transactionMap.put(transaction, new WeakReference(synchronization)) ;
- return synchronization ;
- }
-
- /**
- *
- * @author kevin
- *
- */
- private static class TransactionLocalSynchronization implements Synchronization
- {
- /**
- * The values map.
- */
- private Map map = Collections.synchronizedMap(new HashMap()) ;
- /**
- * The locking thread.
- */
- private Thread lockingThread ;
- /**
- * The lock count.
- */
- private int lockCount ;
- /**
- * The lock.
- */
- private byte[] lock = new byte[0] ;
-
- /**
- * Get the values map.
- * @return The values map.
- */
- public Map getMap()
- {
- return map ;
- }
-
- /**
- * After completion event.
- */
- public void afterCompletion(final int result)
- {
- // Do nothing
- }
-
- /**
- * before completion event.
- */
- public void beforeCompletion()
- {
- // Do nothing
- }
-
- /**
- * Lock the transaction local within the curren thread context.
- * @param transactionLocal The transaction local.
- */
- public void lock(final TransactionLocal transactionLocal)
- {
- // The current code in the app server locks the transaction for all, we follow that practice
- synchronized(lock)
- {
- final Thread currentThread = Thread.currentThread() ;
- if (currentThread == lockingThread)
- {
- lockCount++ ;
- return ;
- }
-
- while (lockingThread != null)
- {
- try
- {
- lock.wait();
- }
- catch (final InterruptedException ie) {}
- }
-
- lockingThread = currentThread ;
- lockCount ++ ;
- }
- }
-
- /**
- * Unlock the transaction local within the curren thread context.
- * @param transactionLocal The transaction local.
- */
- public void unlock(final TransactionLocal transactionLocal)
- {
- synchronized(lock)
- {
- final Thread currentThread = Thread.currentThread() ;
- if (currentThread != lockingThread)
- {
- throw new IllegalStateException("Unlock called from wrong thread. Locking thread: " + lockingThread +
- ", current thread: " + currentThread) ;
- }
-
- if (--lockCount == 0)
- {
- lockingThread = null ;
- lock.notify() ;
- }
- }
- }
- }
-}
Modified: labs/jbosstm/trunk/atsintegration/classes/com/arjuna/ats/jbossatx/jta/TransactionManagerDelegate.java
===================================================================
--- labs/jbosstm/trunk/atsintegration/classes/com/arjuna/ats/jbossatx/jta/TransactionManagerDelegate.java 2008-02-07 13:31:56 UTC (rev 18373)
+++ labs/jbosstm/trunk/atsintegration/classes/com/arjuna/ats/jbossatx/jta/TransactionManagerDelegate.java 2008-02-07 13:38:53 UTC (rev 18374)
@@ -21,8 +21,6 @@
package com.arjuna.ats.jbossatx.jta;
import java.util.Hashtable;
-import java.util.Map;
-import java.util.HashMap;
import javax.naming.Context;
import javax.naming.Name;
@@ -30,15 +28,11 @@
import javax.transaction.RollbackException;
import javax.transaction.Status;
import javax.transaction.SystemException;
-import javax.transaction.Transaction;
import com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionManagerImple;
-import com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionImple;
import com.arjuna.ats.jbossatx.BaseTransactionManagerDelegate;
import com.arjuna.ats.jbossatx.logging.jbossatxLogger;
-import org.jboss.tm.TransactionLocal;
-
public class TransactionManagerDelegate extends BaseTransactionManagerDelegate implements ObjectFactory
{
/**
@@ -120,229 +114,4 @@
{
return TRANSACTION_MANAGER ;
}
-
-
- /////////////////////////
-
- // TransactionLocalDelegate implementation methods. This part is basically
- // stateless, we just delegate down to the object storage on the TransactionImple
-
- // Note this has some interesting effects around Transaction termination. The TransactionImple instance
- // lifetime is up to tx termination only. After that getTransaction() on the tm returns a new instance
- // representing the same tx. Hence TransactionLocal state goes away magically at tx termination time
- // since it's part of the TransactionImple instance. That's what we want and saves writing cleanup code.
- // On the down side, since locks use the same storage they go away too. This causes us to have to
- // jump through some hoops to deal with locks vanishing and maybe never getting unlocked, see below.
-
- /**
- * Does the specified transaction contain a value for the transaction local.
- *
- * @param transactionLocal The associated transaction local.
- * @param transaction The associated transaction.
- * @return true if a value exists within the specified transaction, false otherwise.
- */
- public boolean containsValue(final TransactionLocal transactionLocal, final Transaction transaction) {
- TransactionImple transactionImple = (TransactionImple) transaction;
- if(transactionImple.isAlive()) {
- return (transactionImple.getTxLocalResource(transactionLocal) != null ? true : false);
- } else {
- return false;
- }
- }
-
- /**
- * Get value of the transaction local in the specified transaction.
- *
- * @param transactionLocal The associated transaction local.
- * @param transaction The associated transaction.
- * @return The value of the transaction local.
- */
- public Object getValue(final TransactionLocal transactionLocal, final Transaction transaction) {
- TransactionImple transactionImple = (TransactionImple) transaction;
- if(transactionImple.isAlive()) {
- return transactionImple.getTxLocalResource(transactionLocal);
- } else {
- return null;
- }
- }
-
- /**
- * Store the value of the transaction local in the specified transaction.
- *
- * @param transactionLocal The associated transaction local.
- * @param transaction The associated transaction.
- * @param value The value of the transaction local.
- */
- public void storeValue(final TransactionLocal transactionLocal, final Transaction transaction,
- final Object value) {
- TransactionImple transactionImple = (TransactionImple) transaction;
- if(transactionImple.isAlive()) {
- transactionImple.putTxLocalResource(transactionLocal, value);
- } else {
- throw new IllegalStateException("Can't store value in a TransactionLocal after the Transaction has ended");
- }
- }
-
- /**
- * Lock the transaction local in the context of this transaction.
- *
- * @throws IllegalStateException if the transaction is not active
- * @throws InterruptedException if the thread is interrupted
- */
- public void lock(final TransactionLocal local, final Transaction transaction)
- throws InterruptedException {
- TransactionImple transactionImple = (TransactionImple) transaction;
- if(transactionImple.isAlive()) {
- // There is a race here, as the transaction may terminate between the check
- // and the lock attempt. See lock() implementation below.
- // It's still possible to lock a dead transaction, but that does no real harm.
- TransactionLocalLock lock = findLock(local, transaction);
- if(lock.lock(transactionImple)) {
- return;
- }
- }
-
- throw new IllegalStateException("Can't lock a TransactionLocal after the Transaction has ended");
- }
-
- /**
- * Unlock the transaction local in the context of this transaction
- */
- public void unlock(final TransactionLocal local, final Transaction transaction) {
- TransactionLocalLock lock = findLock(local, transaction);
- lock.unlock();
- }
-
- // Lock implementation: This used to use a Synchronization for lock storage, but
- // we need to be able to lock things in some states where registration of
- // Synchronizations is not permitted. Besides, the JTA 1.1 work gives us a nice
- // general object storage mechanism on a TransactionImple, so we use that.
-
- // This is the key under which the map of TransactionLocals to locks is stored.
- // Bad things will probably happen if users ever use this key themselves
- private final String LOCKS_MAP = "__LOCKS_MAP";
-
- // locate and return the lock for a given TransactionLocal+Transaction tuple.
- // create it if it does not exist.
- private TransactionLocalLock findLock(final TransactionLocal local, final Transaction transaction) {
-
- TransactionImple transactionImple = (TransactionImple) transaction;
- Map locks; // <TransactionLocal, TransactionLocalLock>
- // ideally for performance we should sync on the tx instance itself but that may have nasty
- // side effects so we use something else as the lock object for the sync block
- synchronized (LOCKS_MAP) {
- // ensure there is a holder for lock storage on the given tx instance.
- locks = (Map) transactionImple.getTxLocalResource(LOCKS_MAP);
- if (locks == null) {
- locks = new HashMap(); // <TransactionLocal, TransactionLocalLock>
- transactionImple.putTxLocalResource(LOCKS_MAP, locks);
- }
- }
-
- TransactionLocalLock transactionLocalLock;
- synchronized (locks) {
- // ensure there is a lock for the specified local+tx tuple
- transactionLocalLock = (TransactionLocalLock)locks.get(local);
- if (transactionLocalLock == null) {
- transactionLocalLock = new TransactionLocalLock();
- locks.put(local, transactionLocalLock);
- }
- }
-
- return transactionLocalLock;
- }
-
- // A class for the storage of individual lock state:
-
- private class TransactionLocalLock
- {
- /**
- * The locking thread.
- */
- private Thread lockingThread ;
- /**
- * The lock count.
- */
- private int lockCount ;
- /**
- * The lock.
- */
- private byte[] lock = new byte[0] ;
-
- /**
- * Lock the transaction local within the current thread context.
- * true on lock acquired, false otherwise
- */
- public boolean lock(TransactionImple tx)
- {
- // The current code in the app server locks the transaction for all, we follow that practice
- synchronized(lock)
- {
- final Thread currentThread = Thread.currentThread() ;
- if (currentThread == lockingThread)
- {
- lockCount++ ;
- return true;
- }
-
- while (lockingThread != null)
- {
- try
- {
- // lock object instances get thrown away at Transaction termination. That makes it impossible
- // to call unlock() on them. Searching through them and unlocking them from the transaction
- // termination code is a pain and finalizers suck.
- // Hence we need to make sure we don't wait forever for a notify
- // that will never come. Probably the only thing that will terminate a Transaction in another
- // Thread is the transaction reaper, so we wait not longer than the tx timeout plus a fudge factor.
- long timeout = 0;
- try {
- timeout = getTransactionTimeout();
- } catch(SystemException e) {}
-
- lock.wait(timeout+1000);
- if(!tx.isAlive()) {
- // transaction is dead, can't be locked, cleanup
- lockingThread = null;
- lockCount = 0;
- return false;
- }
- }
- catch (final InterruptedException ie) {}
- }
-
- lockingThread = currentThread ;
- lockCount ++ ;
- return true;
- }
- }
-
- /**
- * Unlock the transaction local within the current thread context.
- */
- public void unlock()
- {
- synchronized(lock)
- {
- if(lockCount == 0 && lockingThread == null) {
- // the lock was probably reset by a transaction termination.
- // we fail silent to save the caller having to deal with race condition.
- return;
- }
-
- final Thread currentThread = Thread.currentThread() ;
- if (currentThread != lockingThread)
- {
- throw new IllegalStateException("Unlock called from wrong thread. Locking thread: " + lockingThread +
- ", current thread: " + currentThread) ;
- }
-
- if (--lockCount == 0)
- {
- lockingThread = null ;
- lock.notify() ;
- }
- }
- }
- }
}
Modified: labs/jbosstm/trunk/atsintegration/classes/com/arjuna/ats/jbossatx/jts/TransactionManagerService.java
===================================================================
--- labs/jbosstm/trunk/atsintegration/classes/com/arjuna/ats/jbossatx/jts/TransactionManagerService.java 2008-02-07 13:31:56 UTC (rev 18373)
+++ labs/jbosstm/trunk/atsintegration/classes/com/arjuna/ats/jbossatx/jts/TransactionManagerService.java 2008-02-07 13:38:53 UTC (rev 18374)
@@ -41,6 +41,7 @@
import com.arjuna.ats.internal.jbossatx.jts.jca.XATerminator;
import com.arjuna.ats.internal.jbossatx.agent.LocalJBossAgentImpl;
import com.arjuna.ats.internal.jta.transaction.jts.UserTransactionImple;
+import com.arjuna.ats.internal.jta.transaction.jts.TransactionSynchronizationRegistryImple;
import com.arjuna.ats.jta.utils.JNDIManager;
import com.arjuna.ats.jta.common.Environment;
import com.arjuna.ats.jta.common.jtaPropertyManager;
@@ -123,7 +124,7 @@
{
started = true ;
}
-
+
ORB orb = null;
this.getLog().info("JBossTS Transaction Service - JBoss Inc.");
@@ -135,7 +136,7 @@
System.setProperty(com.arjuna.ats.tsmx.TransactionServiceMX.AGENT_IMPLEMENTATION_PROPERTY,
com.arjuna.ats.internal.jbossatx.agent.LocalJBossAgentImpl.class.getName());
System.setProperty(Environment.LAST_RESOURCE_OPTIMISATION_INTERFACE, LastResource.class.getName()) ;
-
+
final String alwaysPropagateProperty = alwaysPropagateContext ? "YES" : "NO" ;
System.setProperty(com.arjuna.ats.jts.common.Environment.ALWAYS_PROPAGATE_CONTEXT, alwaysPropagateProperty);
@@ -144,7 +145,7 @@
// Associate transaction reaper with our context classloader.
TransactionReaper.create() ;
-
+
/** Register propagation context manager **/
try
{
@@ -206,13 +207,19 @@
throw e;
}
- /** Bind the transaction manager JNDI reference **/
+ /** Bind the transaction manager and tsr JNDI reference **/
this.getLog().info("Binding TransactionManager JNDI Reference");
jtaPropertyManager.propertyManager.setProperty(Environment.JTA_TM_IMPLEMENTATION, TransactionManagerDelegate.class.getName());
jtaPropertyManager.propertyManager.setProperty(Environment.JTA_UT_IMPLEMENTATION, UserTransactionImple.class.getName());
+ jtaPropertyManager.propertyManager.setProperty(Environment.JTA_TSR_IMPLEMENTATION, TransactionSynchronizationRegistryImple.class.getName());
+ // When running inside the app server, we bind TSR in the JNDI java:/ space, not its required location.
+ // It's the job of individual components (EJB3, web, etc) to copy the ref to the java:/comp space)
+ jtaPropertyManager.propertyManager.setProperty(Environment.TSR_JNDI_CONTEXT, "java:/TransactionSynchronizationRegistry");
+
JNDIManager.bindJTATransactionManagerImplementation();
+ JNDIManager.bindJTATransactionSynchronizationRegistryImplementation();
}
/**
@@ -316,7 +323,7 @@
*
* @param timeout The default timeout in seconds for all transactions created
* using this transaction manager.
- *
+ *
* @throws IllegalStateException if the mbean has already started.
*/
public void setTransactionTimeout(int timeout) throws IllegalStateException
@@ -337,8 +344,8 @@
}
}
}
-
+
/**
* Get the default transaction timeout used by this transaction manager.
*
@@ -480,7 +487,7 @@
* JBoss. If this is false the Recovery Manager is already expected to
* be running when JBoss starts.
* @param runRM
- *
+ *
* @throws IllegalStateException If the MBean has already started.
*/
public void setRunInVMRecoveryManager(boolean runRM)
@@ -506,7 +513,7 @@
* Get whether the recovery manager should be ran in the same VM as
* JBoss. If this is false the Recovery Manager is already expected to
* be running when JBoss starts.
- *
+ *
* @return true if the recover manager is running in the same VM, false otherwise.
*/
public boolean getRunInVMRecoveryManager()
@@ -516,11 +523,11 @@
return _runRM ;
}
}
-
+
/**
* Set the object store directory.
* @param objectStoreDir The object store directory.
- *
+ *
* @throws IllegalStateException if the MBean has already started
*/
public void setObjectStoreDir(final String objectStoreDir)
@@ -543,7 +550,7 @@
}
}
}
-
+
/**
* Get the object store directory.
* @return objectStoreDir The object store directory.
@@ -574,7 +581,7 @@
/**
* Set the flag indicating whether the propagation context should always be propagated.
* @param alwaysPropagateContext true if the context should always be propagated, false if only propagated to OTS transactional objects.
- *
+ *
* @throws IllegalStateException If the MBean has already started.
*/
public void setAlwaysPropagateContext(final boolean alwaysPropagateContext)
More information about the jboss-svn-commits
mailing list