You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by Apache Wiki <wi...@apache.org> on 2006/06/18 22:20:20 UTC

[Myfaces Wiki] Update of "Handling Server Errors" by JulianRay

Dear Wiki user,

You have subscribed to a wiki page or wiki category on "Myfaces Wiki" for change notification.

The following page has been changed by JulianRay:
http://wiki.apache.org/myfaces/Handling_Server_Errors

New page:
== Handling Server Errors ==

Server errors such as HTTP 500 can occur for a number of reasons such as uncaught exceptions, missing JSFs or backing beans, bad URL and the list goes on. While we hope these only occur during development it is important to plan to catch and deal with these errors gracefully when running live with multiple users.

Several approaches have been discussed on the mailing list:


["http://www.jroller.com/page/mert?entry=handling_errors_with_an_errror"] describes an approach which wraps the JSF servlet with a new servlet which delegates to the faces servlet but handles uncaught exceptions allowing the developer to redirect to a custom error page.

Another approach is described in core server pages which uses the servlet engine to catch the error and delegate to a JSF error page. While not as elegant as the  first approach this method has several advantages for some users

[1] It uses a standard JSP approach and framework[[BR]]
[2] It does not require custom servlets[[BR]]
[3] It can easily be customized/changed by simply changing the error handler definition in the web.xml[[BR]]


To implement this method perform the following steps

[1] define an error handling web page in web.xml

{{{
	<error-page>
		<error-code>500</error-code>
		<location>/ErrorDisplay.jsf</location>
	</error-page>
}}}

[2] Create the error handler display. Due to a problem with the JSF 1.1 specification, the error handling page cannot use a <h:form> but must use a subview.
{{{
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<%@ taglib uri="http://myfaces.apache.org/tomahawk" prefix="t"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<f:subview id="error">
<html>
<head>
	<meta content="no-cache" http-equiv="Cache-Control" />
	<meta content="no-cache" http-equiv="Pragma" />
	<title>CMS - Error</title>
        <t:stylesheet path="#{SessionBean.styleSheet}" />
	</head>
	<body>
	<h:form>
           :
           : set up the normal view
           :
	   <h:outputText styleClass="infoMessage" escape="false" value="#{ErrorDisplay.infoMessage}" />
	   <t:htmlTag value="br" />
	   <h:inputTextarea style="width: 99%;" rows="10" readonly="true" value="#{ErrorDisplay.stackTrace}" />
           :
           : more view stuff
           :
        </h:form>
    </body>
</html>
</f:subview>

}}}

[3] Create a backing bean in request scope which can process the error.

{{{

import cms.beans.framework.AbstractUIBean;

import com.c2gl.jsf.framework.ApplicationResource;

import java.io.PrintWriter;
import java.io.StringWriter;

import java.util.Map;

import javax.faces.context.FacesContext;

import javax.servlet.ServletException;

public class ErrorDisplay extends AbstractUIBean {
    private static final long serialVersionUID = 3123969847287207137L;
    private static final String BEAN_NAME = ErrorDisplay.class.getName();

    public String getInfoMessage() {
        return "An unexpected processing error has occurred. Please cut and paste the following information" + " into an email and send it to <b>" +
        some email address + "</b>. If this error " + "continues to occur please contact our technical support staff at <b>" +
        some phone number etc + "</b>.";
    }

    public String getStackTrace() {
        FacesContext context = FacesContext.getCurrentInstance();
        Map requestMap = context.getExternalContext().getRequestMap();
        Throwable ex = (Throwable) requestMap.get("javax.servlet.error.exception");
        StringWriter writer = new StringWriter();
        PrintWriter pw = new PrintWriter(writer);
        fillStackTrace(ex, pw);

        return writer.toString();
    }

    private void fillStackTrace(Throwable ex, PrintWriter pw) {
        if (null == ex) {
            return;
        }

        ex.printStackTrace(pw);

        if (ex instanceof ServletException) {
            Throwable cause = ((ServletException) ex).getRootCause();

            if (null != cause) {
                pw.println("Root Cause:");
                fillStackTrace(cause, pw);
            }
        } else {
            Throwable cause = ex.getCause();

            if (null != cause) {
                pw.println("Cause:");
                fillStackTrace(cause, pw);
            }
        }
    }
}

}}}

In the backing bean we construct a message which informs the user that something we didnt't plan for has happened with directions on who to call, what to do etc. We don't really care if they actually do cut-and-paste the error and email it to us as it is also in Tomcat's logs but giving the user something to do and become part of resolving the problem is always a good idea :)