org.jboss.ejb.plugins
public class: EntityReentranceInterceptor [javadoc |
source]
java.lang.Object
org.jboss.ejb.plugins.AbstractInterceptor
org.jboss.ejb.plugins.EntityReentranceInterceptor
All Implemented Interfaces:
Interceptor
The role of this interceptor is to check for reentrancy.
Per the spec, throw an exception if instance is not marked
as reentrant. We do not check to see if same Tx is
accessing object at the same time as we assume that
any transactional locks will handle this.
WARNING: critical code, get approval from senior developers
before changing.
- author:
< - a href="mailto:bill@burkecentral.com">Bill Burke
- version:
$ - Revision: 37459 $
| Field Summary |
|---|
| protected boolean | reentrant | |
| Methods from org.jboss.ejb.plugins.AbstractInterceptor: |
|---|
|
create, destroy, getContainer, getNext, invoke, invokeHome, isAppException, setContainer, setNext, start, stop |
| Method from org.jboss.ejb.plugins.EntityReentranceInterceptor Detail: |
public Object invoke(Invocation mi) throws Exception {
// We are going to work with the context a lot
EntityEnterpriseContext ctx = (EntityEnterpriseContext) mi.getEnterpriseContext();
boolean nonReentrant = !(reentrant || isReentrantMethod(mi));
// Not a reentrant method like getPrimaryKey
NonReentrantLock methodLock = ctx.getMethodLock();
Transaction miTx = ctx.getTransaction();
boolean locked = false;
try
{
while (!locked)
{
if (methodLock.attempt(5000, miTx, nonReentrant))
{
locked = true;
}
else
{
if (isTxExpired(miTx))
{
log.error("Saw rolled back tx=" + miTx);
throw new RuntimeException("Transaction marked for rollback, possibly a timeout");
}
}
}
}
catch (NonReentrantLock.ReentranceException re)
{
if (mi.getType() == InvocationType.REMOTE)
{
throw new RemoteException("Reentrant method call detected: "
+ container.getBeanMetaData().getEjbName() + " "
+ ctx.getId().toString());
}
else
{
throw new EJBException("Reentrant method call detected: "
+ container.getBeanMetaData().getEjbName() + " "
+ ctx.getId().toString());
}
}
try
{
ctx.lock();
return getNext().invoke(mi);
}
finally
{
ctx.unlock();
methodLock.release(nonReentrant);
}
}
|
protected boolean isReentrantMethod(Invocation mi) {
try
{
Class[] noArg = new Class[0];
getEJBHome = EJBObject.class.getMethod("getEJBHome", noArg);
getHandle = EJBObject.class.getMethod("getHandle", noArg);
getPrimaryKey = EJBObject.class.getMethod("getPrimaryKey", noArg);
isIdentical = EJBObject.class.getMethod("isIdentical", new Class[]{EJBObject.class});
remove = EJBObject.class.getMethod("remove", noArg);
}
catch (Exception e)
{
e.printStackTrace();
throw new ExceptionInInitializerError(e);
}
// is this a known non-entrant method
Method m = mi.getMethod();
if (m != null && (
m.equals(getEJBHome) ||
m.equals(getHandle) ||
m.equals(getPrimaryKey) ||
m.equals(isIdentical) ||
m.equals(remove)))
{
return true;
}
// if this is a non-entrant message to the container let it through
if (mi instanceof CMRInvocation)
{
Entrancy entrancy = ((CMRInvocation) mi).getEntrancy();
if (entrancy == Entrancy.NON_ENTRANT)
{
log.trace("NON_ENTRANT invocation");
return true;
}
}
return false;
}
|
protected boolean isTxExpired(Transaction miTx) throws Exception {
if (miTx != null && miTx.getStatus() == Status.STATUS_MARKED_ROLLBACK)
{
return true;
}
return false;
}
|
public void setContainer(Container container) {
// Public --------------------------------------------------------
super.setContainer(container);
if (container != null)
{
EntityMetaData meta = (EntityMetaData) container.getBeanMetaData();
reentrant = meta.isReentrant();
}
}
|