5

I have the following defined in web.xml:

<error-page>
    <exception-type>java.lang.Throwable</exception-type>
    <location>/shared/errors/DefaultErrorPage.xhtml</location>
</error-page>
<error-page>
    <exception-type>javax.faces.application.ViewExpiredException</exception-type>
    <location>/shared/errors/ViewExpired.xhtml</location>
</error-page>

I'm also using the FullAjaxExceptionHandler from Omnifaces in faces-config.xml:

<factory>
    <exception-handler-factory>
        org.omnifaces.exceptionhandler.FullAjaxExceptionHandlerFactory
    </exception-handler-factory>
</factory>

The FullAjaxExceptionHandler is working fine for ajax calls, but when I hit a page directly and there is an error, it starts rendering the page I was trying to go to, but it doesn't finish, and then the error page defined in web.xml is rendered, which results in the error page being embedded after a partially rendered page.

(I'm using Glassfish 3.1.1 which has Mojarra JSF 2.1.3) Edit: now using Glassfish 3.1.2.2 and JSF 2.1.11

Edit: Discovered the following: The page where the error is happening is using templates (<ui:composition template="/shared/shared/commonLayout.xhtml">) If I change it so that the page is no longer using the template, and then just add in all of the code from the template then it works fine.

jc12
  • 1,411
  • 1
  • 18
  • 24
  • This is strange. To exclude the one and other, is the JSF project stage set to `Development` or not? – BalusC Aug 02 '12 at 02:34
  • Yes it is set to Development. – jc12 Aug 02 '12 at 15:03
  • I tried changing it to Production, but I'm still getting the same results. I'm not sure what you mean by "exclude the one and other". If I'm using the FullAjaxExceptionHandlerFactory for ajax calls, do I also need an ExceptionHandlerFactory for non-ajax calls? – jc12 Aug 02 '12 at 15:21
  • No, I had some possible causes in mind and I was just asking about the project stage so that I can scratch out (exclude) some possible causes from the list in mind. And no, you don't need an `ExceptionHandler` for non-ajax calls. See also http://stackoverflow.com/questions/10534187 Coming back to your concrete problem, try upgrading Mojarra to the latest, which is currently 2.1.11. I recall having seen this issue before, but I'm not sure why and how it would be caused. I believe it's a bug in one of the older Mojarra versions. – BalusC Aug 02 '12 at 15:23
  • I just upgraded to glassfish 3.2.2 and I'm still seeing the problem. FacesContext.class.getPackage().getImplementationVersion() returns 2.1.6-SNAPSHOT. I'm surprised they don't have a later version of JSF, and I'm even more surprised that it is a snapshot version. If I include the latest Mojarra JSF library will it override the one that is bundled with glassfish? – jc12 Aug 02 '12 at 16:34
  • Just replace `javax.faces.jar` file in `/glassfish/modules` folder. – BalusC Aug 02 '12 at 16:39
  • I'm on JSF 2.1.11 now, but I'm still seeing the problem. – jc12 Aug 02 '12 at 17:24
  • It works if I don't use templates (see edit in description), however I really don't want to remove templating from my project. – jc12 Aug 02 '12 at 19:07
  • I'm not exactly sure yet if this is as per the specification, but I can see the causes, the reasoning and several solutions. I've posted it in an answer. – BalusC Aug 02 '12 at 19:43

1 Answers1

5

This will happen when the response is already committed before the exception is been thrown. The response will be committed when ServletOutputStream#flush() has deep under the JSF covers explicitly been invoked in some way, which is more than often only when the response buffer (defaults usually to 2KB in most containers) has been overflowed. A committed response is a point of no return. The server cannot take the already-sent bytes back from the client. The server has basically 2 options:

  • Leave the response as is and log the exception to the server log only.
  • Try writing the error page to the response anyway.

Your Glassfish setup apparently chooses the 2nd way. None of them is perfect. The client would still end up with a halfbaked HTML response and whatever it would end up to look like to the enduser depends on how the webbrowser can do its best in interpreting and presenting the so far obtained HTML.

You, as JSF developer, can however use several approaches to avoid this from happening. In first place, why exactly is that exception been thrown during rendering the response? Doesn't that actually indicate a bug in your own code? Wouldn't you better perform the exception-sensitive business job before rendering the response? You could use among others <f:event type="preRenderView"> for this.

<f:event type="preRenderView" listener="#{bean.init}" />

If that's really not an option for some reason, you could consider increasing the response buffer size to above the size of the largest HTML response, so that the response won't be auto-flushed before the exception occurs. You can do that by the following context parameter which assumes that every HTML response fits within the 100KB limit:

<context-param>
    <param-name>javax.faces.FACELETS_BUFFER_SIZE</param-name>
    <param-value>102400</param-value><!-- 100KB -->
</context-param>
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Increasing the buffer size worked, thanks! The error is occuring during a PostConstruct in a ManagedBean. There are a lot of managed beans being used on the page, and most of them have their own setup code in a method with a PostConstruct annotation. In order to use the preRenderView I would have to put all of the init code into a single function, or maybe you can have multiple preRenderView events, but then you would have to maintain the events for each page. – jc12 Aug 02 '12 at 20:01