Question

I leave some tabs open with forms and when I press the command buttons (after some time when the session expires) I receive a java script alert saying:

serverError: class javax.faces.application.ViewExpiredException viewId:/register.xhtml - View /register.xhtml could not be restored.

On firefox (glassfish 4 locally)

I have added :

<error-page>
    <exception-type>javax.faces.application.ViewExpiredException</exception-type>
    <location>/index.xhtml?faces-redirect=true</location>
</error-page>

in my web.xml but I am not redirected to my index. Why is that ?

Edit: sample button

<h:commandButton value="Register" action="#{userController.register}">
    <f:ajax execute="@form" render="@form" />
</h:commandButton>

UserController is ViewScoped

Was it helpful?

Solution

That's expected behaviour, if you look at sections 13.3.6.3 and 13.3.6.4 of the JSF-2.2 spec, at least if you have

<context-param>
  <param-name>javax.faces.PROJECT_STAGE</param-name>
  <param-value>Development</param-value>
</context-param>

in your web.xml (it silently ignores the error in production mode). The JSF client-side code sends an AJAX request when you click that button and receives

<error>
    <error-name>...</error-name>
    <error-message>...</error-message>
</error>

with your ViewExpiredException in the response. The client-side code is then expected to react to that error information. Register a function with onerror (on the f:ajax tag) or addOnError (on the jsf.ajax object) to handle error yourself.

Since a lot of folks expect the server to direct the client on such an issue, omnifaces includes the FullAjaxExceptionHandler that basically resets your response and sends the error page you specified.

See also:

Session timeout and ViewExpiredException handling on JSF/PrimeFaces ajax request

OTHER TIPS

Try this approach to handle view expiration: Create the following 2 classes in your project

import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExceptionHandlerFactory;

public class ViewExpiredExceptionExceptionHandlerFactory extends
        ExceptionHandlerFactory {

    private ExceptionHandlerFactory parent;

    public ViewExpiredExceptionExceptionHandlerFactory(
            ExceptionHandlerFactory parent) {
        this.parent = parent;
    }

    @Override
    public ExceptionHandler getExceptionHandler() {
        return new ViewExpiredExceptionExceptionHandler(
            parent.getExceptionHandler());
    }
}

and

public class ViewExpiredExceptionExceptionHandler extends
        ExceptionHandlerWrapper {

    private ExceptionHandler wrapped;

    public ViewExpiredExceptionExceptionHandler(ExceptionHandler wrapped) {
        this.wrapped = wrapped;
    }

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

    @Override
    public void handle() throws FacesException {
        for (Iterator<ExceptionQueuedEvent> i = 
                getUnhandledExceptionQueuedEvents().iterator(); i.hasNext();) {
            ExceptionQueuedEvent event = i.next();
            ExceptionQueuedEventContext context = (ExceptionQueuedEventContext)
                event.getSource();
            Throwable t = context.getException();
            if (t instanceof ViewExpiredException) {
                ViewExpiredException vee = (ViewExpiredException) t;
                FacesContext facesContext = FacesContext.getCurrentInstance();
                Map<String, Object> requestMap = facesContext
                    .getExternalContext().getRequestMap();
                NavigationHandler navigationHandler = facesContext
                    .getApplication().getNavigationHandler();
                try {
                    // Push some useful stuff to the request scope for use in
                    // the page
                    requestMap.put("currentViewId", vee.getViewId());
                    navigationHandler.handleNavigation(facesContext, null,
                        "/index");
                    facesContext.renderResponse();
                } finally {
                    i.remove();
                }
            }
        }
        // At this point, the queue will not contain any ViewExpiredEvents.
        // Therefore, let the parent handle them.
        getWrapped().handle();
    }
}

In faces-config.xml add the following lines:

<factory>
    <exception-handler-factory>path.to.class.ViewExpiredExceptionExceptionHandlerFactory</exception-handler-factory>

And that's it, you're good to go.

EDIT

Ok, i forgot about the Omnifaces way of doing this, i don't use this because once you set the page for error it warns you to make pages for 404 and another one that i don't remember right now. You should add to your faces-config.xml the following:

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

and your code will work. For more informations see the showcase for FullAjaxExceptionHandlerFactory from the omnifaces website http://showcase.omnifaces.org/exceptionhandlers/FullAjaxExceptionHandler;jsessionid=sOwX0FVqcY-InUhvDWEMksfQ .

Don't forget to add the required jar to your project.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top