Friday, June 8, 2012

Session Timeouts with Vaadin's Refresher Add-on

The Refresher add-on for Vaadin refreshes the UI without user input, allowing it to display information that has changed asynchronously on the server. It adds an invisible component to the client web page which polls the server for changes. A matching server-side handler is called when the server is polled.

Refresher is among the most popular Vaadin add-ons, but adding a poll (or push) mechanism  to a Java EE application can be dangerous in terms of user sessions. The servlet container doesn't distinguish automatic poll requests from any user-initiated request, so the session will never time out on its own.

This blog shows an example of manually tracking user requests in order to time out sessions properly. The application is contained in this one class (linked here for reference). You can get the whole application in this zip file that includes pom.xml for building and a session listener to see when sessions start and end.

Note the README file: you have to build with the -Pcompile-widgetset option the first time because we're using a Vaadin add-on. Thank you to this blog for showing me how to put the widget compilation into its own profile!

The code is heavily commented to explain how user activity is tracked, but here is a summary:

  1. Using the HttpServletRequestListener interface we can note when a request comes in and compare the time of the request to the time of the previous one. If it's been X minutes, end the session.
  2. But we don't want to note the time of every request. So in step 1 we note the current time, but save the previous one (like pushing the time onto a stack). If the Refresher.RefreshListener is called, we know this isn't user input, so we can discard the current request time and only consider the older one (popping the stack).
  3. At this point, we can now compare the current request time to the older one and make a decision about ending the session.
In the above scenario, you can see that the session-timeout decision is only ever made in the refresher listener. It can't be in the onRequestStart() method because we don't know what kind of request it is (unless you want to parse the request stream!). We also can't end the session in that method because it causes an error within Vaadin. You could make this decision in every listener in your application if you wanted to, but I think the refresher is fine. Since it runs every N seconds, at the most a session will be N seconds longer than normal.

This description of the application is also contained in the source code:

 Simple app with a label and start button. When a user first loads the
 page, there are no automatic refresher calls happening and the container
 will timeout the session normally.
 Clicking the button starts the refresher, mimicking a user logging into
 the 'real' application UI. Whenever the UI is refreshed, it updates
 the label with a new value. This represents the UI reading state from
 another resource such as a database, which is constantly updated by
 other threads. For our simple case, we just show how much time we
 have left before ending the session.

The application was deployed and tested on a GlassFish 3.1.2 server (the Java EE reference implementation), but it should work on any Servlet 3.X container.

While the application works as-is, there is another aspect to consider that I will (hopefully) cover later. Some components will reload their data when a page is refreshed, for instance a Table that only shows a subset of its rows. In this case, the refresh call will force tables to make subsequent calls back to the server, extending the session. I'll add tables and their request handling to this sample application in a separate blog.