1 Reply Latest reply on Oct 16, 2012 8:47 PM by ybxiang.china

    Why Application Exception thrown in server-side interceptor is wrapped by EJB container?

    ybxiang.china

      Dear guys,

       

       

      I defined three application exceptions and an Intercepter in server side:

       

      *************************************[1][ApplicationException][begin]*************************************

      import javax.ejb.ApplicationException;
      @ApplicationException(rollback=true)
      public class NotExistingSessionTokenException extends Exception {    
          private static final long serialVersionUID = 1L;
          public static final NotExistingSessionTokenException INSTANCE;
          static {
              INSTANCE = new NotExistingSessionTokenException();
          }
          private static final String MSG = "Fake Session ";
          private NotExistingSessionTokenException() {
              super(MSG);
          }
      }
      
      
      
      import javax.ejb.ApplicationException;
      @ApplicationException(rollback=true)
      public class NullSessionTokenException extends Exception {    
          private static final long serialVersionUID = 1L; 
          public static final NullSessionTokenException INSTANCE;
          static {
              INSTANCE = new NullSessionTokenException();
          } 
          private static final String MSG = "Null Session Token"; 
          private NullSessionTokenException() {
              super(MSG);
          }
      }
      
      
      
      import javax.ejb.ApplicationException;
      @ApplicationException(rollback=true)
      public class PasswordExpiredException extends Exception {
          private static final long serialVersionUID = 1L; 
          public static final PasswordExpiredException INSTANCE;
          static {
              INSTANCE = new PasswordExpiredException();
          } 
          private static final String MSG = "Password Expired"; 
          private PasswordExpiredException() {
              super(MSG);
          }
      }
      
      
      

      *************************************[1][ApplicationException][end]*************************************

       

       

       

       

       

       

       

       

       

      *************************************[2][Interceptor][begin]*************************************

      public class SessionTokenInterceptor {
          Logger log = Logger.getLogger(SessionTokenInterceptor.class);
      
          @PersistenceContext
          protected EntityManager em;
      
          @Resource
          private EJBContext ejbContext;
      
          @AroundInvoke
          public Object processSessionToken(final InvocationContext invocationContext) throws Exception{
              //1. session token
              //log.info("retrieve SESSION TOKEN from invocation context instead of ejbContext");
              String sessionToken = (String)invocationContext.getContextData().get(ServerClientSharedConstants.SESSION_TOKEN_KEY);
              //log.debug("SESSION_TOKEN:"+sessionToken);//good!
      
              //2. JAAS username
              //log.info("retrieve JAAS username");
              String username = ejbContext.getCallerPrincipal().getName();//JAAS username
      
              //3. check
              if(sessionToken==null){
                  log.error("User["+username+"] has no SESSION TOKEN, so is NOT allowed to do more in this system.");
                  throw NullSessionTokenException.INSTANCE;
              }
              if(! isSessionTokenExisting(sessionToken)){
                  log.error("User["+username+"] is using invalid SESSION TOKEN, so is NOT allowed to do more in this system.");
                  throw NotExistingSessionTokenException.INSTANCE;
              }
      
              //4. call original method and return its result so that other interceptor can continue
              try{
                   return invocationContext.proceed();
              }finally{
              }
          }
      }
      

       

       

      NullSessionTokenException or NotExistingSessionTokenException will be thrown in this interceptor if necessary.

       

      *************************************[2][Interceptor][end]*************************************

       

       

       

       

       

       

       

       

      I use the SessionTokenInterceptor on my session bean:

       

      @Remote(ISecuredRemoteSession.class)
      @Stateless
      @DeclareRoles("admin")
      @Interceptors({SessionTokenInterceptor.class}) 
      public class SecuredRemoteSession implements ISecuredRemoteSession{
      ...
          @ExcludeClassInterceptors
          public String shakeHands() throws Exception{
              User user = getCurrentSessionUser();     
      
              log.info("Check if password is expired.");
              {
                  long passwordExpireMillis = nmsCoreService.getPasswordExpireDays() * 3600000L * 24L;
                  long diff = System.currentTimeMillis() - user.getLastChangePasswordDate().getTime();
                  if(diff > passwordExpireMillis){
                      throw PasswordExpiredException.INSTANCE;
                  }
              } 
      
              return generateNewSessionTokenForCurrentSessionUser();
          }
      ...
      }
      
      
      
      

       

       

       

       

       

       

       

       

       

      On client side, I try to catch those application exception( in a client interceptor),

      *************************************[3][client][Interceptor][begin]*************************************

      import java.lang.reflect.UndeclaredThrowableException;
      import org.apache.log4j.Logger;
      import org.eclipse.swt.widgets.Display;
      import org.jboss.ejb.client.EJBClientInterceptor;
      import org.jboss.ejb.client.EJBClientInvocationContext;
      
      import com.ybxiang.nms.common.exception.NotExistingSessionTokenException;
      
      public class ClientExceptionInterceptor implements EJBClientInterceptor{
          private final static Logger log = Logger.getLogger(ClientExceptionInterceptor.class);
      
          @Override
          public void handleInvocation(EJBClientInvocationContext context) throws Exception {
              context.sendRequest();
          }
      
          @Override
          public Object handleInvocationResult(EJBClientInvocationContext context) throws Exception {
              Object result = null;        try{
                  result = context.getResult();
              }catch(NotExistingSessionTokenException e){
                  log.error("NotExistingSessionTokenException is NOT catched!");//I hope the application exception can be caught here, but actually it is NOT caught here.
              }catch(javax.ejb.EJBException e){            
                  if(e.getCause() instanceof java.lang.reflect.UndeclaredThrowableException){
                      UndeclaredThrowableException cause = (UndeclaredThrowableException)e.getCause();
                      Throwable t = cause.getUndeclaredThrowable();
      
                      if(t instanceof NotExistingSessionTokenException){
                          log.error("NotExistingSessionTokenException is catched!");//The application exception is wrapped into EjbException and the EjbException  is caught here. This is NOT what I expect.
                      }else{
                          log.error("bla bla...);
                      }
                  }
                  else{
                  }
                  throw e;
              }catch(PasswordExpiredExceptione){
                  log.error("PasswordExpiredException:",e);
      
                  throw e;
              }catch(Exception e){
                  log.error("UNknown Exceptoin:",e);
      
                  throw e;
              }finally{
              }        
      
              return result;
          }
      }
      

      *************************************[3][client][Interceptor][end]*************************************

       

      If application exception is thrown from the session bean named SecuredRemoteSession, for example PasswordExpiredException,

                  the exception is NOT wrapped and the client can catch it correctly.

       

      If application exception is thrown from the server side Interceptor named SessionTokenInterceptor, for example NotExistingSessionTokenException,

                  the exception is wrapped into EjbException and the client can NOT catch the application exception directly.

                  This is NOT what I expect. I hope the application exception is NOT wrapped and thrown directly from EJB Container.

       

       

       

       

      Why Application Exception thrown in server-side interceptor is wrapped by EJB container?

       

      Thanks in advance.