views:

2452

answers:

4

I have an application in which users frequently leave the page running in their browser all day. The page has an intervalrendered that updates data every 30 seconds.

However, if the user doesn't interact with the page for a while, it still expires. I'd like it to auto-extend for as long as the browser is open and making the scheduled requests.

Is there a way to automatically extend the session everytime that the scheduled renderer is fired for one of these pages?

A: 

If I have undestood what is your real purpose, then you need a sort of timer which automatically extends every user session client side, consequentely overriding the server side default page session expiration timing ( usually 30 minutes, only for detail because I understood that the script "renders" every 30 seconds if the user is active on the page ).

If so well, before JSF I always extended inactive user sessions via underground Javascript, so I'll use it also in your case. Pratically you can build a simple page listener in Javascript starting from:

window.setInterval( expression , msecIntervalTiming );

the "expression" can be a called function in which you invoke some dummy JSF needed to keep the session alive without reloading the current page visited by the user, in the past I used standard frame or iframe to make http calls, now with XHR / Ajax is more simple too.

Javascript example:

var timerID = null;
function simplePageListener() { // invoked by some user event denoting his absence status
    // here goes all events and logic you need and know for firing the poller...
    if (timerID == null) // avoid  duplicates
        timerID = window.setInterval( "window.startPoller()", msecIntervalTiming );
}
//...
function pollerStart() {
  // make iframe or ajax/xhr requests
}
function pollerStop() {
  // make action like page reloading or other needings
}
//...
function triggeredCleanTimer(timer) { // invoked by some user event denoting his active status
  clearTimeout(timer); // it can be also the global variable "timerID"
  timerID = null;
}

Substantially you use the "timerID" as a global reference to keep track of the listener status, so when you need to activate the "autoextension" you assign it a setInterval. Instead when the user come back to the page (triggered by some event you know), you clear the timeout stopping the listener polling. The above example obviously implies that the user, when comes back, must reload the page manually.

However in your specifical case, I'll avoid to interfere with javascript automatically generated by Icefaces framework. Even if, for ipothesys, you could simulate periodically some user events on invisible input elements (style set on "visibility: hidden", absolutely not on "display: none"), this causes the Icefaces event to not stop it and making itself work continuosly

Elements like <input type="button" name="invisivleButton" value="..." style="visibility: hidden, z-index: 0;" /> on which you can call periodically invoke the click event by

 document.forms["YourDummyForm"]["invisivleButton"].click();

For the usage, see the old great JS docs of Devedge Online :-)

http://devedge-temp.mozilla.org/library/manuals/2000/javascript/1.3/reference/window.html#1203669

Steel Plume
A: 

ICEfaces has an internal mechanism for keeping sessions alive (the mechanism is sometimes referred to as "heartbeating"). You may have a look at the belonging documentation and configure the mentioned parameters (especially heartbeatInterval and heartbeatTimeout) in your web.xml.

Markus Lux
This internal mechanism isn't for keeping sessions alive, its for detecting when they die. The intervals just control how interactively the client detects the death, but they don't actually extend the session.
jsight
A: 

Iceface's Ajax bridge has callback APIs, for example Ice.onSessionExpired() which you may be able to use.

<body id="document:body">
    <script type="text/javascript">
        Ice.onSessionExpired('document:body', function() {
            <!-- Do something here -->
        });
    </script>

See http://www.icefaces.org/docs/v1_8_0/htmlguide/devguide/references4.html#1094786 for more details.

JRL
+1  A: 

I don't really want to do Javascript hacks to click buttons when my code is already being called every 30 seconds by ICEFaces. The following hacked workaround for ICEFaces internal timer seems to work:

  private void updateSessionExpiration () {
      HttpSession sess = getSession();
      if (sess != null) {
        try {
            Field fld = SessionDispatcher.class.getDeclaredField("SessionMonitors");
            fld.setAccessible(true);
            Map map = (Map)fld.get(null);
            String sessID = sess.getId();
            if (map.containsKey(sessID)) {
                log.info("About to touch session...");
                SessionDispatcher.Monitor mon = 
                     (SessionDispatcher.Monitor)map.get(sessID);
                mon.touchSession();
            }
        } catch (Exception e) {
            log.error("Failed to touch session");
        }
      }
  }

Also, with ICEFaces 1.8.2RC1 (and presumably eventually with the release version of ICEFaces 1.8.2 as well), there are two new workarounds available:

HttpServletRequest request = (HttpServletRequest) servletRequest; 
HttpSession session = request.getSession(); 
if (session != null) { 
    SessionDispatcher.Monitor.lookupSessionMonitor(session).touchSession(); 
}

Or, put this in the web.xml to update on any hit to URLs within a specific pattern:

<filter> 
    <filter-name>Touch Session</filter-name> 
    <filter-class>com.icesoft.faces.webapp.http.servlet.TouchSessionFilter</filter-class> 
</filter> 
<filter-mapping> 
    <filter-name>Touch Session</filter-name> 
    <url-pattern>/seam/remoting/*</url-pattern> 
</filter-mapping>
jsight
I'm facing similar problem. Where do you put the code above? Thanks
Tam
@Tam - Put it in any method that is invoked regularly by icefaces (eg, in the method invoked by a RenderManager)
jsight