Curious minds...

In a recent application, the customer wanted to be able to change session timeout dynamically, without restarting the application.
This being a Seam application, I thought it was going to be quite straight-forward: either add it in the timeout= attribute in pages.xml, or just add it wherever we start a new conversation (conversation timeout is effectively what we were looking for anyway).

But, I was wrong.

For starters, the timeout= attribute does not take an EL expression. You can only have a numeric value there. So much for setting it dynamically.
The other thing is – we never start conversations manually – only with pages.xml directives. And I really didn’t want to change the entire conversation management, or dig into Seam code for that matter.

Some google-searches later and I found the HTTP session listener.

The HTTP session listener is a small class you can configure in web.xml, that captures session creation. It has two methods:

void sessionCreated(HttpSessionEvent se);
void sessionDestroyed(HttpSessionEvent se)

sessionCreated() is called when a new session is created. All that’s left is setting the required timeout there:

@Override
public void sessionCreated(HttpSessionEvent se) {
    HttpSession session = se.getSession();
    session.setMaxInactiveInterval(60); //in seconds
}

This is all very nice when you know the session timeout – but if you know it in advance – what’s the use of adding this listener? Just configure components.xml and be done with it.

Getting the timeout configuration value from a database

In our application we have an ApplicationParameterService Seam component. It exposes a method to fetch a configuration value from the database’s configuration table. Sweet. Let’s use it in the session listener:

public class TimeoutConfigListener implements HttpSessionListener {
   
    public static final int TIMEOUT_ID = 70;

    @Override
    public void sessionCreated(HttpSessionEvent se) {
        HttpSession session = se.getSession();
        ApplicationParameterService applicationParameterService =
            (ApplicationParameterService) Component.getInstance( "applicationParameterService" );
        String timeout = applicationParameterService.getParameterById( TIMEOUT_ID );
        session.setMaxInactiveInterval(60 * Integer.parseInt( timeout ));
    }

    @Override
    public void sessionDestroyed( HttpSessionEvent se) {

    }

}

So – in the listener, I ask Seam for the application parameter service, look up the session timeout value, which I get in minutes, and set it (transposed into seconds) on the session. No sweat.

Ah, but a little sweat.
Seam throws an IllegalStateException – No application context. This is a weired Seam phenomenon, where even though the application is running (and in fact, the login page uses the ApplicationParameterService) – there’s no active context at the time that the listener is called.

This can be solved by forcing an application context if there is none:

@Override
    public void sessionCreated(HttpSessionEvent se) {
        HttpSession session = se.getSession();
        if (!Contexts.isApplicationContextActive()) {
            Lifecycle.beginCall();
        }
        ApplicationParameterService applicationParameterService =
            (ApplicationParameterService) Component.getInstance( "applicationParameterService" );
        String timeout = applicationParameterService.getParameterById( TIMEOUT_ID );
        int timeoutSeconds = 60 * Integer.parseInt( timeout );
        session.setMaxInactiveInterval(timeoutSeconds);
    }

and that’s it.

To have the listener capture session creation – you need to add it to web.xml. Make sure you keep Seam’s listener as the first one in the listeners list though. Seam needs it this way:

<!-- in web.xml -->
<listener>
    <listener-class>org.jboss.seam.servlet.SeamListener</listener-class>
</listener>
<listener>
    <listener-class>com.duckranger.TimeoutConfigListener</listener-class>
</listener>

Popularity: 19% [?]

Tagged with:
 

One Response to Setting session timeout dynamically with Seam

  1. Jorge Bautista says:

    This article was nice, clean and very useful. You have been bookmarked.

    I have a question: Does the sentence “Lifecycle.beginCall();” has any secondary effects? I’ve never seen it before.

    Thanks!

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>