1 Reply Latest reply on Apr 28, 2015 3:36 AM by omid pourhadi

    Seam graceful timeouts - another approach

    Ken Clubok Newbie

      A great discussion of how to improve Seam's timeout handling can be found at In Relation To...  Implementing graceful session timeout with Seam, JSF, and jQuery.  But I had a slightly different problem than the one discussed there.  I had a few pages with long text fields, in which a user might spend a lot of time writing a book (figuratively) before submitting the form.  I wanted to ensure that the page didn't time out while the user was diligently typing.

       

      I also wanted to handle both conversation timeouts and session timeouts.  As discussed at solutionsfit – Setting the conversation-timeout in Seam, why it really does work, the conversation timeout only comes into play if the user has multiple browser tabs open, but it is still something to take into account.  On the other hand, I didn't feel the need to issue a timeout alert; simply dumping the user back to the login screen was sufficient for my purposes.

       

      Here is my solution.  It is implemented as a Facelets file that can be included with a <ui:include> tag:

       

      <ui:composition xmlns="http://www.w3.org/1999/xhtml"

          xmlns:ui="http://java.sun.com/jsf/facelets"

          xmlns:f="http://java.sun.com/jsf/core"

          xmlns:h="http://java.sun.com/jsf/html"

          xmlns:c="http://java.sun.com/jstl/core"

          xmlns:s="http://jboss.org/schema/seam/taglib"

                      xmlns:a4j="http://richfaces.org/a4j">

         

        <!-- Prevent timeout if user is active -->

        <script type="text/javascript">

          var keyPressed = false;

          var conversationTimeoutMillis = #{org.jboss.seam.core.conversation.timeout};

          var sessionTimeoutMillis = #{session.maxInactiveInterval} * 1000;

          var sessionTimeoutInterval = null;

          var sessionCheckInterval = null;

          var conversationCheckInterval = null;

       

          setInterval('keepAliveIfActive()', timeoutMillis);

          startSessionTimeoutCheck();

       

          function startTimeoutCheck() {

            conversationCheckInterval = setInterval('keepAliveIfActive()', conversationTimeoutMillis - 10000);

            sessionCheckInterval = setInterval('keepAliveIfActive()', sessionTimeoutMillis - 10000);

            sessionTimeoutInterval = setInterval('ping()', sessionTimeoutMillis + 3000);

          }

       

          function stopTimeoutCheck() {

            if (conversationCheckInterval) clearInterval(conversationCheckInterval);

            if (sessionCheckInterval) clearInterval(sessionCheckInterval);

            if (sessionTimeoutInterval) clearInterval(sessionTimeoutInterval);

          }

       

          function resetTimeoutCheck() {

            stopTimeoutCheck();

            startTimeoutCheck();

          }

       

          jQuery(document).click(function() {

            keyPressed = true;

          });

       

          jQuery(document).keypress(function() {

            keyPressed = true;

          });

       

          function keepAliveIfActive() {

            if (keyPressed) {

              keyPressed = false;

              ping();

              resetTimeoutCheck();

            }

          }

        </script>

       

        <h:form>

          <a4j:jsFunction name="ping" render="" />

        </h:form>

       

      </ui:composition>

       

      This tracks whether a key has been pressed or a mouse has been clicked on the page.  If so, then ten seconds before the conversation/session is due to expire, it sends a do-nothing Ajax request to the server, simply to keep the session and conversation alive.  Three seconds after the session expires, it will send the do-nothing request, but this will trigger a redirect back to the login screen (assuming that the associated page.xml file requires login).

       

      There are probably situations under which this can get confused.  Notably, if two tabs that include this script are open simultaneously, then they will conspire to prevent the session from ever timing out.  The solution from the above-mentioned blog also suffers from this issue, but I don't have any good way to avoid it.  Perhaps something involving local storage, to allow the tabs to communicate with each other.

       

      I'd love to hear any feedback about or potential improvements to this approach!