You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by mi...@apache.org on 2008/04/25 00:28:48 UTC

svn commit: r651441 - in /openjpa/trunk: openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/ openjpa-kernel/ openjpa-kernel/src/main/java/org/apache/openjpa/ee/ openjpa-kernel/src/main/resources/com/ openjpa-kernel/src/main/resources/com/ibm/ op...

Author: mikedd
Date: Thu Apr 24 15:28:42 2008
New Revision: 651441

URL: http://svn.apache.org/viewvc?rev=651441&view=rev
Log:
OPENJPA-149 OPENJPA-159 Moving suspendJTA code to ManagedRuntime

Added:
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ee/WASRegistryManagedRuntime.java   (with props)
    openjpa/trunk/openjpa-kernel/src/main/resources/com/
    openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/
    openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/license.txt   (with props)
    openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/websphere/
    openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/websphere/uow/
    openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/websphere/uow/UOWSynchronizationRegistry.class   (with props)
    openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/wsspi/
    openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/wsspi/uow/
    openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/wsspi/uow/UOWAction.class   (with props)
    openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/wsspi/uow/UOWActionException.class   (with props)
    openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/wsspi/uow/UOWException.class   (with props)
    openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/wsspi/uow/UOWManager.class   (with props)
    openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/wsspi/uow/UOWManagerFactory.class   (with props)
Modified:
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/AbstractJDBCSeq.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/TableJDBCSeq.java
    openjpa/trunk/openjpa-kernel/pom.xml
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ee/AbstractManagedRuntime.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ee/AutomaticManagedRuntime.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ee/ManagedRuntime.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ee/RegistryManagedRuntime.java
    openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/ee/localizer.properties
    openjpa/trunk/openjpa-kernel/src/test/java/org/apache/openjpa/ee/TestWASManagedRuntime.java
    openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/J2DoPrivHelper.java

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/AbstractJDBCSeq.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/AbstractJDBCSeq.java?rev=651441&r1=651440&r2=651441&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/AbstractJDBCSeq.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/AbstractJDBCSeq.java Thu Apr 24 15:28:42 2008
@@ -45,7 +45,6 @@
 
     protected int type = TYPE_DEFAULT;
     protected Object current = null;
-    private static ThreadLocal _outerTransaction = new ThreadLocal();
 
     /**
      * Records the sequence type.
@@ -144,24 +143,22 @@
     }
 
     /**
-     * Return the connection to use based on the type of sequence. This
-     * connection will automatically be closed; do not close it.
+     * <P>Return the connection to use based on the type of sequence. This
+     * connection will automatically be closed; do not close it.</P>
+     * 
+     * @return If the sequence type is <code>TYPE_TRANSACTIONAL</code> or 
+     * <code>TYPE_CONTIGUOUS</code> the connection from the {@link StoreManager}
+     * will be returned. 
+     * 
+     * <P>Otherwise a new connection will be obtained using DataSource2 from the 
+     * current configuration. In this case autocommit is set to false prior to 
+     * returning the connection.</P>
      */
     protected Connection getConnection(JDBCStore store)
         throws SQLException {
         if (type == TYPE_TRANSACTIONAL || type == TYPE_CONTIGUOUS)
             return store.getConnection();
-        else if (suspendInJTA()) {
-            try {
-                TransactionManager tm = getConfiguration()
-                    .getManagedRuntimeInstance().getTransactionManager();
-                _outerTransaction.set(tm.suspend());
-                tm.begin();
-                return store.getConnection();
-            } catch (Exception e) {
-                throw new StoreException(e);
-            }
-        } else {
+        else {
             JDBCConfiguration conf = store.getConfiguration();
             DataSource ds = conf.getDataSource2(store.getContext());
             Connection conn = ds.getConnection();
@@ -172,32 +169,18 @@
     }
 
     /**
-     * Close the current connection.
+     * Close the current connection. If the sequence is
+     * <code>TYPE_TRANSACTIONAL</code> or <code>TYPE_CONTIGUOUS</code>
+     * nothing will be done. Otherwise the connection will be closed.
      */
     protected void closeConnection(Connection conn) {
         if (conn == null)
             return;
-
         if (type == TYPE_TRANSACTIONAL || type == TYPE_CONTIGUOUS) {
             // do nothing; this seq is part of the business transaction
             return;
-        } else if (suspendInJTA()) {
-            try {
-                TransactionManager tm = getConfiguration()
-                    .getManagedRuntimeInstance().getTransactionManager();
-                tm.commit();
-                try { conn.close(); } catch (SQLException se) {}
-
-                Transaction outerTxn = (Transaction)_outerTransaction.get();
-                if (outerTxn != null)
-                    tm.resume(outerTxn);
-
-            } catch (Exception e) {
-                throw new StoreException(e);
-            } finally {
-                _outerTransaction.set(null);
-            }
-        } else {
+        }
+        else {
             try {
                 conn.commit();
             } catch (SQLException se) {

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/TableJDBCSeq.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/TableJDBCSeq.java?rev=651441&r1=651440&r2=651441&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/TableJDBCSeq.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/TableJDBCSeq.java Thu Apr 24 15:28:42 2008
@@ -26,6 +26,8 @@
 import java.sql.Types;
 import java.util.HashMap;
 
+import javax.transaction.NotSupportedException;
+
 import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
 import org.apache.openjpa.jdbc.conf.JDBCConfigurationImpl;
 import org.apache.openjpa.jdbc.meta.ClassMapping;
@@ -39,7 +41,6 @@
 import org.apache.openjpa.jdbc.sql.DBDictionary;
 import org.apache.openjpa.jdbc.sql.RowImpl;
 import org.apache.openjpa.jdbc.sql.SQLBuffer;
-import org.apache.openjpa.jdbc.sql.SQLExceptions;
 import org.apache.openjpa.lib.conf.Configurable;
 import org.apache.openjpa.lib.conf.Configuration;
 import org.apache.openjpa.lib.conf.Configurations;
@@ -79,7 +80,8 @@
     private transient Log _log = null;
     private int _alloc = 50;
     private int _intValue = 1;
-    private final HashMap _stat = new HashMap();
+    private final HashMap<ClassMapping, Status> _stat =
+        new HashMap<ClassMapping, Status>();
 
     private String _table = "OPENJPA_SEQUENCE_TABLE";
     private String _seqColumnName = "SEQUENCE_VALUE";
@@ -87,8 +89,7 @@
 
     private Column _seqColumn = null;
     private Column _pkColumn = null;
-    private int _schemasIdx = 0;    
-
+    
     /**
      * The sequence table name. Defaults to <code>OPENJPA_SEQUENCE_TABLE</code>.
      * By default, the table will be placed in the first schema listed in your
@@ -270,13 +271,19 @@
     protected Object currentInternal(JDBCStore store, ClassMapping mapping)
         throws Exception {
         if (current == null) {
-            Connection conn = getConnection(store);
+            CurrentSequenceRunnable runnable =
+                new CurrentSequenceRunnable(store, mapping);
             try {
-                long cur = getSequence(mapping, conn);
-                if (cur != -1)
-                    current = Numbers.valueOf(cur);
-            } finally {
-                closeConnection(conn);
+                if (suspendInJTA()) {
+                    // NotSupportedException is wrapped in a StoreException by
+                    // the caller.
+                    _conf.getManagedRuntimeInstance().doNonTransactionalWork(
+                            runnable);
+                } else {
+                    runnable.run();
+                }
+            } catch (RuntimeException re) {
+                throw (Exception) (re.getCause() == null ? re : re.getCause());
             }
         }
         return super.currentInternal(store, mapping);
@@ -311,7 +318,6 @@
             _stat.put(mapping, status);
         }
         return status;
-            
     }
 
     /**
@@ -361,50 +367,43 @@
      * Updates the max available sequence value.
      */
     private void allocateSequence(JDBCStore store, ClassMapping mapping,
-        Status stat, int alloc, boolean updateStatSeq) 
-        throws SQLException {
-        Connection conn = getConnection(store);
-        try { 
-            if (setSequence(mapping, stat, alloc, updateStatSeq, conn))
-                return;
-        } catch (SQLException se) {
-            throw SQLExceptions.getStore(_loc.get("bad-seq-up", _table),
-                se, _conf.getDBDictionaryInstance());
-        } finally {
-            closeConnection(conn);
-        }
-        
+            Status stat, int alloc, boolean updateStatSeq) throws SQLException {
+        Runnable runnable =
+            new AllocateSequenceRunnable(
+                    store, mapping, stat, alloc, updateStatSeq);
         try {
-            // possible that we might get errors when inserting if
-            // another thread/process is inserting same pk at same time
-            SQLException err = null; 
-            // ### why does this not call getConnection() / closeConnection()?
-            conn = _conf.getDataSource2(store.getContext()).getConnection();
-            try {
-                insertSequence(mapping, conn);
-            } catch (SQLException se) {
-                err = se;
-            } finally {
-                try { conn.close(); } catch (SQLException se) {}
-            }
-
-            // now we should be able to update...
-            conn = getConnection(store);
-            try {
-                if (!setSequence(mapping, stat, alloc, updateStatSeq, conn))
-                    throw (err != null) ? err : new SQLException(_loc.get
-                        ("no-seq-row", mapping, _table).getMessage());
-            } finally {
-                closeConnection(conn);
+            if (suspendInJTA()) {
+                // NotSupportedException is wrapped in a StoreException by
+                // the caller.
+                try {
+                _conf.getManagedRuntimeInstance().doNonTransactionalWork(
+                        runnable);
+                }
+                catch(NotSupportedException nse) { 
+                    SQLException sqlEx = new SQLException(nse.getLocalizedMessage());
+                    sqlEx.initCause(nse);
+                    throw sqlEx;
+                }
+            } else {
+                runnable.run();
             }
-        } catch (SQLException se2) {
-            throw SQLExceptions.getStore(_loc.get("bad-seq-up", _table),
-                se2, _conf.getDBDictionaryInstance());
-        } 
+        } catch (RuntimeException re) {
+            Throwable e = re.getCause();
+            if(e instanceof SQLException ) 
+                throw (SQLException) e;
+            else 
+                throw re;
+        }
     }
 
     /**
-     * Inserts the initial sequence information into the database, if any.
+     * Inserts the initial sequence column into the database.
+     * 
+     * @param mapping
+     *            ClassMapping for the class whose sequence column will be
+     *            updated
+     * @param conn
+     *            Connection used issue SQL statements.
      */
     private void insertSequence(ClassMapping mapping, Connection conn)
         throws SQLException {
@@ -442,7 +441,16 @@
     }
 
     /**
-     * Return the current sequence value, or -1 if unattainable.
+     * Get the current sequence value.
+     * 
+     * @param mapping
+     *            ClassMapping of the entity whose sequence value will be
+     *            obtained.
+     * @param conn
+     *            Connection used issue SQL statements.
+     * 
+     * @return The current sequence value, or <code>SEQUENCE_NOT_FOUND</code>
+     *         if the sequence could not be found.
      */
     protected long getSequence(ClassMapping mapping, Connection conn)
         throws SQLException {
@@ -736,5 +744,117 @@
         if (rs == null || !rs.next())
             return -1;
         return dict.getLong(rs, 1);
+    }
+
+    /**
+     * AllocateSequenceRunnable is a runnable wrapper that will inserts the
+     * initial sequence value into the database.
+     */
+    protected class AllocateSequenceRunnable implements Runnable {
+
+        JDBCStore store = null;
+        ClassMapping mapping = null;
+        Status stat = null;
+        int alloc;
+        boolean updateStatSeq;
+
+        AllocateSequenceRunnable(JDBCStore store, ClassMapping mapping,
+                Status stat, int alloc, boolean updateStatSeq) {
+            this.store = store;
+            this.mapping = mapping;
+            this.stat = stat;
+            this.alloc = alloc;
+            this.updateStatSeq = updateStatSeq;
+        }
+
+        /**
+         * This method actually obtains the current sequence value.
+         * 
+         * @throws RuntimeException
+         *             any SQLExceptions that occur when obtaining the sequence
+         *             value are wrapped in a runtime exception to avoid
+         *             breaking the Runnable method signature. The caller can
+         *             obtain the "real" exception by calling getCause().
+         */
+        public void run() throws RuntimeException {
+            Connection conn = null;
+            SQLException err = null;
+            try {
+                // Try to use the store's connection.
+                
+                conn = getConnection(store);  
+                boolean sequenceSet =
+                    setSequence(mapping, stat, alloc, updateStatSeq, conn);
+                closeConnection(conn);
+
+                if (!sequenceSet) {
+                    // insert a new sequence column. 
+                    // Prefer connection2 / non-jta-data-source when inserting 
+                    // a sequence column regardless of Seq.type.
+                    conn = _conf.getDataSource2(store.getContext())
+                                .getConnection();
+                    insertSequence(mapping, conn);
+                    conn.close();
+
+                    // now we should be able to update using the connection per
+                    // on the seq type.
+                    conn = getConnection(store);
+                    if (!setSequence(mapping, stat, alloc, updateStatSeq, conn))
+                    {
+                        throw (err != null) ? err : new SQLException(_loc.get(
+                                "no-seq-row", mapping, _table).getMessage());
+                    }
+                    closeConnection(conn);
+                }
+            } catch (SQLException e) {
+                if (conn != null) {
+                    closeConnection(conn);
+                }
+                RuntimeException re = new RuntimeException(e.getMessage());
+                re.initCause(e);
+                throw re;
+            }
+        }
+    }
+
+    /**
+     * CurentSequenceRunnable is a runnable wrapper which obtains the current
+     * sequence value from the database.
+     */
+    protected class CurrentSequenceRunnable implements Runnable {
+        private JDBCStore _store;
+        private ClassMapping _mapping;
+
+        CurrentSequenceRunnable(JDBCStore store, ClassMapping mapping) {
+            _store = store;
+            _mapping = mapping;
+        }
+
+        /**
+         * This method actually obtains the current sequence value.
+         * 
+         * @throws RuntimeException
+         *             any SQLExceptions that occur when obtaining the sequence
+         *             value are wrapped in a runtime exception to avoid
+         *             breaking the Runnable method signature. The caller can
+         *             obtain the "real" exception by calling getCause().
+         */
+        public void run() throws RuntimeException {
+            Connection conn = null;
+            try {
+                conn = getConnection(_store);
+                long cur = getSequence(_mapping, conn);
+                if (cur != -1 ) // USE the constant
+                    current = Numbers.valueOf(cur);
+            } catch (SQLException sqle) {
+                RuntimeException re = new RuntimeException(sqle.getMessage());
+                re.initCause(sqle);
+                throw re;
+            } finally {
+                if (conn != null) {
+                    closeConnection(conn);
+                }
+            }
+        }
     }
 }

Modified: openjpa/trunk/openjpa-kernel/pom.xml
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/pom.xml?rev=651441&r1=651440&r2=651441&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/pom.xml (original)
+++ openjpa/trunk/openjpa-kernel/pom.xml Thu Apr 24 15:28:42 2008
@@ -52,8 +52,8 @@
         <dependency>
             <groupId>commons-pool</groupId>
             <artifactId>commons-pool</artifactId>
-            <scope>compile</scope>
-        </dependency>
+            <scope>compile</scope>
+        </dependency>
     </dependencies>
     <build>
         <plugins>
@@ -142,6 +142,15 @@
 						</goals>
 					</execution>
                 </executions>
+            </plugin>
+            <plugin>
+                <artifactId>maven-jar-plugin</artifactId>
+                <version>2.2</version>
+                <configuration>
+                    <excludes>
+                        <exclude>**/com/ibm/**</exclude>
+                    </excludes>
+                </configuration>                
             </plugin>
         </plugins>
     </build>

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ee/AbstractManagedRuntime.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ee/AbstractManagedRuntime.java?rev=651441&r1=651440&r2=651441&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ee/AbstractManagedRuntime.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ee/AbstractManagedRuntime.java Thu Apr 24 15:28:42 2008
@@ -17,7 +17,14 @@
 
 package org.apache.openjpa.ee;
 
+import javax.transaction.InvalidTransactionException;
+import javax.transaction.NotSupportedException;
 import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+
+import org.apache.openjpa.lib.util.Localizer;
+import org.apache.openjpa.util.GeneralException;
 
 /*
  * AbstractManagedRuntime.java
@@ -26,7 +33,9 @@
  *
  */
 public abstract class AbstractManagedRuntime implements ManagedRuntime {
-    
+
+    private static Localizer _loc =
+        Localizer.forPackage(AbstractManagedRuntime.class);
     /**
      * Returns a transaction key that can be used to associate transactions
      * and Brokers.
@@ -38,4 +47,62 @@
         return getTransactionManager().getTransaction();
     }
 
+    /**
+     * <P>
+     * Do a unit of work which will execute outside of the current managed
+     * transaction. The default implementation suspends the transaction prior to
+     * execution, and resumes the transaction afterwards.
+     * </P>
+     * 
+     * @param runnable
+     *            The runnable wrapper for the work that will be done. The
+     *            runnable object should be fully initialized with any state
+     *            needed to execute.
+     * 
+     * @throws NotSupportedException
+     *            if the current transaction can not be obtained, or an error 
+     *            occurs when suspending or resuming the transaction.
+     */
+    public void doNonTransactionalWork(Runnable runnable) throws 
+            NotSupportedException {
+        TransactionManager tm = null;
+        Transaction transaction = null;
+        
+        try { 
+            tm = getTransactionManager(); 
+        }
+        catch(Exception e) {
+            NotSupportedException nse =
+                new NotSupportedException(e.getMessage());
+            nse.initCause(e);
+            throw nse;
+        }
+        try {
+            transaction = tm.suspend();
+        } catch (Exception e) {
+            NotSupportedException nse = new NotSupportedException(  
+                    _loc.get("exc-suspend-tran", e.getClass()).getMessage());
+            nse.initCause(e);
+            throw nse;
+        }
+        
+        runnable.run();
+        
+        try {
+            tm.resume(transaction);
+        } catch (Exception e) {
+            try {
+                transaction.setRollbackOnly();
+            }
+            catch(SystemException se2) {
+                throw new GeneralException(se2);
+            }
+            NotSupportedException nse =
+                new NotSupportedException(
+                        _loc.get("exc-resume-tran", e.getClass()).getMessage());
+            nse.initCause(e);
+            throw nse;
+        } 
+
+    }
 }

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ee/AutomaticManagedRuntime.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ee/AutomaticManagedRuntime.java?rev=651441&r1=651440&r2=651441&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ee/AutomaticManagedRuntime.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ee/AutomaticManagedRuntime.java Thu Apr 24 15:28:42 2008
@@ -21,11 +21,13 @@
 import java.util.LinkedList;
 import java.util.List;
 
+import javax.transaction.NotSupportedException;
 import javax.transaction.SystemException;
 import javax.transaction.TransactionManager;
 
 import org.apache.openjpa.lib.conf.Configurable;
 import org.apache.openjpa.lib.conf.Configuration;
+import org.apache.openjpa.lib.util.J2DoPrivHelper;
 import org.apache.openjpa.lib.util.Localizer;
 import org.apache.openjpa.util.InvalidStateException;
 
@@ -73,6 +75,7 @@
     private static final WLSManagedRuntime WLS;
     private static final SunOneManagedRuntime SUNONE;
     private static final WASManagedRuntime WAS;
+    private static final WASRegistryManagedRuntime WAS_REG;
 
     private static Localizer _loc = Localizer.forPackage
         (AutomaticManagedRuntime.class);
@@ -108,24 +111,57 @@
         mr = null;
         try {
             mr = new WASManagedRuntime();
+        } catch (Throwable t) {
         }
-        catch (Throwable t) {
+        WAS = (WASManagedRuntime) mr;
+
+        mr = null;
+        try {
+            // In a WebSphere environment the thread's current classloader might
+            // not have access to the WebSphere APIs. However the "runtime"
+            // classloader will have access to them.
+            
+            // Should not need a doPriv getting this class' classloader
+            ClassLoader cl = AutomaticManagedRuntime.class.getClassLoader();
+
+            Class<WASRegistryManagedRuntime> mrClass =
+                (Class<WASRegistryManagedRuntime>) J2DoPrivHelper
+                        .getForNameAction(
+                                WASRegistryManagedRuntime.class.getName(),
+                                true, cl).run();
+            mr = J2DoPrivHelper.newInstanceAction(mrClass).run();
+        } catch (Throwable t) {
+            // safe to ignore
         }
-        WAS= (WASManagedRuntime) mr;
+        WAS_REG = (WASRegistryManagedRuntime) mr;
     }
 
     private Configuration _conf = null;
     private ManagedRuntime _runtime = null;
-
+    
     public TransactionManager getTransactionManager()
         throws Exception {
         if (_runtime != null)
             return _runtime.getTransactionManager();
 
-        List errors = new LinkedList();
+        List<Throwable> errors = new LinkedList<Throwable>();
         TransactionManager tm = null;
 
-        // first try the registry, which is the official way to obtain
+        // Try the registry extensions first so that any applicable vendor
+        // specific extensions are used.
+        if (WAS_REG != null) {
+            try {
+                tm = WAS_REG.getTransactionManager();
+            } catch (Throwable t) {
+                errors.add(t);
+            }
+            if (tm != null) {
+                _runtime = WAS_REG;
+                return tm;
+            }
+        }
+
+        // Then try the registry, which is the official way to obtain
         // transaction synchronication in JTA 1.1
         if (REGISTRY != null) {
             try {
@@ -255,5 +291,24 @@
             return _runtime.getTransactionKey();
         
         return null;
+    }
+
+    /**
+     * Delegate nonTransactional work to the appropriate managed runtime. If no
+     * managed runtime is found then delegate {@link AbstractManagedRuntime}.
+     */
+    public void doNonTransactionalWork(Runnable runnable)
+            throws NotSupportedException {
+        // Obtain a transaction manager to initialize the runtime.
+        try {
+            getTransactionManager();
+        } catch (Exception e) {
+            NotSupportedException nse =
+                new NotSupportedException(_loc
+                        .get("tm-unavailable", _runtime).getMessage());
+            nse.initCause(e);
+            throw nse;
+        }
+        _runtime.doNonTransactionalWork(runnable);
     }
 }

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ee/ManagedRuntime.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ee/ManagedRuntime.java?rev=651441&r1=651440&r2=651441&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ee/ManagedRuntime.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ee/ManagedRuntime.java Thu Apr 24 15:28:42 2008
@@ -18,6 +18,7 @@
  */
 package org.apache.openjpa.ee;
 
+import javax.transaction.NotSupportedException;
 import javax.transaction.SystemException;
 import javax.transaction.TransactionManager;
 
@@ -65,5 +66,26 @@
      */
     public Object getTransactionKey()
         throws Exception, SystemException;
-    
+
+    /**
+     * <P>
+     * Do a unit of work which will execute outside of the current managed
+     * transaction.
+     * </P>
+     * <P>
+     * If the runnable object encounters an exception it should be wrapped in a
+     * RuntimeException and thrown back to the caller
+     * </P>
+     * 
+     * @param runnable
+     *            The runnable wrapper for the work that will be done. The
+     *            runnable object should be fully initialized with any state
+     *            needed to execute.
+     * 
+     * @throws NotSupportedException
+     *             if the transaction can not be suspended.
+     */
+    public void doNonTransactionalWork(Runnable runnable)
+            throws NotSupportedException;
+  
 }

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ee/RegistryManagedRuntime.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ee/RegistryManagedRuntime.java?rev=651441&r1=651440&r2=651441&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ee/RegistryManagedRuntime.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ee/RegistryManagedRuntime.java Thu Apr 24 15:28:42 2008
@@ -32,6 +32,8 @@
 import javax.transaction.TransactionSynchronizationRegistry;
 import javax.transaction.xa.XAResource;
 
+import org.apache.openjpa.lib.util.Localizer;
+
 /**
  * Implementation of the {@link ManagedRuntime} interface that uses 
  * the {@link TransactionSynchronizationRegistry} interface (new in JTA 1.1)
@@ -42,10 +44,12 @@
  */
 public class RegistryManagedRuntime
     implements ManagedRuntime {
-
     private String _registryName =
         "java:comp/TransactionSynchronizationRegistry";
     private TransactionManagerRegistryFacade _tm = null;
+    
+    private static Localizer _loc =
+        Localizer.forPackage(RegistryManagedRuntime.class);
 
     /**
      * Return the cached TransactionManager instance.
@@ -187,6 +191,16 @@
             throws RollbackException, IllegalStateException, SystemException {
             throw new SystemException();
         }
+    }
+    
+    /**
+     * <P>
+     * RegistryManagedRuntime cannot suspend transactions.
+     * </P>
+     */
+    public void doNonTransactionalWork(Runnable runnable) throws NotSupportedException {
+        throw new NotSupportedException(
+                _loc.get("tsr-cannot-suspend").getMessage());
     }
 }
 

Added: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ee/WASRegistryManagedRuntime.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ee/WASRegistryManagedRuntime.java?rev=651441&view=auto
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ee/WASRegistryManagedRuntime.java (added)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ee/WASRegistryManagedRuntime.java Thu Apr 24 15:28:42 2008
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+package org.apache.openjpa.ee;
+
+import com.ibm.wsspi.uow.UOWAction;
+import com.ibm.wsspi.uow.UOWActionException;
+import com.ibm.wsspi.uow.UOWException;
+import com.ibm.wsspi.uow.UOWManager;
+import com.ibm.wsspi.uow.UOWManagerFactory;
+
+/**
+ * WASRegistryManagedRuntime provides WebSphere specific extensions to
+ * {@link RegistryManagedRuntime}. Currently these extensions consist of using
+ * the WebSphere UOWManager interface to submit non transactional work.
+ */
+public class WASRegistryManagedRuntime extends RegistryManagedRuntime {
+    /**
+     * <P>
+     * RegistryManagedRuntime cannot suspend transactions, but WebSphere 
+     * provides an interface to submit work outside of the current tran.
+     * </P>
+     */
+    public void doNonTransactionalWork(Runnable runnable)
+            throws RuntimeException, UnsupportedOperationException {
+        try {
+            UOWManagerFactory.getUOWManager().runUnderUOW(
+                UOWManager.UOW_TYPE_LOCAL_TRANSACTION, false,
+                new DelegatingUOWAction(runnable));
+        }
+        catch(UOWActionException e ) {
+            RuntimeException re = new RuntimeException(e.getMessage());
+            re.initCause(e);
+            throw re;
+        }
+        catch(UOWException e ) {
+            RuntimeException re = new RuntimeException(e.getMessage());
+            re.initCause(e);
+            throw re;
+        }
+    }
+
+    
+    /**
+     * Delegate for the WebSphere proprietary UOWAction interface. Enables a 
+     * {$link Runnable} to be passed in to the WebSphere UOWManager.  
+     */
+    class DelegatingUOWAction implements UOWAction {
+        Runnable _del;
+
+        public DelegatingUOWAction(Runnable delegate) {
+            _del = delegate;
+        }
+
+        public void run() throws Exception {
+            _del.run();
+        }
+    }
+}

Propchange: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/ee/WASRegistryManagedRuntime.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/license.txt
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/license.txt?rev=651441&view=auto
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/license.txt (added)
+++ openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/license.txt Thu Apr 24 15:28:42 2008
@@ -0,0 +1,18 @@
+You may use or redistribute the files or modules contained in this jar subject to the following terms:  
+
+The WebSphere Application Server files or modules contained in this jar 
+may be redistrubuted as provided by IBM to you, and only as part of Your 
+application distribution.  
+
+You may not use IBM's name or trademarks in connection with the marketing 
+of Your applications without IBM's prior written consent.  
+
+IBM PROVIDES THESE FILES OR MODULES ON AN "AS IS" BASIS AND IBM DISCLAIMS 
+ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 
+WARRANTY OF NON-INFRINGEMENT AND THE IMPLIED WARRANTIES OF MERCHANTABILITY 
+OR FITNESS FOR A PARTICULAR PURPOSE.  IBM SHALL NOT BE LIABLE FOR ANY 
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT 
+OF THE USE OR OPERATION OF THE FILES OR MODULES .  IBM HAS NO OBLIGATION 
+TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR MODIFICATIONS TO 
+THE FILES OR MODULES .  
+

Propchange: openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/license.txt
------------------------------------------------------------------------------
    svn:eol-style = native

Added: openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/websphere/uow/UOWSynchronizationRegistry.class
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/websphere/uow/UOWSynchronizationRegistry.class?rev=651441&view=auto
==============================================================================
Binary file - no diff available.

Propchange: openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/websphere/uow/UOWSynchronizationRegistry.class
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/wsspi/uow/UOWAction.class
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/wsspi/uow/UOWAction.class?rev=651441&view=auto
==============================================================================
Binary file - no diff available.

Propchange: openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/wsspi/uow/UOWAction.class
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/wsspi/uow/UOWActionException.class
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/wsspi/uow/UOWActionException.class?rev=651441&view=auto
==============================================================================
Binary file - no diff available.

Propchange: openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/wsspi/uow/UOWActionException.class
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/wsspi/uow/UOWException.class
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/wsspi/uow/UOWException.class?rev=651441&view=auto
==============================================================================
Binary file - no diff available.

Propchange: openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/wsspi/uow/UOWException.class
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/wsspi/uow/UOWManager.class
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/wsspi/uow/UOWManager.class?rev=651441&view=auto
==============================================================================
Binary file - no diff available.

Propchange: openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/wsspi/uow/UOWManager.class
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/wsspi/uow/UOWManagerFactory.class
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/wsspi/uow/UOWManagerFactory.class?rev=651441&view=auto
==============================================================================
Binary file - no diff available.

Propchange: openjpa/trunk/openjpa-kernel/src/main/resources/com/ibm/wsspi/uow/UOWManagerFactory.class
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Modified: openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/ee/localizer.properties
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/ee/localizer.properties?rev=651441&r1=651440&r2=651441&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/ee/localizer.properties (original)
+++ openjpa/trunk/openjpa-kernel/src/main/resources/org/apache/openjpa/ee/localizer.properties Thu Apr 24 15:28:42 2008
@@ -18,19 +18,27 @@
 tm-not-found: Could not perform automatic lookup of EJB container''s \
 	javax.transaction.TransactionManager implementation. Please ensure that \
 	you are running the application from within an EJB 1.1 compliant EJB \
-	container, and then set the org.apache.openjpa.ManagedRuntime property to the \
-	appropriate value to obtain the TransactionManager.
+	container, and then set the org.apache.openjpa.ManagedRuntime property to \ 
+	the	appropriate value to obtain the TransactionManager.
 expected-reference: Expected object to be of type Reference, but instead was \
 	"{0}".
 not-supported: This operation is not supported.
 was-unsupported-op: Unable to execute {0} on a WebSphere managed transaction. \
 	WebSphere does not support direct manipulation of managed transactions.
-was-transaction-id-exception: Unable to determine identity of the current WebSphere \
-	managed transaction. Please ensure that your are running the application from \
-	within WebSphere Application Server (version 5.0.2 or newer).
+was-transaction-id-exception: Unable to determine identity of the current \ 
+	WebSphere managed transaction. Please ensure that your are running the \
+	application from within WebSphere Application Server (version 5.0.2 or \ 
+	newer).
 was-reflection-exception: An error occured reflecting WebSphere proprietary \
 	interfaces. Please ensure that you are running the application from within \
 	WebSphere Application Server (version 5.0.2 or newer).
 was-lookup-error: An error occurred looking up the WebSphere extended JTA \
-	service. Please ensure that you are running the application from within WebSphere \
-	Application Server (version 5.0.2 or newer).
+	service. Please ensure that you are running the application from within \ 
+	WebSphere Application Server (version 5.0.2 or newer).
+tm-unavailable: Unable to obtain a TransactionManager using {0}. 
+tsr-cannot-suspend: The Transaction Synchronization Registry can not suspend \
+	the current transaction. 
+exc-suspend-tran: A {0} exception occurred when trying to suspend the current \
+	transaction. 
+exc-resume-tran: A {0} exception occurred when trying to resume the current \
+	transaction. The transaction will be marked rollback only.
\ No newline at end of file

Modified: openjpa/trunk/openjpa-kernel/src/test/java/org/apache/openjpa/ee/TestWASManagedRuntime.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/test/java/org/apache/openjpa/ee/TestWASManagedRuntime.java?rev=651441&r1=651440&r2=651441&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/test/java/org/apache/openjpa/ee/TestWASManagedRuntime.java (original)
+++ openjpa/trunk/openjpa-kernel/src/test/java/org/apache/openjpa/ee/TestWASManagedRuntime.java Thu Apr 24 15:28:42 2008
@@ -36,7 +36,6 @@
      * been modified via the maven build.
      *
      * @throws ClassNotFoundException
-     * @author Michael Dick
      */
     public void testInterfaceAdded() throws ClassNotFoundException {
 

Modified: openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/J2DoPrivHelper.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/J2DoPrivHelper.java?rev=651441&r1=651440&r2=651441&view=diff
==============================================================================
--- openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/J2DoPrivHelper.java (original)
+++ openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/J2DoPrivHelper.java Thu Apr 24 15:28:42 2008
@@ -201,13 +201,13 @@
      * Requires security policy: 'permission java.lang.RuntimePermission
      * "getClassLoader";'
      * 
-     * @return Classloader
+     * @return Class
      */
-    public static final PrivilegedExceptionAction getForNameAction(
+    public static final PrivilegedExceptionAction<Class<?>> getForNameAction(
         final String className, final boolean initializeBoolean,
         final ClassLoader classLoader) {
-        return new PrivilegedExceptionAction() {
-            public Object run() throws ClassNotFoundException {
+        return new PrivilegedExceptionAction<Class<?>>() {
+            public Class<?> run() throws ClassNotFoundException {
                 return Class.forName(className, initializeBoolean, classLoader);
             }
         };
@@ -228,10 +228,10 @@
      *   
      * @return Classloader
      */
-    public static final PrivilegedAction getClassLoaderAction(
+    public static final PrivilegedAction<ClassLoader> getClassLoaderAction(
         final Class clazz) {
-        return new PrivilegedAction() {
-            public Object run() {
+        return new PrivilegedAction<ClassLoader>() {
+            public ClassLoader run() {
                 return clazz.getClassLoader();
             }
         };
@@ -330,21 +330,21 @@
      * Requires security policy:
      *   'permission java.lang.RuntimePermission "getClassLoader";'
      *   
-     * @return Object
-     * @exception IllegalAccessException
+     * @return A new instance of the provided class.
+     * @exception IllegalAccessException 
      * @exception InstantiationException
      */
-    public static final PrivilegedExceptionAction newInstanceAction(
-        final Class clazz) throws IllegalAccessException,
+    public static final <T> PrivilegedExceptionAction<T> newInstanceAction(
+        final Class<T> clazz) throws IllegalAccessException,
         InstantiationException {
-        return new PrivilegedExceptionAction() {
-            public Object run() throws IllegalAccessException,
+        return new PrivilegedExceptionAction<T>() {
+            public T run() throws IllegalAccessException,
                     InstantiationException {
                 return clazz.newInstance();
             }
         };
     }
-
+    
     /**
      * Return a PrivilegeAction object for loader.getParent().
      *