(no commit message)
[utils] / test / enterprise / src / main / java / org / wamblee / support / persistence / TransactionProxyFactory.java
index 4e72f4845d4a377b7075f62a11e0b8856b0e6783..548a3cdaebc1a8279ebaef779854807387925a99 100644 (file)
@@ -15,6 +15,7 @@
  */
 package org.wamblee.support.persistence;
 
+
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -27,10 +28,24 @@ import org.wamblee.support.persistence.JpaBuilder.JpaUnitOfWork;
 
 /**
  * This utility makes sure that each invocation on a certain interface is
- * carried out within a JPA unit of work.
+ * carried out within a JPA unit of work. Note that this is equivalent
+ * to the sementics of a requiresNew transaction attribute. 
+ * 
+ * Use {@link #getTransactionScopedEntityManager()} to get the transaction
+ * scoped entity manager to pass to services.
  * 
- * Use {@link #getTransactionScopedEntityManager()} to get the transaction scoped 
- * entity manager to pass to services. 
+ * 
+ * For example: 
+ * <pre>
+ *     JpaBuilder builder = ...
+ *     TransactionProxyFactory<Service> factory = new TransactionProxyFactory<Service>(
+ *           builder, Service.class);
+ *     Service service = new JpaService(factory.getTransactionScopedEntityManager());
+ *     Service proxy = factory.getProxy(service);
+ *     proxy.executeMethod(...); 
+ * </pre>
+ * The above example executes the executeMethod() call on the service object within an active transaction.
+ * In the constructor of the service a transaction scoped entity manager is passed.  
  * 
  * @param T
  *            Type of interface to proxy.
@@ -39,6 +54,13 @@ import org.wamblee.support.persistence.JpaBuilder.JpaUnitOfWork;
  */
 public class TransactionProxyFactory<T> {
 
+    /**
+     * Executes the call on the service within a new transaction.  
+     * 
+     * @author Erik Brakkee
+     *
+     * @param <T> Type of the service interface. 
+     */
     private class UnitOfWorkInvocationHandler<T> implements InvocationHandler {
 
         private T service;
@@ -54,13 +76,21 @@ public class TransactionProxyFactory<T> {
                 .execute(new JpaUnitOfWork<Object>() {
                     @Override
                     public Object execute(EntityManager aEm) throws Exception {
+                        EntityManager oldEm = ENTITY_MANAGER.get(); 
                         try {
                             ENTITY_MANAGER.set(aEm);
                             return aMethod.invoke(service, aArgs);
                         } catch (InvocationTargetException e) {
-                            throw (Exception)e.getCause();
-                        } finally { 
-                            ENTITY_MANAGER.set(null);
+                            Throwable cause = e.getCause();
+                            if (cause instanceof Exception) {
+                                throw (Exception) cause;
+                            } else if (cause instanceof Error) {
+                                throw (Error) cause;
+                            }
+                            // last resort.
+                            throw new RuntimeException(e);
+                        } finally {
+                            ENTITY_MANAGER.set(oldEm);
                         }
                     }
                 });
@@ -68,9 +98,9 @@ public class TransactionProxyFactory<T> {
 
     }
 
-    private static final ThreadSpecificProxyFactory<EntityManager> ENTITY_MANAGER = 
-        new ThreadSpecificProxyFactory<EntityManager>(EntityManager.class);
-    
+    private static final ThreadSpecificProxyFactory<EntityManager> ENTITY_MANAGER = new ThreadSpecificProxyFactory<EntityManager>(
+        EntityManager.class);
+
     private JpaBuilder jpaBuilder;
     private Class<T> clazz;
 
@@ -83,8 +113,8 @@ public class TransactionProxyFactory<T> {
         jpaBuilder = aJpaBuilder;
         clazz = aClass;
     }
-    
-    public EntityManager getTransactionScopedEntityManager() { 
+
+    public EntityManager getTransactionScopedEntityManager() {
         return ENTITY_MANAGER.getProxy();
     }
 
@@ -98,8 +128,9 @@ public class TransactionProxyFactory<T> {
                 new Class[] { InvocationHandler.class }).newInstance(
                 new Object[] { handler });
             return proxy;
-        } catch (Exception e) { 
-            throw new RuntimeException("Could not create proxy for " + clazz.getName(), e);
+        } catch (Exception e) {
+            throw new RuntimeException("Could not create proxy for " +
+                clazz.getName(), e);
         }
     }
 }