[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