2 Replies Latest reply on May 11, 2006 11:21 AM by pmuir

    Errorhandling with Interceptor. Advice needed.

    lcoetzee

      Hi all,

      I have been strugling quite some time to handle errors gracefully (these errors can include stuff like null pointers or entity not found). I have kept an eye out for good ways to handle errors but as yet have not found a good way ( I am aware of the current EJB3 rollback bugs: e.g. http://www.jboss.com/index.html?module=bb&op=viewtopic&t=82614)

      It is also something that we have discussed a bit on this forum: e.g.http://www.jboss.com/index.html?module=bb&op=viewtopic&t=76085
      as well as more recently.

      The following is the scheme I have tried but unfortunately it is not working as expected.

      1. I have created my own exception(note the rollback=false):

      .
      .
      @ApplicationException(rollback=false)
      public class NAPException extends Exception implements Serializable {
      
       /**
       *
       */
       private static final long serialVersionUID = -5617117494284445988L;
      
       public NAPException() {
       super();
       }
      
       public NAPException(String message) {
       super(message);
       }
      
      }


      2. I have made my business methods throw the above exception when catching another exception. In addition I have implemented an interceptor to handle this thrown exception.
      @IfNAPException(goToOutcome = "doErrorPage")
      public String handleLoadAllServices() throws NAPException {
      try {
      //do something here that can throw checked or unchecked exceptions
      //e.g not finding entity or get a NPE
      } catch (Exception e)
      throw new NAPException(e);
      }
      
      


      3. My annotation (annotate the method as well as class)

      
      @Target( { ElementType.METHOD, ElementType.TYPE })
      @Retention(RetentionPolicy.RUNTIME)
      @Interceptors(IfNAPExceptionInterceptor.class)
      public @interface IfNAPException {
       /**
       * The JSF outcome if the NAPException was thrown and handled
       */
       String goToOutcome() default "";
      }
      


      4. The interceptor

      @Around( { BijectionInterceptor.class, ValidationInterceptor.class,
       OutcomeInterceptor.class, BusinessProcessInterceptor.class })
      @Within(RemoveInterceptor.class)
      
      public class IfNAPExceptionInterceptor {
      
       private UserTransaction userTransaction;
      
       @In(create = true, required = true)
       private transient FacesMessages facesMessages;
      
       static final Logger logger = Logger
       .getLogger(IfNAPExceptionInterceptor.class);
      
       @AroundInvoke
       public Object customInterceptor(InvocationContext ctx) throws Exception {
      
       // logger.info("*** BEFORE INTERCEPTION ***");
       Object object = null;
       try {
       object = ctx.proceed();
       } catch (NAPException e) {
       if (shouldRollback()) {
       logger.error("Got NAPException in customInterceptor ");
       // Only handle the NAP exception if we have the annotation on
       // the method
       if (ctx.getMethod().isAnnotationPresent(IfNAPException.class)) {
       logger.error("Method has annotation. Will be handled");
       IfNAPException annotation = ctx.getMethod().getAnnotation(
       IfNAPException.class);
       object = annotation.goToOutcome();
       logger.info("Returning outcome: " + object);
       rollbackAfterException();
       redirect(annotation.goToOutcome(),
       e.getClass().toString()
       + " " + e.getMessage());
       }
       }
       }
       // logger.info("*** AFTER INTERCEPTION ***");
       return object;
       }
      
      private void rollbackAfterException() {
       try {
       if (Transactions.isTransactionActiveOrMarkedRollback()) {
      
       int status = Transactions.getUserTransaction().getStatus();
       if (status == Status.STATUS_MARKED_ROLLBACK) {
       logger.info("killing transaction");
       Transactions.getUserTransaction().rollback();
       }
       }
       } catch (Exception te) {
       logger.error("could not roll back transaction", te);
       }
       }
      
       private void redirect(String outcome, String errorMessage) {
       FacesContext facesContext = FacesContext.getCurrentInstance();
       facesContext.addMessage(null, new FacesMessage("An error occured: "
       + errorMessage));
       // add the error message
       facesContext.getApplication().getNavigationHandler().handleNavigation(
       facesContext, null, outcome);
       facesContext.responseComplete();
       }
      
       private boolean shouldRollback() throws Exception, NamingException {
       // int status = Transactions.getUserTransaction().getStatus();
       // return (status == Status.STATUS_MARKED_ROLLBACK);
       return Transactions.isTransactionActiveOrMarkedRollback();
       }
      
      


      I have three main problems:

      1. I cannot redirect to my outcome (as defined in my faces-config.xml) which points to an error page. I always end up at the page where I was.

      2. For some weird reason I cannot stop the interception process. The original method (throwing the exception )gets re-invoked .

      3. I havent got a clue as to where I should put this interceptor in the stack (Around/Within).

      Anyway, any suggestions as how to do error handling would be appreciated.

      Thanks

      Louis