Session Timeouts with GWT RPC calls

Posted: July 20, 2011 in eBayOpenSource, GWT RPC, session timeout

Working with GWT has a number of benefits but in the other hand we could get some cons and troubles that you’ll need to solve by yourself. That’s the case for a user Session Timeout, for example. While in an ordinary JSP servlet you could have total control of a user session and its actions, due to the client resident feature of GWT, things turns a bit complicated….

Last Friday I was working on a Session Timeout feature for Turmeric, an eBay Open Source platform. In the next lines I’m gonna show you how I did it , anyways you can surf these updates at my git-hub home.

Based on GWT RPC call mechanism and a few timers, I added a new service into Policy Admin UI (the web project to manage policies in Turmeric), called SessionServiceImpl, which implements RemoteServiceServlet and extends my service. This servlet instance, as usual will reside in the server side of my app.  Then I added the two interfaces needed for RPC calls, SessionInterface and SessionInterfaceAsync, and its implementation.

public class SessionServiceImpl extends RemoteServiceServlet implements
SessionInterface {

private static final long serialVersionUID = 1L;

private int timeout;

@Override
public Integer getUserSessionTimeout() {

timeout = getThreadLocalRequest().getSession().getMaxInactiveInterval() * 1000;
return timeout;
}

@Override
public Boolean isSessionAlive() {

return new Boolean((System.currentTimeMillis() - getThreadLocalRequest().getSession()
.getLastAccessedTime()) < timeout);
}

@Override
public void ping() {

}

}

This Servlet has its own time counters for user logged. Why I had to create a specific time member instead of using the HTTPSession ones? Since  of GWT genned code resides on client machines, the server session is not updated until a new RPC call be made by user, ie FindByXXXX, createXXX methods and so on… So, in the user does some clicks on the left side tree menu, the last accessed time at HTTPSession will not be automatically updated. Now since in our GWT  app a common dispatcher should be the selectPresenter method under the Controller, I preferred to use it as a common entry point to notify the session updates, just calling to a ping method. .

the SessionService interface:


public interface SessionInterface extends RemoteService {
Integer getUserSessionTimeout();
Boolean isSessionAlive();
void ping();
}
<pre>

the asyncronous one, at your client side. Our  code will call the sessionService but it will not wait for a reply as in synch way. The response will came later…who knows…

public interface SessionInterfaceAsync  {
void getUserSessionTimeout(AsyncCallback<Integer> callback);
void isSessionAlive(AsyncCallback<Boolean> callback);
void ping(AsyncCallback callback);
}

Later, since GWT 1.6, if I recall correctly, you could add your servlets into your *.gwt.xml file instead of your web.xml file. I’m on GWT 2.2 so I added these lines into our PolicyAdminUI.gwt.xml file:

<servlet path="/sessionService" class="org.ebayopensource.turmeric.policy.adminui.server.SessionServiceImpl"/>

and finally in the web.xml a new property to set the timeout configurable:

<!--  session timeout in minutes -->
<session-config>
    <session-timeout>15</session-timeout>
 </session-config>

and here is how my appController looks like:

//this method is called when the controller starts and bind...
private void initSessionTimers() {
sessionService.getUserSessionTimeout(new AsyncCallback<Integer>() {
public void onSuccess(Integer timeout) {
timeoutCicle = timeout;
sessionTimeoutResponseTimer = new Timer() {
@Override
public void run() {
isSessionAlive();
}
};
sessionTimeoutResponseTimer.schedule(timeout);
}

public void onFailure(Throwable caught) {
               //throw custom errors
}
});

}

private void isSessionAlive() {
sessionService.isSessionAlive(new AsyncCallback<Boolean>() {
public void onSuccess(Boolean alive) {
if (alive.booleanValue()) {
sessionTimeoutResponseTimer.cancel();
sessionTimeoutResponseTimer.scheduleRepeating(timeoutCicle);
} else {
displaySessionTimedOut();
}

}

public void onFailure(Throwable caught) {
//throw custom errors
}
});

}

private void displaySessionTimedOut() {
Window.alert(PolicyAdminUIUtil.messages
.expiredSession());
Window.Location.reload();

}

private void updateSessionLastAccessedTime() {
sessionService.ping(new AsyncCallback<Object>() {
public void onSuccess(Object paramT) {
//do nothing
}

public void onFailure(Throwable caught) {
//throw custom errors
}

});

}

that’s all folks,
hope it helps somebody….

About these ads
Comments
  1. Ming says:

    I’m trying to do similar work too. But my problem is that, if I made the RPC call to check the time left on server, the call I made is not just checking the time left, it also resets the “getLastAccessedTime” as well. So, if I check the “getLastAccessedTime” again next time, it will very likely see my own server call, instead of the users’ server call. I think it makes sense since I indeed have accessed the server by doing the RPC call. How can I make a RPC call to check the real users’ lastAccessTime instead of my getLastAccessedTime server call? Many thanks!

  2. josealvarezmuguerza says:

    naturally, as you mentioned, the lastAccessedTime should be … the last one, through the getRemainingTime().

    Following my example the getThreadLocalRequest().getSession()
    .getLastAccessedTime() value could be stored in a new synchronized member. Then within isSessionAlive() method you could check its value and override it.
    Finally create a new getRemainingTime() which does not override the new member with getThreadLocalRequest().getSession()
    .getLastAccessedTime()

    regards

  3. Ming says:

    Thanks for the reply. I think I am a little confused. :) How can you fix the value of the lastAccessTime? Doesn’t the value get changed every time the method gets called?

    Is this something you recommended? I put my questions inside the code. Thanks a lot!

    public class SessionServiceImpl extends RemoteServiceServlet implements
    SessionInterface {

    private static final long serialVersionUID = 1L;

    private int timeout;

    // add this new class variable
    private int lastAccessTime;

    @Override
    public Integer getUserSessionTimeout() {

    timeout = getThreadLocalRequest().getSession().getMaxInactiveInterval() * 1000;
    return timeout;
    }

    // add the method to set lastAccessTime; but won’t it be changed every time I tried to check the lastAccessTime?

    @Override
    public long getLastAccessedTime() {
    lastAccessTime = getThreadLocalRequest().getSession().getLastAccessedTime().
    return lastAccessTime ;
    }

    @Override
    public Boolean isSessionAlive() {

    long howLongAgo = System.currentTimeMillis() – lastAccessTime;

    // how do I need to reset the lastAccessTime?

    return new Boolean((System.currentTimeMillis() – getThreadLocalRequest().getSession()
    .getLastAccessedTime()) < timeout);
    }

    // add getRemainingTime
    @Override
    public Long getRemainingTime() {

    long remainingTime = timeout – (System.currentTimeMillis() – lastAccessTime);
    return remainingTime;

    }

    @Override
    public void ping() {

    }

    }

  4. josealvarezmuguerza says:

    take care with your code, remember java servlets are not php code, so your new class member seems to be shared by all your users.
    finally, in your isSessionAlive method you can use the new member.

  5. Ming says:

    Thanks for your reply. I think I can put the LastAccessTime and RemainingTime as session variables to avoid being shared by all users.

    But here is my scenarios:

    1) 11:00:00 user logged in. Session established.
    Time started (59 min timer; I gave one minute before server times out to give user a reminder window and make the server call )
    LastAccessTime session variable is set to 11:00:00.
    RemainingTime session variable is set to 60min

    2) 11:05:00 user made a server call.

    3) 11:59:00, timer runs out.
    Calculate remaining time:
    TotalServerTime(60) – (CurrentTime – realUserLastAccessTime).
    Because it’s the first time the timer kicks in, the

    realUserLastAccessTime = session.getLastAccessTime().

    Reset remainingTime to 6 min.
    Reset LastAccessTime to 11:05:00
    Rest Timer to 6 min.

    (user may or may not have accessed server between 11:59:00 and 12:04:00)

    4). 12:04:00, the new timer set in step 3 runs out.
    calculate remaining time.
    But at this point, how can I decide user has or has not accessed the server between the first timer and this new timer (5 min window)? I’m thinking about the logic below:

    if (currentTime – session.getLastAccessTime < remainingTime session variable – 1 min)

    then, user has accessed the server.

    reset LastAccessTime and RemainingTime session variable.

    Otherwise, return time left (which is 1 min) back to client. Reminder will show.

    But my concern is that the logic in step 4 isn't very reliable because

    currentTime – session.getLastAccessTime will either less or equal to (remainingTime variable -1 min). It cannot be bigger. In other words, I'm replying on an exact match in milliseconds.

    I really want to use the server side lastAccessTime to decide the real user access time. But it seems to be quite difficult.

    Thanks!

  6. […] How to implement a Session Timeout with GWT RPC Calls. A real case in an open source SOA Governance project    Web Services Read the original post on DZone… […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s