0

I am new to JSF 2.0 / PrimeFaces and I've created one webapp using JSF 2.0 + Spring 4. For session timeout, I've done below mapping in web.xml :

<session-config>
    <session-timeout>1</session-timeout>
</session-config>

<error-page>
    <exception-type>javax.faces.application.ViewExpiredException</exception-type>
    <location>/resources/login/timeout.xhtml</location>
</error-page>

After login, user redirects to admin.xhtml in which there element as

<h:link value="showAnotherPage" outcome="other.xhtml"/>

But after 2 or 5 minutes, when I click on the link, it redirects me to other.xhtml page not on timeout page.

Is anything that I'm missing to configure? Please help.

Tiny
  • 27,221
  • 105
  • 339
  • 599
Aasif Solkar
  • 81
  • 1
  • 12
  • Is `other.xhtml` a protected page that requires a login? And why are you testing the platform. NB This has nothing to do with JSF. It is enforced by Tomcat or whatever your Servlet container is. – user207421 Jul 05 '17 at 17:28
  • @EJP : admin.xhtml is the page which I display after successful login. I just added one link to check whether session timeout is working or not on admin.xhtml. It's not any protected kind of page. – Aasif Solkar Jul 06 '17 at 05:13

3 Answers3

0

I had this problem. You need to make sure there is no client call polling (ajax) server side resource, if this happens the session will not expire. I had a <p:poll /> tag that didn't let the session expire.

Mohsen
  • 4,536
  • 2
  • 27
  • 49
0

The ViewExpiredException will be thrown whenever the javax.faces.STATE_SAVING_METHOD is set to server (default) and the enduser sends a HTTP POST request on a view via <h:form> with <h:commandLink>, <h:commandButton> or <f:ajax>, while the associated view state isn't available in the session anymore.

The <h:link> will fire a full GET request so no POST request.

A good post with a more in-depth explanation can be found here

-1

I'd personally implement it in another way.

Define an Exception handler factory in your faces-config.xml as follows:

<factory>
    <exception-handler-factory>
        com.package.faces.FullAjaxExceptionHandlerFactory
    </exception-handler-factory>
</factory>

Create the exception handler factory that extends javax.faces.context.ExceptionHandlerFactory. It should return your own implementation of the ExceptionHandler. This could be an example:

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

public class FullAjaxExceptionHandlerFactory extends ExceptionHandlerFactory {

    private ExceptionHandlerFactory wrapped;

    /**
     * Construct a new full ajax exception handler factory around the given wrapped factory.
     * @param wrapped The wrapped factory.
     */
    public FullAjaxExceptionHandlerFactory(ExceptionHandlerFactory wrapped) {
            this.wrapped = wrapped;
    }

    /**
     * Returns a new instance of {@link FullAjaxExceptionHandler} which wraps the original exception handler.
     */
    @Override
    public ExceptionHandler getExceptionHandler() {
            return new FullAjaxExceptionHandler(wrapped.getExceptionHandler());
    }

    /**
     * Returns the wrapped factory.
     */
    @Override
    public ExceptionHandlerFactory getWrapped() {
            return wrapped;
    }

}

In the end, extend the javax.faces.context.ExceptionHandlerWrapper to handle all exceptions. An example is the following:

public class FullAjaxExceptionHandler extends ExceptionHandlerWrapper {

    private ExceptionHandler wrapped;

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

    private static Throwable extractCustomException(Throwable ex) {
        Throwable t = ex;
        while (t != null) {
            if (t instanceof YourOwnExceptionInterface) {
                return t;
            }
            t = t.getCause();
        }
        return ex;
    }

    private static String extractMessage(Throwable t) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        t.printStackTrace(pw);

        return matchJmillErrorTag(sw.toString()); 
    }

    public static boolean handleException(Throwable original) {
        Throwable ex = extractCustomException(original);

        if (ex instanceof ViewExpiredException) {
            // redirect to login page
            return false;
        } else if (ex instanceof YourOwnExceptionInterface) {
            ((YourOwnExceptionInterface) ex).handle();
            return true;
        } else if (ex instanceof NonexistentConversationException) {
            FacesContext.getCurrentInstance().getExternalContext().invalidateSession();

            // redirect to login page

            return false;
        } else {
            String message = extractMessage(ex);
            final FacesContext fc = FacesContext.getCurrentInstance();
            original.printStackTrace();

            // redirect to error page

            fc.responseComplete();
            return true;
        }
    }

    @Override
    public void handle() throws FacesException {
        final Iterator<ExceptionQueuedEvent> i = getUnhandledExceptionQueuedEvents().iterator();
        FacesContext facesContext = FacesContext.getCurrentInstance();
        if (Redirector.isRedirectingToLogin(facesContext)) {
            return;
        }
        while (i.hasNext()) {
            ExceptionQueuedEvent event = i.next();
            ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event.getSource();
            i.remove();
            if (!handleException(context.getException())) {
                return;
            }
        }
        getWrapped().handle();
    }

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

}

Check the public static boolean handleException(Throwable original) in the previous class. You could use that to manage all your exceptions.

At one point I put a condition there about YourOwnExceptionInterface which is an interface with a handle() method that I'd implement for example by a NotAuthorizedException kind of exception. In this case in the handle() method of the NotAuthorizedException I'd notify the user that he can't complete a certain operation through a p:growl component for example. I'd use this in my beans as throw new NotAuthorizedException("message");

The custom exception class should of course extend the RuntimeException.

500 Server error
  • 644
  • 13
  • 28
  • You would add several yards of redundant code to the application why? And it solves the problem how? The problem being what? – user207421 Jul 05 '17 at 17:30
  • Just proposed a solution that I find useful at least in large (enterprise) application. This kind of control/customization helps me a lot in my projects. The problem being solved is that of getting the user to some page if a certain error or exception is thrown. Such as the javax.faces.application.ViewExpiredException asked above. This was my solution. @EJP why don't you write a better one? – 500 Server error Jul 05 '17 at 18:36