欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

The JSF 2.0 exception handling mechanism

程序员文章站 2022-07-15 16:12:11
...

《JSF 2.0 Cookbook》 http://www.packtpub.com/article/jsf-20-features

In this recipe we talk about the exception handling mechanism provided by JSF 2.0. You will see how to map exceptions to error pages in the web.xml file, how to use a managed bean for extracting an exception from the request and build a String from the stack trace, and how to customize the exception handling with a user-defined exception handler.

How to do it...

We start our recipe with the simplest solution for handling exceptions. It consists in mapping exception to error pages in the web.xml descriptor . For start we add in web.xml an entry for to define a JSF page as an error page (in our example, we define an error page named error.xhtml, mapped to the java.lang.NumberFormatException exception):

...
<error-page>
<exception-type>java.lang.NumberFormatException</exception-type>
<location>/faces/error.xhtml</location>
</error-page>

...

Now, JSF keeps track of a set of values in the request that provide more details on the error page. Next you can see one of these values edited in error.xhtml:

...
User Error:
#{requestScope['javax.servlet.error.message']}
...

Now, we can test the previous example by throwing a java.lang.NumberFormatException from a bean getter method, as shown next (when the error is thrown, the error.xhtml error page is getting into action):

...
private String number = "345s";
...
public String getNumber() {
try {
Integer intnumber = Integer.valueOf(this.number);
return String.valueOf(intnumber);
} catch (NumberFormatException e) {
throw new java.lang.NumberFormatException(e.getMessage());
}
}

public void setNumber(String number) {
this.number = number;
}
...

Going further, we can write a managed bean for extracting the exception from the request and building a String from the stack trace. You can see the action that does this job for us next:

...
private String error = "";
...
public String getError() {
StringBuilder errorMessage = new StringBuilder();
FacesContext facesContext = FacesContext.getCurrentInstance();
Map<String, Object> map =
facesContext.getExternalContext().getRequestMap();
Throwable throwable = (Throwable)
map.get("javax.servlet.error.exception");

if (throwable != null) {
errorMessage.append(throwable.getMessage()).append("\n");
for (StackTraceElement element : throwable.getStackTrace())
{
errorMessage.append(element).append("\n");
}
}
this.error = errorMessage.toString();
return this.error;
}
...

To get the stack trace we use the following code in the error.xhtml page:

...
System Administrator Error: <br/>
<h:outputText value="#{bean.error}"/>
...

You can go even further and customize the exception handling. Any custom exception handler should be defined in faces-config.xml, as in the following example:

...
<factory>
<exception-handler-factory>
exception.handler.CustomExceptionHandler
</exception-handler-factory>
</factory>
...

In the custom exception handler you should override the handle method to describe the behavior of your application in the case of a particular exception or set of exceptions. The prototype of this method is:

public void handle() throws FacesException {
...//do your job here
super.handle();
}

How it works...

Basically, in all three cases described previously, the idea is the same. The exceptions are caught by the system and they are treated according to our desires. We can provide a simple error page, or we can get much deeper and exploit the exception's stack trace and create large logs with detailed information for users or for administrators.

 

javax.faces.webapp.FacesServlet

public void service(ServletRequest req, ServletResponse resp)
        throws IOException, ServletException {

        ...

        // Acquire the FacesContext instance for this request
        FacesContext context = facesContextFactory.getFacesContext
              (servletConfig.getServletContext(), request, response, lifecycle);

        ....

}

 

com.sun.faces.context.FacesContextFactoryImpl

public FacesContext getFacesContext(Object sc, Object request, Object response, Lifecycle lifecycle)
    throws FacesException {

       ....        
        FacesContext ctx = new FacesContextImpl(
                  externalContextFactory.getExternalContext(sc, request, response), lifecycle);

        ctx.setExceptionHandler(exceptionHandlerFactory.getExceptionHandler());

        return ctx;        
    }

 

com.sun.faces.lifecycle.Phase 

public void doPhase(FacesContext context,
                        Lifecycle lifecycle,
                        ListIterator<PhaseListener> listeners) {

    ....

    try {
            handleBeforePhase(context, listeners, event);
            if (!shouldSkip(context)) {
                execute(context);
            }
        } catch (Throwable e) {
            queueException(context, e);
        } finally {
            try {
                handleAfterPhase(context, listeners, event);
            } catch (Throwable e) {
                queueException(context, e);
            }
            ....

            context.getExceptionHandler().handle();
        }

}

 

JSF 2.0 default impl

com.sun.faces.context.ExceptionHandlerFactoryImpl

public ExceptionHandler getExceptionHandler() {
        FacesContext fc = FacesContext.getCurrentInstance();
        if (fc.getPartialViewContext().isAjaxRequest()) {
            return new AjaxExceptionHandlerImpl(new ExceptionHandlerImpl(Boolean.TRUE));
        }
        ApplicationAssociate associate = getAssociate(fc);
        return new ExceptionHandlerImpl(((associate != null) ? associate.isErrorPagePresent() : Boolean.TRUE));
    }