> What about when a container/interceptor itself throws an error,
> this still needs to reach the client as an ordinary
> RemoteException/EJBException.
>
This would be handled by the head interceptor or proxy - kind of:
try {
InvocationResult result = firstInterceptor.invoke()
if (result.wasNormal) {
return result.getResult();
} else if (result.wasApplicationException()) {
throw (Exception) result.getThrowable();
} else {
// convert system exception to EJB/Remote and throw
}
} catch (Throwable t) {
// problem raised by container
// convert to EJB/Remote and throw
}
> We returned exceptions rather than throwing them in OpenEJB at
> first, just as you're proposing. We eventually took it out
> simply because exceptions can still occur on the way back to the
> client. So you end up catching exceptions anyway, but now your
> code is split between try/catches and some if tests on the result
> object. Still works, but looks a little goofy.
Hmmm - goofy :-)
Right now we have (from StatelessInstanceInterceptor):
boolean threwSystemException = false;
try {
return getNext().invoke(invocation);
} catch (RuntimeException e) {
threwSystemException = true;
throw e;
} catch (RemoteException e) {
threwSystemException = true;
throw e;
} catch (Error e) {
threwSystemException = true;
throw e;
} finally {
// this invocation is done so remove the reference to the context
EJBInvocationUtil.putEnterpriseContext(invocation, null);
if (threwSystemException) {
// invocation threw a system exception so the pool
// needs to dispose of the context
pool.remove(ctx);
} else {
// return the context to the pool
pool.release(ctx);
}
}
which gets pretty tedious in dealing with the different exit conditions from
the invoke. It could become something like:
InvocationResult result = null;
try {
result = getNext().invoke(invocation);
} finally {
// this invocation is done so remove the reference to the context
EJBInvocationUtil.putEnterpriseContext(invocation, null);
if (result == null || result.wasSystemException()) {
// invocation threw a system exception so the pool
// needs to dispose of the context
pool.remove(ctx);
} else {
// return the context to the pool
pool.release(ctx);
}
}
which I think is a little less goofy (but not much).
>
> Actually, I don't see the need for an InvocationResult interface.
> Seems like it was added for just-in-case flexibility, but after
> years of existence it still isn't getting leveraged for anything.
> The RPCContainer interface of OpenEJB has been like this for
> years with no problems:
>
> Object invoke(<invocation data>) Exception
>
This was how JBoss did it too before 4.x when InvocationResult was
introduced. The reason it is there is to allow meta-values to be passed back
up the interceptor stack. For example, cluster state-change information (if
a node joined or left), read-ahead information for a finder; basically any
system data that could be useful in the next invocation.
--
Jeremy