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 sessionDestroyed(HttpSessionEvent se)
sessionCreated() is called when a new session is created. All that’s left is setting the required timeout there:
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 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:
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:
<listener>
<listener-class>org.jboss.seam.servlet.SeamListener</listener-class>
</listener>
<listener>
<listener-class>com.duckranger.TimeoutConfigListener</listener-class>
</listener>
Popularity: 11% [?]