Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error page defined in web.xml is embedded in partially rendered JSF page

Tags:

jsf-2

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.

like image 955
jc12 Avatar asked Aug 01 '12 21:08

jc12


1 Answers

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>
like image 110
BalusC Avatar answered Nov 09 '22 12:11

BalusC