JSF and PrimeFaces: Session Timeout Handling

Implementing session timeout handling in an ajax web application can be hard. You have to redirect to a login page when a single ajax call fails after user session is invalid.

My solution is based on PrimeFaces idle monitor. User is redirected to logout action after timeout to invalidate the session. 2 minutes before a countdown dialog is shown to warn user. After moving the mouse again session is extended.

PrimeFaces idle monitor and dialog is placed in a template you can add to every page which is involved:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
   xmlns:h="http://java.sun.com/jsf/html"
   xmlns:ui="http://java.sun.com/jsf/facelets"
   xmlns:p="http://primefaces.org/ui">

<ui:composition>
   <h:form prependId="false">
      <p:idleMonitor
         timeout="#{session.maxInactiveInterval * 1000 - 125000}"
         onidle="startIdleMonitor()"
         onactive="timeoutDialog.hide()" />

      <p:dialog id="timeoutSession"
         header="#{msg['session.expire']}"
         widgetVar="timeoutDialog"
         showEffect="fade" hideEffect="fade"
         modal="true"
         width="400"
         height="110"
         closable="false"
         draggable="false"
         resizable="false"
         appendToBody="true"
         onHide="stopCount()"
         onShow="doTimer()">
         <br />
         <p>
            <span class="ui-icon ui-icon-alert" style="float: left; margin: 8px 8px 0;"/>
            <p:panel>
               #{msg['logoff.soon.1']}
               <span id="dialog-countdown" style="font-weight: bold"></span>
               #{msg['logoff.soon.2']}
            </p:panel>
         </p>
         <br />
         <p style="font-weight: bold;">#{msg['move.cursor']}</p>
      </p:dialog>
      <p:remoteCommand name="keepAlive" actionListener="#{auth.keepSessionAlive}" />
   </h:form>
   <script type="text/javascript">
      var TIME = 120; // in seconds
      var countTimer = TIME;
      var processTimer;
      var timer_is_on = 0;
      var redirectPage = "#{request.contextPath}/auth/j_verinice_timeout";

      var countDownDiv = "dialog-countdown";
      var txtCountDown = null;
      if (!txtCountDown)
      	txtCountDown = document.getElementById(countDownDiv);

      function startIdleMonitor() {
      	countTimer = TIME;
      	txtCountDown.innerHTML = countTimer;
      	timeoutDialog.show();
      }
      function timedCount() {
      	txtCountDown.innerHTML = countTimer;
      	if (countTimer == 0) {
      		stopCount();
      		window.location.href = redirectPage;
      		return;
      	}
      	countTimer = countTimer - 1;
      	processTimer = setTimeout("timedCount()", 1000);
      }
      function doTimer() {
      	if (!timer_is_on) {
      		timer_is_on = 1;
      		timedCount();
      	}
      }
      function stopCount() {
      	clearTimeout(processTimer);
      	timer_is_on = 0;
      	keepAlive();
      }
      </script>
</ui:composition>
</html>
  • Line 11: The timeout of the idle monitor is set by system var session.maxInactiveInterval. The value you set in your web.xml or server configuration.
  • Line 12/13: Javascript method startIdleMonitor() is called after timeout without any user interaction. This method opens the dialog. timeoutDialog.hide() is called when user is busy again: Dialog is closed
  • Line 26/27: Two more Javascript methods are called when dialog is shown or hide: doTimer() starts and stopCount() stops the countdown.
  • Line 40: PrimeFaces remote command to keep session alive. By calling an arbitrary method on server the session is extended. Command is called by Javascript method keepAlive() in line 78.
  • Line 59-68: Javascript method timedCount() is called every second to execute the countdown. After timeout redirect is done in line 63.

To activate timeout handling in multiple pages include the timeout template in your layout template:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:ui="http://java.sun.com/jsf/facelets"
  xml:lang="de-DE">
<h:head>
  ...
</h:head>
<body>
  <ui:include src="/template/sessionTimeOut.xhtml" />
  <ui:include src="/nav.xhtml"/>>
  <ui:insert name="content">Default content</ui:insert>
  <ui:include src="/footer.xhtml"/>>
</body>
</html>

A specific time out for your web application you can set in your web.xml:

<!--?xml version="1.0" encoding="UTF-8"?-->
<web-app>
   ...
   <session-config>
      <!-- Session idle timeout in min. -->
      <session-timeout>30</session-timeout>
    </session-config>
</web-app>
About these ads
    • hjelperne
    • 4. Januar 2013

    Hi,
    Thanks for great example. What does your keepSessionAlive() backing bean function look like?

  1. Calling keepSessionAlive() stops idle time for the user session on application server. Just call an arbitrary getter in this method. I think it can even be empty.

    • hjelperne
    • 4. Januar 2013

    Thanks for the response! Actually an empty method didnt extend the session in my case.

    I had to add:

    FacesContext fc = FacesContext.getCurrentnstance();
    HttpServletRequest request = (HttpServletRequest) fc.getExternalContext().getRequest();
    request.getSession();

    to the keepSessionAlive() function

    Now it works as expected.

    Thanks again!

  2. Take care that keepSessionAlive() is really called before session is expired by increasing the 120000 from line 11:

    timeout=”#{session.maxInactiveInterval * 1000 – 125000}”

    (I just changed the code sample in the article.)

      • Kedar
      • 3. April 2013

      dear murygin
      this solution doesn’t work as idle monitor time out triggers only when that page is idle (i.e. not even mouse hovering on that page) and session will be timed out because of no request from page for specific time. to reproduce follow below steps
      assumption:
      * sessionMaxInterval is 3 minute (180 seconds)
      * idle monitor timeout value is 125000 ms.
      1. load the page move the mouse for 30 seconds
      2. go to another page
      3. idle monitor pop ups at 55th second which will count for 125 seconds
      4. so total time here is 125+30+55 = 210 seconds
      5. so if user moves mouse at last 2nd second of timer by that time session would already get invalidated.

        • John Mendes
        • 19. April 2013

        Dear Kedar,

        I am a beginner in JSF. Could you send to me an example of the classes used in this tutorial?

  3. Dear Kedar,

    The meaning of “idle” for PrimeFaces is no action at all (including mouse motion). The meaning “idle” for the server is no request from the client.

    Unfortunately I don’t have a solution for this problem…

    Daniel.

    • Pierre
    • 10. Juni 2013

    Hi
    I dont understand the metrics…
    #{session.maxInactiveInterval * 1000 – 125000}
    session.maxInactiveInterval is minutes (30 in your example)
    so the result is negative…..
    How does it work ?

  4. Time unit for session.maxInactiveInterval is milliseconds.

    • Jlga
    • 24. Juli 2013

    HI. Please help me.

    I have this error.

    Grave: JSF1073: se ha interceptado javax.faces.event.AbortProcessingException durante el procesamiento de INVOKE_APPLICATION 5 : UIComponent-ClientId=j_idt13, Mensaje=/Paginas/Entorno/sessionTimeOut.xhtml @33,48 actionListener=”#{auth.keepSessionAlive}”: Objetivo inalcanzable, identificador ‘auth’ resuelto a nulo
    jul 24, 2013 9:23:59 AM com.sun.faces.context.AjaxExceptionHandlerImpl log
    Grave: /Paginas/Entorno/sessionTimeOut.xhtml @33,48 actionListener=”#{auth.keepSessionAlive}”: Objetivo inalcanzable, identificador ‘auth’ resuelto a nulo
    javax.faces.event.AbortProcessingException: /Paginas/Entorno/sessionTimeOut.xhtml @33,48 actionListener=”#{auth.keepSessionAlive}”: Objetivo inalcanzable, identificador ‘auth’ resuelto a nulo

    • Andres A.
    • 25. Juli 2013

    Hi, here is an update:

    ………..

    …………………………..

    …………

    var TIME = 120; // in seconds
    var maxSesion=”#{session.maxInactiveInterval}”
    var countTimer = maxSesion;
    var processTimer;
    var timer_is_on = 0;
    var redirectPage = “#{request.contextPath}/seguridad/login.xhtml”;

    var countDownDiv = “dialog-countdown”;
    var txtCountDown = null;
    if (!txtCountDown)
    txtCountDown = document.getElementById(countDownDiv);

    function startIdleMonitor() {
    if(timer_is_on){
    txtCountDown.innerHTML = countTimer;
    timeoutDialog.show();
    }
    }
    function timedCount() {
    txtCountDown.innerHTML = countTimer;
    if (countTimer == 0) {
    stopCount();
    window.location.href = redirectPage;
    return;
    }
    if(countTimer == TIME)
    {
    timer_is_on = 1;
    }
    countTimer = countTimer – 1;
    processTimer = setTimeout(“timedCount()”, 1000);
    }

    function stopCount() {
    clearTimeout(processTimer);
    countTimer = maxSesion;
    timer_is_on = 0;
    keepAlive();
    }

    ………………………..

    This guarranted that time in page be less that sesion time, and reset when move the mouse

  5. Better yet, use primefaces poll:

    http://www.primefaces.org/showcase/ui/poll.jsf

    This will let you call a keepAlive method every X seconds.

  6. @rsisto Then your session never expires. For some applications this might be a problem.

  7. Thank you, great solution!

    • Kishor
    • 27. Oktober 2014

    I have a question:
    Consider I have set th Timeout for 30 minutes, thb that case: startIdleMonitor() will start from 28th minute.
    Now user moves the Mouse(mot click) at 27th minute and startIdleMonitor() will still start at 28 minute and logs out at 30th minute.
    Form user(who move the mouse)’s perspective the timer had reset to 30 minutes again, when he moved the mouse at 27th minute.
    Wouldn’t he be surprised when system logs out, 3 minutes after he moved the mouse???

  1. No trackbacks yet.

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ photo

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s

Folgen

Erhalte jeden neuen Beitrag in deinen Posteingang.

%d Bloggern gefällt das: