protected Object invokeNext(Invocation invocation,
boolean inheritedTx) throws Exception {
InvocationType type = invocation.getType();
try
{
if (type == InvocationType.REMOTE || type == InvocationType.LOCAL || type == InvocationType.SERVICE_ENDPOINT)
{
// register the Timer with the transaction
if (ejbTimeout.equals(invocation.getMethod()))
registerTimer(invocation);
return getNext().invoke(invocation);
}
else
{
return getNext().invokeHome(invocation);
}
}
catch (Throwable e)
{
// if this is an ApplicationException, just rethrow it
if (e instanceof Exception &&
!(e instanceof RuntimeException || e instanceof RemoteException))
{
throw (Exception) e;
}
// attempt to rollback the transaction
Transaction tx = invocation.getTransaction();
if (tx == null)
{
// Look for a hanging active user transaction that we should mark rollback
try
{
tx = tm.getTransaction();
if (TxUtils.isActive(tx) == false)
tx = null;
}
catch (Exception ex)
{
log.warn("Unable to determine transaction context", ex);
}
}
if (tx != null)
{
try
{
tx.setRollbackOnly();
}
catch (SystemException ex)
{
log.error("SystemException while setting transaction " +
"for rollback only", ex);
}
catch (IllegalStateException ex)
{
log.error("IllegalStateException while setting transaction " +
"for rollback only", ex);
}
}
// is this a local invocation
boolean isLocal =
type == InvocationType.LOCAL ||
type == InvocationType.LOCALHOME;
// if this transaction was NOT inherited from the caller we simply
// rethrow the exception, and LogInterceptor will handle
// all exception conversions.
if (!inheritedTx)
{
if (e instanceof Exception)
{
throw (Exception) e;
}
if (e instanceof Error)
{
throw (Error) e;
}
// we have some funky throwable, wrap it
if (isLocal)
{
String msg = formatException("Unexpected Throwable", e);
throw new EJBException(msg);
}
else
{
ServerException ex = new ServerException("Unexpected Throwable");
ex.detail = e;
throw ex;
}
}
// to be nice we coerce the execption to an interface friendly type
// before wrapping it with a transaction rolled back exception
Throwable cause;
if (e instanceof NoSuchEntityException)
{
NoSuchEntityException nsee = (NoSuchEntityException) e;
if (isLocal)
{
cause = new NoSuchObjectLocalException(nsee.getMessage(),
nsee.getCausedByException());
}
else
{
cause = new NoSuchObjectException(nsee.getMessage());
// set the detil of the exception
((NoSuchObjectException) cause).detail =
nsee.getCausedByException();
}
}
else
{
if (isLocal)
{
// local transaction rolled back exception can only wrap
// an exception so we create an EJBException for the cause
if (e instanceof Exception)
{
cause = e;
}
else if (e instanceof Error)
{
String msg = formatException("Unexpected Error", e);
cause = new EJBException(msg);
}
else
{
String msg = formatException("Unexpected Throwable", e);
cause = new EJBException(msg);
}
}
else
{
// remote transaction rolled back exception can wrap
// any throwable so we are ok
cause = e;
}
}
// We inherited tx: Tell caller we marked for rollback only.
if (isLocal)
{
if (cause instanceof TransactionRolledbackLocalException)
{
throw (TransactionRolledbackLocalException) cause;
}
else
{
throw new TransactionRolledbackLocalException(cause.getMessage(),
(Exception) cause);
}
}
else
{
if (cause instanceof TransactionRolledbackException)
{
throw (TransactionRolledbackException) cause;
}
else
{
TransactionRolledbackException ex =
new TransactionRolledbackException(cause.getMessage());
ex.detail = cause;
throw ex;
}
}
}
}
This method calls the next interceptor in the chain.
All Throwables are caught and divided into two groups: application
exceptions and system exceptions. Application exception are simply
rethrown. System exceptions result in the transaction being marked
for rollback only. If the transaction was not started by the container
(i.e., it was inherited from the client) the system exception is wrapped
in a TransactionRolledBack[Local]Exception. |