How to hide RuntimeException details from EJB client?
Question
I have a JEE5 application that exposes services using (local) session beans.
When an internal fault occurs during service execution, a RuntimeException is thrown and encapsulated by JBoss(5.0.1) in a javax.ejb.EJBTransactionRolledbackException.
The problem is that client applications receiving this EJBTransactionRolledbackException can access detailled informations about the cause runtime exception, exposing internal architecture of my application. And I don't want that.
Instead, I would like JBoss to always encapsulate RuntimeException thrown by exposed session beans into a single (and simple) TechnicalException (with no cause).
What's the best way to achieve this ? (Using interceptors ? Using JBoss configuration ?)
Solution
Finally, based on previous answer and my personal researches, I retained the folowing solution.
I've created an interceptor dedicated to manage server faults :
public class FaultBarrierInterceptor {
@AroundInvoke
public Object intercept(final InvocationContext invocationContext) throws Exception {
try {
return invocationContext.proceed();
} catch (final RuntimeException e) {
final Logger logger = Logger.getLogger(invocationContext.getMethod().getDeclaringClass());
logger.error("A fault occured during service invocation:" +
"\n-METHOD: " + invocationContext.getMethod() +
"\n-PARAMS: " + Arrays.toString(invocationContext.getParameters()), e);
throw new TechnicalException();
}
}}
The thrown technical exception extends EJBException and does not expose the cause RuntimeException:
public class TechnicalException extends EJBException {}
I use this interceptor in all public services :
@Stateless
@Interceptors({FaultBarrierInterceptor.class})
public class ShoppingCardServicesBean implements ShoppingCardServices { ...
This is an implementation of the Fault Barrier pattern.
Any runtime exception is catched, logged and a fault is signaled to the client (without internal details) using a TechnicalException. Checked exceptions are ignored.
RuntimeException handling is centralized and separated from any business methods.
OTHER TIPS
Any RuntimeException extends java.lang.Exception.
The EJB spec provides handling for 2 types of exceptions (Application and System)
If you'd like to throw a System Exception, you would usually do it like so:
try {
.... your code ...
}catch(YourApplicationException ae) {
throw ae;
}catch(Exception e) {
throw new EJBException(e); //here's where you need to change.
}
To hide the internal details of your system exception, simply replace:
throw new EJBException(e);
with:
throw new EJBException(new TechnicalException("Technical Fault"));
Hope this is what you were looking for.
Cheers