2

I don't redirect or forward my user to another page. So when the my SessionExpiredExceptionHandler (extends ExceptionHandlerWrapper) handles the ViewExireException. I want the user to stay on the same page and display a PrimeFaces Dialog. For notifying that the session has expired and that the user needs to login again (dialog based). I am use Servlet 3.1 functions to login/logout user and Basic/file for auth-method to map the users to different system roles.

What is happening now is that the View/page get refreshed after 2 min, but the session doesn't get invalidated. That only happens the second time when the page refreshes, after 4 min.

    <session-config>
        <session-timeout>2</session-timeout>
    </session-config>

Edit: Which is refreshed by the meta tag:

<meta http-equiv="refresh" content="#{session.maxInactiveInterval}" />

How can I make SessionExpiredExceptionHandlerinvalidate the session object (Servlet logout) when the Exceptions occur the first time, and how can I invoke a JavaScript (expireDlg.show()) on the client to display a PrimeFaces dialog ?

I have looked at some other threads but not found a viable solution. Session time-out

SessionExpiredExceptionHandler

    @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 fc = FacesContext.getCurrentInstance();
        Map<String, Object> requestMap = fc.getExternalContext().getRequestMap();
        NavigationHandler nav = fc.getApplication().getNavigationHandler();                

        try {
            requestMap.put("currentViewId", vee.getViewId());

            nav.handleNavigation(fc, null, "Home");
            fc.renderResponse();

        } finally {
            i.remove();
        }                                
        }
    }
    // At this point, the queue will not contain any ViewExpiredEvents.
    // Therefore, let the parent handle them.
    getWrapped().handle();
    }

web.xml

<exception-type>javax.faces.application.ViewExpiredException</exception-type>
    <location>/home.xhtml</location>
</error-page>
Community
  • 1
  • 1
Chris
  • 712
  • 3
  • 16
  • 39

2 Answers2

2

How can I make SessionExpiredExceptionHandler invalidate the session object (Servlet logout) when the Exceptions occur the first time

The session is supposedly to be already invalidated/expired (otherwise a ViewExpiredException wouldn't be thrown at all), so I don't see how it's useful to manually invalidate/expire it yourself. But for the case that, you can invalidate it as follows:

externalContext.invalidateSession();

and how can I invoke a JavaScript (expireDlg.show()) on the client to display a PrimeFaces dialog ?

You can use the PrimeFaces RequestContext API to programmatically instruct PrimeFaces to execute some JS code on complete of ajax response.

RequestContext.getCurrentInstance().execute("expireDlg.show()");

Don't forget to remove the navigation handler block from the exception handler if you actually don't want to navigate.

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • That I figured out, to comment out the navigation part. But at the moment the handler doesn't get called at all. The page only get refreshed, but the locally store SessionUser is still valid? – Chris Jan 15 '13 at 15:32
  • 1
    You mean, the exception handler is never constructed/invoked? Did you register its factory in `faces-config.xml` as expained in the blog article where you found this kickoff example? – BalusC Jan 15 '13 at 15:37
  • Acctually the ExceptionHandler get called several times for every request. Even if there are no Exceptions. – Chris Jan 15 '13 at 16:00
  • I've done what you have suggested, I've removed navigation block, but I got NullPointerException: http://stackoverflow.com/questions/14606828/how-to-handle-viewexpiredexception-by-showing-javascript-alert – Danubian Sailor Jan 30 '13 at 15:01
2

This solution worked for my case. It seams that Primefaces (3.3) is swallowing the ExceptionQueuedEvent. There are no Exception to handle when my ViewExceptionHandler gets called. So instead I used the p:idleMonitor component with event listner. I also removed the meta refresh tag.

<p:idleMonitor timeout="#{(session.maxInactiveInterval-60)*1000}">
        <p:ajax event="idle" process="@this" update="sessionMsg" listener="#{userController.userIdleSession()}" />
        <p:ajax event="active" process="@this" update="sessionMsg" listener="#{userController.userActiveSession()}"/>
</p:idleMonitor>

One weird thing is if the timeoutis excatly the same as the web.xmlsession time-out parameter, the listener won't be invoked.

Bean functions

public void userIdleSession() {
    if (!userIdleMsgVisable) {
        userIdleMsgVisable = true;
        JsfUtil.addWarningMessage(JsfUtil.getResourceMessage("session_expire_title"), JsfUtil.getResourceMessage("session_expire_content"));            
    }
}

public void userActiveSession() {
        if (!userSessionDlgVisable) {
            userSessionDlgVisable = true;                     
            RequestContext.getCurrentInstance().execute("sessionExipreDlg.show()");            
        }
    }

The dialog (sessionExipreDlg) called the redirect instead of using navigation handler to get new scope and refresh the page.

public void userInactiveRedirect() {
        FacesContext fc = FacesContext.getCurrentInstance();
        userIdleMsgVisable = false;
        userSessionDlgVisable = false;
        sessionUser = null;         
        HttpServletRequest request = (HttpServletRequest) fc.getExternalContext().getRequest();
        JsfUtil.findBean("homeController", HomeController.class).clearCurrentValues();        
        try {
            fc.getExternalContext().redirect(JsfUtil.getApplicationPath(request, false, null));            
        } catch (IOException ex) {
            BeanUtil.severe(ex.getLocalizedMessage());
        }
    }
Chris
  • 712
  • 3
  • 16
  • 39
  • And what if the user did not click anywhere on the page just moves the mouse (example with scrolling) until the session expires. After it makes a click on a button for example. Then an ViewExpiredException will be thrown. – FAndrew Sep 15 '17 at 11:53