0

I need to customize the "Not found in ExternalContext as a Resource" page. I have tried both changing the web.xml to add the 404 and 500 error-code sections:

<error-page>
  <error-code>500</error-code>
  <location>/500.xhtml</location>
</error-page>
<error-page>
  <error-code>404</error-code>
  <location>/404.xhtml</location>
</error-page>

and following the info provided by SO/forums/blog like
http://duckranger.com/2010/08/configure-a-custom-404-page-in-glassfish/
How to create custom 404 messages in JSF 2.0?

but no success:
All I get is a blank page (or a "This XML file does not appear to have any style information associated with it. The document tree is shown below." that the browser generates) and the following stack trace when accessing a non-existing page:

SEVERE: doFilter
/m/test.xhtml Not Found in ExternalContext as a Resource
  com.sun.faces.context.FacesFileNotFoundException: /m/test.xhtml Not Found in ExternalContext as a Resource
at com.sun.faces.facelets.impl.DefaultFaceletFactory.resolveURL(DefaultFaceletFactory.java:232)
at com.sun.faces.facelets.impl.DefaultFaceletFactory.resolveURL(DefaultFaceletFactory.java:273)
at com.sun.faces.facelets.impl.DefaultFaceletFactory.getMetadataFacelet(DefaultFaceletFactory.java:209)
at com.sun.faces.application.view.ViewMetadataImpl.createMetadataView(ViewMetadataImpl.java:114)
at com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:233)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:116)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1539)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:343)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:217)
at com.example.v2.filter.AbstractFilter.doFilter(AbstractFilter.java:55)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:217)
at com.example.v2.filter.AbstractFilter.doFilter(AbstractFilter.java:55)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:217)
at com.example.v2.filter.AbstractFilter.doFilter(AbstractFilter.java:55)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:217)
at com.example.v2.filter.AbstractFilter.doFilter(AbstractFilter.java:55)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:217)
at com.example.v2.filter.MobileFilter.skip(MobileFilter.java:111)
at com.example.v2.filter.MobileFilter.doFilter(MobileFilter.java:67)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:217)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:279)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:98)
at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:91)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:162)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:330)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:174)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:828)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:725)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1019)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
at java.lang.Thread.run(Thread.java:722)

EDIT and FIX
In some blog/forum, the Filter chaining examples are as follows:

try {
  chain.doFilter(request, response);
  } catch (Throwable t) { // or Exception
    // do some logging
  }

This is wrong and prevents JSF to continue the normal flow of error processing. I kept the logging but re-throw the Exception. After that the error-code 500 in web.xml takes care of the issue.

try {
  chain.doFilter(request, response);
  } catch (Throwable t) { // or Exception
    // do some logging
    throw t; // so JSF/Container can continue normal low of error handling
  }
Community
  • 1
  • 1
JScoobyCed
  • 10,203
  • 6
  • 34
  • 58

2 Answers2

2

This is a Facelets-specific "feature". A missing resource results in a FacesFileNotFoundException (which is a subclass of FileNotFoundException) being thrown instead of that the response is been returned with a 404 status.

To cover that, add the following to web.xml as well:

<error-page>
    <exception-type>java.io.FileNotFoundException</exception-type>
    <location>/404.xhtml</location>
</error-page>

Alternatively, you could use OmniFaces' FacesExceptionFilter which transparently delegates those exceptions to 404's.

As to the second problem:

All I get is a blank page (or a "This XML file does not appear to have any style information associated with it.

The error page <location> has to match FacesServlet's URL pattern as well. Better is to just map the FacesServlet on *.xhtml directly, this way you never need to worry about virtual URLs.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Thank you for the reply. I had tested actually the `exception-type` with the actual FacesFileNotFoundException. Using the more general FileNotFoundException doesn't help. However, if I disable my filters, the stacktrace still shows but the error page is correctly shown. If I remove the exception-type, the regular error-code 500 seems to take care of it properly. BUT I need the filters ... – JScoobyCed Nov 01 '12 at 03:43
  • @BalusC Thanks, it works for me. But it still returns http status 500 instead of 404. – banterCZ Feb 07 '13 at 09:00
  • @banter: Use the `FacesExceptionFilter`. – BalusC Feb 07 '13 at 10:37
0

In some blog/forum, the Filter chaining examples I had blindly copied are as follows:

try {
  chain.doFilter(request, response);
  } catch (Throwable t) { // or Exception
    // do some logging
  }

This is wrong and prevents JSF to continue the normal flow of error processing. I kept the logging but re-throw the Exception. After that the error-code 500 in web.xml takes care of the issue.

try {
  chain.doFilter(request, response);
  } catch (Throwable t) { // or Exception
    // do some logging
    throw t; // so JSF/Container can continue normal low of error handling
  }
JScoobyCed
  • 10,203
  • 6
  • 34
  • 58