*/
package org.wamblee.support.persistence;
+
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 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.
*
+ *
+ * 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.
*
*/
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;
.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);
// last resort.
throw new RuntimeException(e);
} finally {
- ENTITY_MANAGER.set(null);
+ ENTITY_MANAGER.set(oldEm);
}
}
});