(no commit message)
[utils] / test / enterprise / src / main / java / org / wamblee / test / persistence / JpaBuilder.java
index 331ea9a10390b11b88375b32dfbe714ce9e9f9e7..48556cfafcecf1f55690db0ff6b23a000fa788d2 100644 (file)
@@ -26,7 +26,10 @@ import javax.persistence.EntityTransaction;
 import javax.persistence.Persistence;
 import javax.persistence.PersistenceException;
 
+import org.wamblee.general.ThreadSpecificProxyFactory;
 import org.wamblee.test.jndi.StubInitialContextFactory;
+import org.wamblee.test.transactions.TransactionResource;
+import org.wamblee.test.transactions.TransactionResult;
 
 /**
  * Utility for building an appropriately configured EntityManagerFactory. The
@@ -37,7 +40,7 @@ import org.wamblee.test.jndi.StubInitialContextFactory;
  * The other purpose is to to shield dependencies of the test code on a
  * particular JPA provider.
  */
-public class JpaBuilder {
+public class JpaBuilder implements TransactionResource<EntityManager> {
 
     private static final Logger LOGGER = Logger.getLogger(JpaBuilder.class
         .getName());
@@ -60,26 +63,32 @@ public class JpaBuilder {
     }
 
     private PersistenceUnitDescription persistenceUnit;
-    private String url; 
-    private String user; 
-    private String password; 
+    private String url;
+    private String user;
+    private String password;
     private EntityManagerFactory factory;
+    private ThreadSpecificProxyFactory<EntityManager> entityManager;
 
     /**
      * Constructs the builder.
      * 
-     * @param aUrl JDBC URL
-     * @param aUser User name
-     * @param aPassword Password.
+     * @param aUrl
+     *            JDBC URL
+     * @param aUser
+     *            User name
+     * @param aPassword
+     *            Password.
      * @param aPersistenceUnit
      *            Persistence unit.
      */
     public JpaBuilder(String aUrl, String aUser, String aPassword,
         PersistenceUnitDescription aPersistenceUnit) {
         persistenceUnit = aPersistenceUnit;
-        url = aUrl; 
-        user = aUser; 
-        password = aPassword; 
+        url = aUrl;
+        user = aUser;
+        password = aPassword;
+        entityManager = new ThreadSpecificProxyFactory<EntityManager>(
+            EntityManager.class);
     }
 
     /**
@@ -117,7 +126,7 @@ public class JpaBuilder {
      */
     public EntityManagerFactory createFactory() {
         Map<String, String> jpaProps = new TreeMap<String, String>();
-        
+
         jpaProps.put("javax.persistence.jtaDataSource", null);
         jpaProps.put("javax.persistence.transactionType", "RESOURCE_LOCAL");
         jpaProps.put("javax.persistence.jdbc.url", url);
@@ -126,7 +135,7 @@ public class JpaBuilder {
 
         JpaCustomizerBuilder.getCustomizer().customize(persistenceUnit,
             jpaProps);
-        
+
         // jpaProps.put("javax.persistence.provider",
         // HibernatePersistence.class.getName());
         EntityManagerFactory emf = Persistence.createEntityManagerFactory(
@@ -142,24 +151,101 @@ public class JpaBuilder {
      * passing it the entity manager. Use of this method saves a lot of typing
      * for applications.
      * 
+     * This method requires the transaction to succeed. Otherwise the test will
+     * fail. See {@link #execute(JpaUnitOfWork, TransactionResultCallback)} and
+     * {@link RequireTransactionStatus} for more possibilities.
+     * 
      * @param aWork
      *            Work to execute.
+     * 
      * @return The return value of the execute method of the unit of work.
      */
     public <T> T execute(JpaUnitOfWork<T> aWork) throws Exception {
-        EntityManager em = factory.createEntityManager();
-        EntityTransaction transaction = em.getTransaction();
-        transaction.begin();
+        return execute(aWork, new RequireTransactionStatus(
+            TransactionResult.COMMIT));
+    }
+
+    /**
+     * Executes a unit of work. This creates an entitymanager and runs the
+     * {@link JpaUnitOfWork#execute(EntityManager)} within a transaction,
+     * passing it the entity manager. Use of this method saves a lot of typing
+     * for applications.
+     * 
+     * @param aWork
+     *            Work to execute.
+     * @param aTransactionResultCallback
+     *            callback to notify of the result of the transaction.
+     * 
+     * @return The return value of the execute method of the unit of work.
+     */
+    public <T> T execute(JpaUnitOfWork<T> aWork,
+        TransactionResultCallback aCallback) throws Exception {
+        EntityManager em = begin();
         try {
             T value = aWork.execute(em);
-            transaction.commit();
+            TransactionResult result = commit(em);
+            aCallback.status(result);
             return value;
         } catch (Exception e) {
             LOGGER.log(Level.WARNING, "Exception occured", e);
-            transaction.rollback();
+            TransactionResult result = rollback(em);
+            aCallback.status(result);
             throw e;
+        }
+    }
+
+    @Override
+    public EntityManager begin() {
+        EntityManager em = factory.createEntityManager();
+        EntityTransaction transaction = em.getTransaction();
+        transaction.begin();
+        entityManager.set(em);
+        return em;
+    }
+
+    @Override
+    public TransactionResult commit(EntityManager aEntityManager) {
+        try {
+            EntityTransaction transaction = aEntityManager.getTransaction();
+            if (transaction.isActive()) {
+                if (transaction.getRollbackOnly()) {
+                    transaction.rollback();
+                    return TransactionResult.ROLLBACK;
+                }
+                transaction.commit();
+                return TransactionResult.COMMIT;
+            }
+            return TransactionResult.UNKNOWN;
         } finally {
-            em.close();
+            aEntityManager.close();
+            entityManager.set(null);
         }
     }
+
+    @Override
+    public TransactionResult rollback(EntityManager aEntityManager) {
+        try {
+            EntityTransaction transaction = aEntityManager.getTransaction();
+            if (transaction.isActive()) {
+                transaction.rollback();
+                return TransactionResult.ROLLBACK;
+            }
+            return TransactionResult.UNKNOWN;
+        } finally {
+            if (aEntityManager.isOpen()) {
+                aEntityManager.close();
+            }
+            entityManager.set(null);
+        }
+    }
+
+    /**
+     * Gets a contextual reference to an entity manager that delegates to the
+     * appropriate (current) one which is active for the current transaction.
+     * 
+     * @return EntityManager.
+     */
+    public EntityManager getContextualEntityManager() {
+        return entityManager.getProxy();
+    }
 }