JSF and PrimeFaces: Session Timeout Handling

Implementing session timeout handling in an ajax web application can be hard. You have to redirect to a login page when a single ajax call fails after user session is invalid.
My solution is based on PrimeFaces idle monitor. User is redirected to logout action after timeout to invalidate the session. 2 minutes before a countdown dialog is shown to warn user. After moving the mouse again session is extended.
PrimeFaces idle monitor and dialog is placed in a template you can add to every page which is involved:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<ui:composition>
<h:form prependId="false">
<p:idleMonitor
timeout="#{session.maxInactiveInterval * 1000 - 125000}"
onidle="startIdleMonitor()"
onactive="timeoutDialog.hide()" />
<p:dialog id="timeoutSession"
header="#{msg['session.expire']}"
widgetVar="timeoutDialog"
showEffect="fade" hideEffect="fade"
modal="true"
width="400"
height="110"
closable="false"
draggable="false"
resizable="false"
appendToBody="true"
onHide="stopCount()"
onShow="doTimer()">
<br />
<p>
<span class="ui-icon ui-icon-alert" style="float: left; margin: 8px 8px 0;"/>
<p:panel>
#{msg['logoff.soon.1']}
<span id="dialog-countdown" style="font-weight: bold"></span>
#{msg['logoff.soon.2']}
</p:panel>
</p>
<br />
<p style="font-weight: bold;">#{msg['move.cursor']}</p>
</p:dialog>
<p:remoteCommand name="keepAlive" actionListener="#{auth.keepSessionAlive}" />
</h:form>
<script type="text/javascript">
var TIME = 120; // in seconds
var countTimer = TIME;
var processTimer;
var timer_is_on = 0;
var redirectPage = "#{request.contextPath}/auth/j_verinice_timeout";
var countDownDiv = "dialog-countdown";
var txtCountDown = null;
if (!txtCountDown)
txtCountDown = document.getElementById(countDownDiv);
function startIdleMonitor() {
countTimer = TIME;
txtCountDown.innerHTML = countTimer;
timeoutDialog.show();
}
function timedCount() {
txtCountDown.innerHTML = countTimer;
if (countTimer == 0) {
stopCount();
window.location.href = redirectPage;
return;
}
countTimer = countTimer - 1;
processTimer = setTimeout("timedCount()", 1000);
}
function doTimer() {
if (!timer_is_on) {
timer_is_on = 1;
timedCount();
}
}
function stopCount() {
clearTimeout(processTimer);
timer_is_on = 0;
keepAlive();
}
</script>
</ui:composition>
</html>
- Line 11: The timeout of the idle monitor is set by system var session.maxInactiveInterval. The value you set in your web.xml or server configuration.
- Line 12/13: Javascript method startIdleMonitor() is called after timeout without any user interaction. This method opens the dialog. timeoutDialog.hide() is called when user is busy again: Dialog is closed
- Line 26/27: Two more Javascript methods are called when dialog is shown or hide: doTimer() starts and stopCount() stops the countdown.
- Line 40: PrimeFaces remote command to keep session alive. By calling an arbitrary method on server the session is extended. Command is called by Javascript method keepAlive() in line 78.
- Line 59-68: Javascript method timedCount() is called every second to execute the countdown. After timeout redirect is done in line 63.
To activate timeout handling in multiple pages include the timeout template in your layout template:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets" xml:lang="de-DE"> <h:head> ... </h:head> <body> <ui:include src="/template/sessionTimeOut.xhtml" /> <ui:include src="/nav.xhtml"/>> <ui:insert name="content">Default content</ui:insert> <ui:include src="/footer.xhtml"/>> </body> </html>
A specific time out for your web application you can set in your web.xml:
<!--?xml version="1.0" encoding="UTF-8"?-->
<web-app>
...
<session-config>
<!-- Session idle timeout in min. -->
<session-timeout>30</session-timeout>
</session-config>
</web-app>
Hi,
Thanks for great example. What does your keepSessionAlive() backing bean function look like?
Calling keepSessionAlive() stops idle time for the user session on application server. Just call an arbitrary getter in this method. I think it can even be empty.
Thanks for the response! Actually an empty method didnt extend the session in my case.
I had to add:
FacesContext fc = FacesContext.getCurrentnstance();
HttpServletRequest request = (HttpServletRequest) fc.getExternalContext().getRequest();
request.getSession();
to the keepSessionAlive() function
Now it works as expected.
Thanks again!
Take care that keepSessionAlive() is really called before session is expired by increasing the 120000 from line 11:
timeout=”#{session.maxInactiveInterval * 1000 – 125000}”
(I just changed the code sample in the article.)
dear murygin
this solution doesn’t work as idle monitor time out triggers only when that page is idle (i.e. not even mouse hovering on that page) and session will be timed out because of no request from page for specific time. to reproduce follow below steps
assumption:
* sessionMaxInterval is 3 minute (180 seconds)
* idle monitor timeout value is 125000 ms.
1. load the page move the mouse for 30 seconds
2. go to another page
3. idle monitor pop ups at 55th second which will count for 125 seconds
4. so total time here is 125+30+55 = 210 seconds
5. so if user moves mouse at last 2nd second of timer by that time session would already get invalidated.
Dear Kedar,
I am a beginner in JSF. Could you send to me an example of the classes used in this tutorial?
Dear Kedar,
The meaning of “idle” for PrimeFaces is no action at all (including mouse motion). The meaning “idle” for the server is no request from the client.
Unfortunately I don’t have a solution for this problem…
Daniel.