ajaxjsfprimefacesnavigationpartial-response

partial-response xml displayed after navigation from CustomExceptionHandler due to ViewExpiredException


Hi I'm working on a JSF 2.2.4 project using Primefaces 4.0

I'm trying to replicate the ViewExpiredException by using the steps below.

-Go to the browser Login in the application

-Open another tab, click a p:menuitem (e.g. Accounting Screen)

-Restart the server (one of the tabs redirects automatically to the login page)

-Login the application again and then click the same p:menuitem again [Suddenly the browser displays partial-response xml instead of the jsf page]

XML displayed on browser:

<partial-response>
  <redirect url="/myapplication/denied/viewexpiredpage.jsf"/>
</partial-response>

CustomExceptionHandler.java

public class CustomExceptionHandler extends ExceptionHandlerWrapper {

private Logger logger = LoggerFactory.getLogger(CustomExceptionHandler.class);

private ExceptionHandler wrapped;

CustomExceptionHandler(ExceptionHandler exception) {
    this.wrapped = exception;
}

@Override
public ExceptionHandler getWrapped() {
    return wrapped;
}

@Override
public void handle() throws FacesException {
    FacesContext fc = FacesContext.getCurrentInstance();
    Map<String, Object> requestMap = fc.getExternalContext().getRequestMap();
    NavigationHandler nav = fc.getApplication().getNavigationHandler();

    for (Iterator<ExceptionQueuedEvent> i = getUnhandledExceptionQueuedEvents().iterator(); i.hasNext();) {
        ExceptionQueuedEvent event = i.next();
        ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event.getSource();
        Throwable t = context.getException();

        try {
            if (t instanceof ViewExpiredException) {
                logger.error("Custom Exception Handler caught an error: " + t.getMessage());
                fc.setViewRoot(fc.getApplication().getViewHandler().createView(fc, "expiredpage"));
                nav.handleNavigation(fc, null, "expiredpage");
                fc.getPartialViewContext().setRenderAll(true);
                fc.renderResponse();
            }else{     
                logger.error("Custom Exception Handler caught an error: " + t.getMessage());
            }
        }finally{
            i.remove();
        }
    }
    // At this point, the queue will not contain any ViewExpiredEvents.
    // Therefore, let the parent handle them.
    getWrapped().handle();
}
}

faces-config.xml

<factory>
    <exception-handler-factory>
        com.pemc.crss.web.commons.exceptionhandler.CustomExceptionHandlerFactory
    </exception-handler-factory>
</factory>

<navigation-rule>
    <from-view-id>*</from-view-id>
    <navigation-case>
        <from-outcome>expiredpage</from-outcome>
        <to-view-id>/denied/viewexpiredpage.jsf</to-view-id>
        <redirect />
    </navigation-case>
</navigation-rule>

The ViewExpiredException has been caught in the exception handler and the url from the partial response seems to be correct but for some wierd reason why does it display the partial-response xml instead of the actual jsf error page?

Any help in shedding some light on the issue would be greatly appreciated. Thanks!


Solution

  • ViewHandler#createView() does not accept a navigation case (the "expiredpage" you have there). What you should have instead is the actual view id or relative path to the error page:

    fc.getApplication().getViewHandler().createView(fc, "/myapplication/denied/viewexpiredpage.jsf");