I have a JSF app which I want to ensure provides the user with a meaningful response when it errors with an HTTP 500. The app dies when I force an OutOfMemoryError but I'm getting a default 500 error page from Tomcat 6.0.35.
Relevant parts of my app set up are:
web.xml:
<filter>
<filter-name>Error</filter-name>
<filter-class>myApp.ErrorFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Error</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
...
<error-page>
<exception-type>javax.faces.application.ViewExpiredException</exception-type>
<location>/expiredIndex.jsf</location>
</error-page>
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/error.jsf</location>
</error-page>
ErrorFilter.java:
public class ErrorFilter implements Filter {
static Logger logger = Logger.getLogger("MYAPP");
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
chain.doFilter(request, response);
} catch (ServletException e) {
logger.error(getDirID()+"|"+"Caught Servlet Exception");
Throwable rootCause = e.getRootCause();
logger.error(getDirID()+"|"+"Root cause is " + rootCause.toString());
if (rootCause instanceof RuntimeException) { // This is true for any FacesException.
logger.error(getDirID()+"|"+"Rethrowing exception as RuntimeException" + rootCause.toString());
throw (RuntimeException) rootCause; // Throw wrapped RuntimeException instead of ServletException.
} else {
throw e;
}
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
public String getDirID() {
DirID newDirID = new DirID();
String dirID = newDirID.getDirID();
return dirID;
}
}
The cut-down stack trace for your pleasure:
2012-09-17 17:35:51,881|ERROR|[http-8080-1]:Exception in the filter chain
javax.servlet.ServletException: Servlet execution threw an exception
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:313)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
...
Caused by: java.lang.OutOfMemoryError: Java heap space
at com.sun.facelets.util.FastWriter.overflow(FastWriter.java:50)
at com.sun.facelets.util.FastWriter.write(FastWriter.java:57)
...
Sep 17, 2012 5:35:51 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet Faces Servlet threw exception
java.lang.NullPointerException
at myApp.DirID.getDirID(DirID.java:27)
at myApp.ErrorFilter.getDirID(ErrorFilter.java:50)
at myApp.ErrorFilter.doFilter(ErrorFilter.java:31)
and probably the most relevant bit:
Sep 17, 2012 5:35:51 PM com.sun.faces.lifecycle.Phase doPhase
SEVERE: JSF1054: (Phase ID: RESTORE_VIEW 1, View ID: ) Exception thrown during phase execution: javax.faces.event.PhaseEvent[source=com.sun.faces.lifecycle.LifecycleImpl@16968dd]
Sep 17, 2012 5:35:51 PM org.apache.catalina.core.ApplicationDispatcher invoke
SEVERE: Servlet.service() for servlet Faces Servlet threw exception
javax.faces.application.ViewExpiredException: viewId:/error.jsf - View /error.jsf could not be restored.
Now my view on this is that the container dies when it hits the max memory limit and as such the error.jsf posh error page is not accessible given the state the stack is left in.
My questions are:
- Given the cause is a sudden out-of-memory error, can I get back from this so the server has enough to make the redirect to my error.jsf page?
- If the answer to 1 is yes, what is the most efficient method of implementation (preferably with a code snip-it for maximum guruness).
Thanks