0

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:

  1. 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?
  2. 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

pnuts
  • 58,317
  • 11
  • 87
  • 139
volvox
  • 3,014
  • 16
  • 51
  • 80

2 Answers2

1

Basically, the answer for 1 would be no, you shouldn't try to recover from an OOM error (more info here, and check the links provided in comments and answers). The error would be posted in your tomcat log and in your web application log (if any).

If you get an OOM, I would use a Profiler like VisualVM to check where the problem could be and try to resolve the problem.

Additional info:


Another thing, you can handle the error using the error code, just add this in your web.xml:

<error-page>
    <error-code>500</error-code>
    <location>/ErrorForCode500.html</location>
</error-page>
Community
  • 1
  • 1
Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332
  • thanks for the answer. on your second point, i'm rethrowing certain exceptions and they're picked up by the web.xml as listed above so adding the 500 won't work. – volvox Sep 17 '12 at 23:19
1

Once you hit an OOM exception, the entire state of the application is suspect and shouldn't be recovered. Trying to handle it is kind of noble, but it's far more important to make sure it doesn't happen.

Ickster
  • 2,167
  • 4
  • 22
  • 43