views:

443

answers:

2

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 ?)

+1  A: 

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

Ryan Fernandes
A: 

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.

jruillier