throws Exception
{
InstanceCache cache = container.getInstanceCache();
InstancePool pool = container.getInstancePool();
Object methodID = mi.getId();
EnterpriseContext ctx = null;
BeanLock lock = container.getLockManager().getLock(methodID);
boolean callerRunAsIdentityPresent = SecurityActions.peekRunAsIdentity() != null;
boolean pushSecurityContext = SecurityActions.getSecurityContext() == null;
try
{
/* The security context must be established before the cache
lookup because the activation of a session should have the caller's
security context as ejbActivate is allowed to call other secured
resources. Since the pm makes the ejbActivate call, we need to
set the caller's security context. The only reason this shows up for
stateful session is that we moved the SecurityInterceptor to after
the instance interceptor to allow security exceptions to result in
invalidation of the session. This may be too literal an interpretation
of the ejb spec requirement that runtime exceptions should invalidate
the session.
*/
if(!callerRunAsIdentityPresent && pushSecurityContext)
{
AuthenticationManager am = container.getSecurityManager();
String securityDomain = SecurityConstants.DEFAULT_APPLICATION_POLICY;
if(am != null)
securityDomain = am.getSecurityDomain();
SecurityActions.createAndSetSecurityContext(mi.getPrincipal(), mi.getCredential(),
securityDomain , null);
//SecurityActions.pushSubjectContext(mi.getPrincipal(), mi.getCredential(), null);
}
lock.sync();
try
{
// Get context
try
{
ctx = cache.get(methodID);
}
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);
}
// Associate it with the method invocation
mi.setEnterpriseContext(ctx);
// Set the JACC EnterpriseBean PolicyContextHandler data
EnterpriseBeanPolicyContextHandler.setEnterpriseBean(ctx.getInstance());
// BMT beans will lock and replace tx no matter what, CMT do work on transaction
boolean isBMT = ((SessionMetaData)container.getBeanMetaData()).isBeanManagedTx();
if (isBMT == false)
{
// Do we have a running transaction with the context
if (ctx.getTransaction() != null &&
// And are we trying to enter with another transaction
!ctx.getTransaction().equals(mi.getTransaction()))
{
// Calls must be in the same transaction
StringBuffer msg = new StringBuffer("Application Error: " +
"tried to enter Stateful bean with different tx context");
msg.append(", contextTx: " + ctx.getTransaction());
msg.append(", methodTx: " + mi.getTransaction());
throw new EJBException(msg.toString());
}
//If the instance will participate in a new transaction we register a sync for it
if (ctx.getTransaction() == null && mi.getTransaction() != null)
{
register(ctx, mi.getTransaction(), lock);
}
}
if (!ctx.isLocked())
{
//take it!
ctx.lock();
}
else
{
if (!isCallAllowed(mi))
{
// Concurent calls are not allowed
throw new EJBException("Application Error: no concurrent " +
"calls on stateful beans");
}
else
{
ctx.lock();
}
}
}
finally
{
lock.releaseSync();
}
// Set the current security information
/**
* JBAS-3976: Setting principal on the context has been moved to a separate interceptor
*/
if (ejbTimeout.equals(mi.getMethod()))
AllowedOperationsAssociation.pushInMethodFlag(IN_EJB_TIMEOUT);
else
AllowedOperationsAssociation.pushInMethodFlag(IN_BUSINESS_METHOD);
boolean validContext = true;
try
{
// Invoke through interceptors
Object ret = getNext().invoke(mi);
return ret;
}
catch (RemoteException e)
{
// Discard instance
cache.remove(methodID);
pool.discard(ctx);
validContext = false;
throw e;
}
catch (RuntimeException e)
{
// Discard instance
cache.remove(methodID);
pool.discard(ctx);
validContext = false;
throw e;
}
catch (Error e)
{
// Discard instance
cache.remove(methodID);
pool.discard(ctx);
validContext = false;
throw e;
}
finally
{
AllowedOperationsAssociation.popInMethodFlag();
if (validContext)
{
// Still a valid instance
lock.sync();
try
{
// release it
ctx.unlock();
// if removed, remove from cache
if (ctx.getId() == null)
{
// Remove from cache
cache.remove(methodID);
pool.free(ctx);
}