package net.sourceforge.javautil.database.jpa;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.FlushModeType;
import javax.persistence.LockModeType;
import javax.persistence.Query;
import net.sourceforge.javautil.common.proxy.AbstractProxy;
/**
* This is a proxy for an {@link EntityManager} to make sure transactions are started on extended methods.
*
* @author elponderador
* @author $Author$
* @version $Id$
*/
public class EntityManagerExtendedHandler extends AbstractProxy {
/**
* @param em The extended entity manager
* @return A new proxy for using the extended manager
*/
public static <T extends IEntityManagerExtended, EM extends T> IEntityManagerExtended createEMProxy (T em, Class<T> iface) {
return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[] { iface }, new EntityManagerExtendedHandler(em));
}
protected final IEntityManagerExtended eme;
protected final UserTransactionSupport transaction;
private EntityManagerExtendedHandler(IEntityManagerExtended eme) {
this.eme = eme;
this.transaction = new UserTransactionSupport(eme);
}
@Override public synchronized Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
TransactionAttribute ta = method.getAnnotation(TransactionAttribute.class);
boolean auto = ta != null && (ta.value() == TransactionAttributeType.REQUIRES_NEW ||
ta.value() == TransactionAttributeType.REQUIRED || ta.value() == TransactionAttributeType.MANDATORY);
boolean began = false;
if (auto && !transaction.isActive()) {
began = true;
transaction.begin();
}
try {
return super.invoke(proxy, method, args);
} catch (Throwable t) {
if (transaction.isActive()) transaction.rollback();
throw t;
} finally {
if (auto && began && transaction.isActive()) {
transaction.commit();
}
}
}
@Override protected Object getTarget(Method method, Object[] args) { return eme; }
}