public Object invoke(Invocation mi) throws Exception {
boolean trace = log.isTraceEnabled();
// The key
Object key = mi.getId();
// The context
EntityEnterpriseContext ctx;
try
{
ctx = (EntityEnterpriseContext) container.getInstanceCache().get(key);
}
catch (NoSuchObjectException e)
{
if (mi.isLocal())
throw new NoSuchObjectLocalException(e.getMessage());
else
throw e;
}
catch (EJBException e)
{
throw e;
}
catch (RemoteException e)
{
throw e;
}
catch (Exception e)
{
InvocationType type = mi.getType();
boolean isLocal = (type == InvocationType.LOCAL || type == InvocationType.LOCALHOME);
if (isLocal)
throw new EJBException("Unable to get an instance from the pool/cache", e);
else
throw new RemoteException("Unable to get an intance from the pool/cache", e);
}
if (trace) log.trace("Begin invoke, key=" + key);
// Associate transaction, in the new design the lock already has the transaction from the
// previous interceptor
// Don't set the transction if a read-only method. With a read-only method, the ctx can be shared
// between multiple transactions.
Transaction tx = mi.getTransaction();
if (!container.isReadOnly())
{
Method method = mi.getMethod();
if (method == null ||
!container.getBeanMetaData().isMethodReadOnly(method.getName()))
{
ctx.setTransaction(tx);
}
}
// Set the current security information
ctx.setPrincipal(mi.getPrincipal());
// Set the JACC EnterpriseBean PolicyContextHandler data
EnterpriseBeanPolicyContextHandler.setEnterpriseBean(ctx.getInstance());
// Set context on the method invocation
mi.setEnterpriseContext(ctx);
if (ejbTimeout.equals(mi.getMethod()))
AllowedOperationsAssociation.pushInMethodFlag(IN_EJB_TIMEOUT);
else
AllowedOperationsAssociation.pushInMethodFlag(IN_BUSINESS_METHOD);
Throwable exceptionThrown = null;
boolean discardContext = false;
try
{
Object obj = getNext().invoke(mi);
return obj;
}
catch (RemoteException e)
{
exceptionThrown = e;
discardContext = true;
throw e;
}
catch (RuntimeException e)
{
exceptionThrown = e;
discardContext = true;
throw e;
}
catch (Error e)
{
exceptionThrown = e;
discardContext = true;
throw e;
}
catch (Exception e)
{
exceptionThrown = e;
throw e;
}
catch (Throwable e)
{
exceptionThrown = e;
discardContext = true;
throw new NestedRuntimeException(e);
}
finally
{
AllowedOperationsAssociation.popInMethodFlag();
// Make sure we clear the transaction on an error before synchronization.
// But avoid a race with a transaction rollback on a synchronization
// that may have moved the context onto a different transaction
if (exceptionThrown != null && tx != null)
{
Transaction ctxTx = ctx.getTransaction();
if (tx.equals(ctxTx) && ctx.hasTxSynchronization() == false)
ctx.setTransaction(null);
}
// If an exception has been thrown,
if (exceptionThrown != null &&
// if tx, the ctx has been registered in an InstanceSynchronization.
// that will remove the context, so we shouldn't.
// if no synchronization then we need to do it by hand
// But not for application exceptions
!ctx.hasTxSynchronization() && discardContext)
{
// Discard instance
// EJB 1.1 spec 12.3.1
container.getInstanceCache().remove(key);
if (trace) log.trace("Ending invoke, exceptionThrown, ctx=" + ctx, exceptionThrown);
}
else if (ctx.getId() == null)
{
// The key from the Invocation still identifies the right cachekey
container.getInstanceCache().remove(key);
if (trace) log.trace("Ending invoke, cache removal, ctx=" + ctx);
// no more pool return
}
EnterpriseBeanPolicyContextHandler.setEnterpriseBean(null);
if (trace) log.trace("End invoke, key=" + key + ", ctx=" + ctx);
}// end finally
}
|