JSF Techniques – ERROR Handling

© 2009, Software Engineering Solutions, Inc.

-         Damodar Chetty

-         Apr 4, 2009

As professionals, we all strive to write perfect code, with perfect exception handling to boot. Unfortunately, even the best laid plans sometimes result in exception/error conditions that we failed to consider. Even worse, there may be errors thrown by any one of the numerous frameworks that we use, which can often be out of our control.

For obvious reasons, filling a user's screen with a Java stack trace is not the optimal solution in these situations. Instead, we'd like to provide the user with a simplified indication of the error condition, and provide some options for recovery.

In this article we will look at how error handling may be implemented for applications written using MyFaces/Facelets.

1. The Servlet Specification

The Servlet 2.5 specification terms this the "error page mechanism", and describes how HTTP error codes or uncaught exception types can be mapped to error handling resources – either static HTML pages, or dynamic resources (JSPs or servlets).

This mechanism is very declarative in nature, and is driven by the <error-page> element in web.xml, which maps either an <exception-type> or an <error-code> to a resource's <location>. The exception type is specified as the fully qualified class name of the exception (such as java.lang.Throwable); the error code is specified as an HTTP status error code (such as a 404 or a 500); and the location is specified as a URL.

If the resource is a dynamic resource (such as a JSP or a servlet), the container will also make available to it, the request and response objects. It will also stuff in additional request attributes that will help the dynamic resource determine the specific error condition. These request attributes include:

·         javax.servlet.error.status_code – the HTTP status code;

·         javax.servlet.error.exception – the specific exception thrown, as a java.lang.Throwable. You can use this exception to get its message, print its stack trace, etc.

·         javax.servlet.error.request_uri – the URI of the original request, whose processing led to this error.

·         javax.servlet.error.servlet_name – the logical name of the servlet in which the error occurred.

This mechanism kicks in when an uncaught exception is propagated up to the container, or when sendError() is called on the response to send an error code in the 4xx or 5xx ranges.

 

2. MyFaces Error Handling

Both Facelets and MyFaces themselves provide additional error handling support – and surface a stack trace, the component tree, and request parameters to the user.

This is often considered a security risk, as the information provided has the potential to be used against the application itself.

Consequently, one of the most important items on your reading list should be the document on MyFaces Error Handling.

 

3. Error Handling Strategies

One of the key decisions that you need to make is how much control you want over the error handling and customization process. The greater the customization you need, the more complex is the error handling scenario.

Note:

In all the cases that follow, we simulate an uncaught exception by explicitly throwing an NPE from within an action method in a managed bean:

public class LoginBean extends PageBean {

  private String username;

  private String password;

  private String clientCode;

  private UserRealm realm;

  public LoginBean() {      }

  public String login() {

   if (true) throw new NullPointerException("Et tu Brutus!");

   //do some authentication logic here

   return "homepage";

  }

  … other methods …

 

3.1. Servlet Error Page Mechanism With Static Resource

With the first option, we use the standard Servlet spec's error page mechanism to display a static resource.

Because the error handling mechanism provided by MyFaces kicks in before the container's default error page mechanism, the first thing you need to do is to shut it up.

Edit your web.xml file to shut down the error mechanisms of both MyFaces and Facelets by setting both these parameters to false:

web.xml:

  <context-param>

   <param-name>org.apache.myfaces.ERROR_HANDLING</param-name>

   <param-value>false</param-value>

  </context-param>

  <context-param>

   <param-name>facelets.DEVELOPMENT</param-name>

   <param-value>false</param-value>

  </context-param>

 

Next, add in mapping entries to map java.lang.Throwable to our custom error page:

   <error-page>

     <exception-type>java.lang.Throwable</exception-type>

     <location>/error.html</location>

   </error-page>

 

Finally, write a static html file as our basic error resource:

error.html:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"

        "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head><title>Error</title></head>

<body>An error has occurred.</body>

</html>

While simple is often beautiful, terse is not quite enough when it comes to debugging an issue on a production server. As a result, we will need to continue on with our exploration of alternative options.

 

3.2. Using the MyFaces Error Mechanism

This mechanism is one step up in terms of complexity, and provides you with limited customizability.

web.xml

First, ensure that MyFaces error handling has been enabled, by setting the following web.xml parameter to true:

  <context-param>

   <param-name>org.apache.myfaces.ERROR_HANDLING</param-name>

   <param-value>true</param-value>

  </context-param>

You also need to provide your own custom error template. The default template provides way too much information – including request parameters that may expose sensitive data, and so is unsuitable for production usage.

  <context-param>

   <param-name>org.apache.myfaces.ERROR_TEMPLATE_RESOURCE</param-name>

   <param-value>mycustom-template-error.xml</param-value>

  </context-param>

 

Next, create your custom template. The easiest option is to base it on an existing template such as the META-INF/rsc/myfaces-dev-error.xml file in myfaces-api-1.2.x.jar. Note that this template has an XML extension – which should clue you in on the amount of customization that may be possible using it.

This page is actually parsed by javax.faces.webapp._ErrorPageWriter, which looks for certain keywords for dynamic replacements. The following keywords are supported - @@message@@, @@trace@@, @@now@@, @@tree@@, @@vars@@, and @@cause@@ - the contents of which are fairly self-explanatory. E.g., @@trace@@ resolves to the stack trace, and @@now@@ generates a timestamp.

However, that's about as much control as you get. In the example below, I have changed the heading for my custom error page, and have hidden the stack trace from view – by placing it within comments. The stack trace is available for viewing using your browser's View Source command. I have also suppressed the request parameters (@@vars@@) and component tree (@@tree@@) from being displayed.

Place this file in your main source folder, so that it ends up at the root of your classpath – in your WEB-INF\classes folder. This allows the _ErrorPageWriter.splitTemplate() method to locate it using the web application class loader's getResourceAsStream() method:

InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(rsc);

 

mycustom-template-error.xml

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />

<title>Error - @@message@@</title>

…lines omitted…

</head>

<body>

  <h1>An Internal Program Error Occurred: [Custom Error Page]</h1>

  <div id="error" class="grayBox" style="border: 1px solid #900;">

   @@message@@      <br/>

   Caused by:<br/>

   @@cause@@

  </div>

   <!--

   <pre><code>@@trace@@</code></pre>

   -->

</body>

</html>

3.3. Servlet Error Page Mechanism With Dynamic Resource

This is the final and most complex option in your arsenal.

Here, we use a JSP to generate our exception response. We could also have used a servlet – but the JSP option is a lot simpler. Of course, you now have yet another technology in your stack to consider – but JSP is available for free anyway – so why not use it?

web.xml

As before, turn of MyFaces and Facelets Error Handling to make sure that they do not interfere with the servlet container's error page mechanism.

  <context-param>

   <param-name>org.apache.myfaces.ERROR_HANDLING</param-name>

   <param-value>false</param-value>

  </context-param>

  <context-param>

   <param-name>facelets.DEVELOPMENT</param-name>

   <param-value>false</param-value>

  </context-param>

Next, add in the mapping entry to map any uncaught java.lang.Throwable to our new error handling JSP.

  <error-page>

   <exception-type>java.lang.Throwable</exception-type>

   <location>/ErrorPage.jsp</location>

  </error-page>

 

Finally ensure that your JSP mapping is in place.

  <servlet-mapping>

   <servlet-name>jsp</servlet-name>

   <url-pattern>*.jsp</url-pattern>

  </servlet-mapping>

 

  <servlet>

   <servlet-name>jsp</servlet-name>

   <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>

   <init-param>

     <param-name>fork</param-name>

     <param-value>false</param-value>

   </init-param>

   <init-param>

     <param-name>xpoweredBy</param-name>

     <param-value>false</param-value>

   </init-param>

   <load-on-startup>1</load-on-startup>

  </servlet>

 

ErrorPage.jsp

Finally, let's create our error handler JSP. Note that the isErrorPage attribute is set to true for the Page directive. Also note that we can now access the exception implicit object to access its stack trace.

In addition, this JSP prints out the javax.servlet.error.* request attributes that have been conveniently added for use by the container.

Note the generation of the <a> retry link at the bottom of the page. We are able to do this because of the javax.servlet.error.request_uri request attribute that gives us the URL used when the error was encountered.

<%@ page isErrorPage="true" %>

<%@ page import = "java.util.Date" %>

<%

final String requestURL = request.getRequestURL().toString();

final String requestURI = request.getRequestURI();

final int index = requestURL.indexOf(requestURI);

final String retryURL = requestURL.substring(0, index) +

                     request.getAttribute("javax.servlet.error.request_uri");

%>

<HTML>

<BODY>

<H1>Error Page</H1>

A program error occurred on <%= new Date() %> at <%= request.getServerName() %>.<p />

<strong>javax.servlet.error.request_uri: </strong>

<%= request.getAttribute("javax.servlet.error.request_uri") %>

<br>

<strong>javax.servlet.error.exception: </strong>

  <%= request.getAttribute("javax.servlet.error.exception")%>

<br>

<strong>javax.servlet.error.status_code: </strong>

  <%= request.getAttribute("javax.servlet.error.status_code")%>

<br>

<strong>javax.servlet.error.servlet_name: </strong>

  <%= request.getAttribute("javax.servlet.error.servlet_name")%>

<br>

<!-- Error info:

  <% exception.printStackTrace(); %>

-->

<a href="<%=retryURL%>">Click here to retry this operation.</a>

</BODY>

</HTML>

 

At the risk of stating the obvious, the amount of customizability that you get with this final option is pretty much unbounded.

4. Conclusion

I have not discussed the final option – that of using JSF to handle the error page, and you can find that option discussed here. However, there seemed to be some incompatibilities with JSF 1.1 and using <f:view>, and I also ran into issues with using Facelets in this combination. All of which didn't fill me with a tremendous sense of confidence in this approach.

The JSP approach gave me the right combination of power and flexibility to make it my preferred choice.