My JSF Books/Videos My JSF Tutorials OmniFaces/JSF PPTs
JSF 2.3 Tutorial
JSF Caching Tutorial
JSF Navigation Tutorial
JSF Scopes Tutorial
JSF Page Author Beginner's Guide
OmniFaces 2.3 Tutorial Examples
OmniFaces 2.2 Tutorial Examples
JSF Events Tutorial
OmniFaces Callbacks Usages
JSF State Tutorial
JSF and Design Patterns
JSF 2.3 New Features (2.3-m04)
Introduction to OmniFaces
25+ Reasons to use OmniFaces in JSF
OmniFaces Validators
OmniFaces Converters
JSF Design Patterns
Mastering OmniFaces
Reusable and less-verbose JSF code

My JSF Resources ...

Java EE Guardian
Member of JCG Program
Member MVB DZone
Blog curated on ZEEF
OmniFaces is an utility library for JSF, including PrimeFaces, RichFaces, ICEfaces ...

[OmniFaces Utilities] - Find the right JSF OmniFaces 2 utilities methods/functions

Search on blog

Petition by Java EE Guardians

Twitter

joi, 9 iunie 2016

Writing a custom exception handler

When an error occurs in a Java program it usually results in an exception being thrown. Java exception handling enables Java applications to handle errors and this is an important aspect in order to write robust and reliable Java applications or components. So, how we choose to throw, catch and handle these exceptions is always an aspect that we should carefully consider. JSF has its own system of treating exceptions. First it defines a super-exception, named FacesException. This class represents general JSF exceptions and usually when you get a FacesException, it wraps the real cause of the exception inside of it - for this we have FacesException#getCause(). As a note here, this is the reason for what OmniFaces comes with a set of utilities in its org.omnifaces.util.Exceptions class meant to provide general utility methods with respect to working with exceptions - for example, we can unwrap a caught FacesException until a non-FacesException is found. Beside the FacesException, JSF provides several sub-classes of it specially dedicated for some JSF common exceptions, such as AbortProcessingException, ConverterException, EvaluationException, FaceletException, ProtectedViewException, UpdateModelException, ValidatorException, ViewExpiredException. Probably, the most well known from here we have ConverterException, ValidatorException and ViewExpiredException.

Obviously, when an JSF application causes an exception, JSF is responsible for handle it. With other words, JSF decide how and what to do when an exception occurs. It decide if the exception must be thrown as it is, must be reported in a special case (e.g. with a custom message), must be simply ignored (swallowed) etc. Basically, the unhandled exceptions are queued via ExceptionQueuedEvent, and they are handled by an exception handler. For example, Oracle Mojarra implementation provide two handler exceptions, one is com.sun.faces.context.ExceptionHandlerImpl and another one is com.sun.faces.context.AjaxExceptionHandlerImpl. Basically, both of them (and any other exception handler) acts the same in two simple steps:

- override the handle() method
- iterate over the unhandled exceptions (one by one) and handle them accordingly

Note that OmniFaces comes with two exception handler implementations, FullAjaxExceptionHandler (handle exceptions occurred during a JSF AJAX request) and FacesMessageExceptionHandler (adds every exception as a global FATAL faces message). Both of them are dissected in detail in "Mastering OmniFaces" book.

Now, as you can see, we can have multiple exception handlers, so JSF has decide which one(s) to use? Here is where the ExceptionHandlerFactory enters in the scene. This class is responsible to serve instances of exception handlers. For example, in Oracle Mojarra the implementation of ExceptionHandlerFactory is com.sun.faces.context.ExceptionHandlerFactoryImpl. There is true that here we have a little trick in JSF, because since there are two exception handlers, JSF group them in com.sun.faces.context.AjaxNoAjaxExceptionHandler. It is a simple and very intuitive class, just check out its code line by line:

// Source code from Oracle Mojarra 2.2.9
package com.sun.faces.context;

import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerWrapper;
import javax.faces.context.FacesContext;

public class AjaxNoAjaxExceptionHandler extends ExceptionHandlerWrapper {
   
 private AjaxExceptionHandlerImpl ajaxExceptionHandlerImpl;
 private ExceptionHandlerImpl exceptionHandlerImpl;

 public AjaxNoAjaxExceptionHandler(AjaxExceptionHandlerImpl ajaxExceptionHandlerImpl,
                                          ExceptionHandlerImpl exceptionHandlerImpl) {
  this.ajaxExceptionHandlerImpl = ajaxExceptionHandlerImpl;
  this.exceptionHandlerImpl = exceptionHandlerImpl;
 }

 @Override
 public ExceptionHandler getWrapped() {
  FacesContext fc = FacesContext.getCurrentInstance();
  if (null != fc && fc.getPartialViewContext().isAjaxRequest()) {
      return ajaxExceptionHandlerImpl;
  }

  return exceptionHandlerImpl;       
 }       
}

And the ExceptionHandlerFactoryImpl uses like this:

// Source code from Oracle Mojarra 2.2.9
public ExceptionHandler getExceptionHandler() {
 FacesContext fc = FacesContext.getCurrentInstance();
 ApplicationAssociate myAssociate = getAssociate(fc);

 ExceptionHandler result = new AjaxNoAjaxExceptionHandler(
  new AjaxExceptionHandlerImpl(new ExceptionHandlerImpl(Boolean.TRUE)),
  new ExceptionHandlerImpl(((myAssociate != null) ? myAssociate.isErrorPagePresent() : Boolean.TRUE)));

 return result;
}

We also can have a quick look over the ExceptionHandlerImpl. Especially on the ExceptionHandlerImpl#handle()method:

// Source code from Oracle Mojarra 2.2.9
public void handle() throws FacesException {

 for (Iterator<ExceptionQueuedEvent> i = getUnhandledExceptionQueuedEvents().iterator(); i.hasNext(); ) {
      ExceptionQueuedEvent event = i.next();
      ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event.getSource();
      try {
          Throwable t = context.getException();
 ...
}
  
So, mainly if we think to write a custom exception handler, we have to think to the flow from figure below:

Here it is a custom exception handler factory:

public class CustomExceptionHandlerFactory extends ExceptionHandlerFactory {

 private ExceptionHandlerFactory exceptionHandlerFactory;

 public CustomExceptionHandlerFactory(){       
 }
   
 public CustomExceptionHandlerFactory(ExceptionHandlerFactory exceptionHandlerFactory) {
  this.exceptionHandlerFactory = exceptionHandlerFactory;
 }

 @Override
 public ExceptionHandler getExceptionHandler() {
  ExceptionHandler handler = new CustomExceptionHandler(exceptionHandlerFactory.getExceptionHandler());

  return handler;
 }
}

And, the custom exception handler skeleton is:

public class CustomExceptionHandler extends ExceptionHandlerWrapper {

 private static final Logger LOG = Logger.getLogger(CustomExceptionHandler.class.getName());

 private ExceptionHandler exceptionHandler;

 CustomExceptionHandler(ExceptionHandler exceptionHandler) {
  this.exceptionHandler = exceptionHandler;

  LOG.info("JSF uses the CustomExceptionHandler ...");
 }

 @Override
 public ExceptionHandler getWrapped() {
  return exceptionHandler;
 }

 @Override
 public void handle() throws FacesException {

  LOG.info("JSF invoked CustomExceptionHandler#handle() method ...");

  final Iterator<ExceptionQueuedEvent> queue = getUnhandledExceptionQueuedEvents().iterator();

  // If there's no unhandled exception simply return.
  if (!queue.hasNext()) {
      return;
  }

  /////////////////////////////////////
  // HANDLE THE FIRST EXCEPTION ONLY //
  /////////////////////////////////////
  Throwable throwable = queue.next().getContext().getException();

  // Handle the exception, throwable.
  LOG.log(Level.INFO, "Handling exception: {0}", throwable);

  // Let JSF handle exceptions of type AbortProcessingException.
  if (throwable instanceof AbortProcessingException) {
      return;
  }

  // Remove the exception from the queue.
  queue.remove();

  // in order to find the exception root cause, maybe use here
  // the org.omnifaces.util.Exceptions utilities such as:
  // Exceptions#is() or/and Exceptions#unwrap() methods
  //... HANDLE THE EXCEPTION ...
       
  // Remove all remaining exceptions if you want to fix only the first.
  while (queue.hasNext()) {
         queue.next();
         queue.remove();
  }

  // Give control to the default (or other) exception handler.
  getWrapped().handle();

  //////////////////////////////////////
  // HANDLE ALL OR A CERTAIN EXCEPTION //
  ///////////////////////////////////////
  while (queue.hasNext()) {
         ExceptionQueuedEvent item = queue.next();
         ExceptionQueuedEventContext exceptionQueuedEventContext = (ExceptionQueuedEventContext) item.getSource();

         // Get the excpetion from current iteration.
         Throwable throwable_item = exceptionQueuedEventContext.getException();

         // If you know that you want to handle all exceptions from queue
         // then you can remove the exception from this iteration from the queue.
         queue.remove();

         // Handle the exception at this iteration, throwable_item.
         LOG.log(Level.INFO, "Handling exception: {0}", throwable_item);

         // In order to find the exception root cause, maybe use here
         // the org.omnifaces.util.Exceptions utilities such as:
         // Exceptions#is() or/and Exceptions#unwrap() methods
         //...
         // If you want to handle a certain exception place here the conditions to
         // identify it. Also, remove from the queue only this exception
         // (pay attention to not remove unhandled exceptions, only if you intend to do so):
         queue.remove();
         //... HANDLE THE EXCEPTION OF THIS ITERATION ...
           
         // Eventually, if you don't want to handle more exception then break the loop.
         break;
  }

  // Give control to the default (or other) exception handler.
  getWrapped().handle();
 }
}

You can find this skeleton here.

Niciun comentariu :

Trimiteți un comentariu

JSF BOOKS COLLECTION

Postări populare

Follow by Email

Visitors Starting 4 September 2015

Locations of Site Visitors