[ Team LiB ] Previous Section Next Section

Handling Session Termination

A session can be terminated in two ways: You force the termination by calling the invalidate method on the session, or the servlet engine times the session out. Depending on the kind of data you store in the session, you might need to perform some kind of cleanup of the session data. For example, you might have a database connection stored in the session. Although Java's garbage collector eventually eliminates these resources, you shouldn't keep them open any longer than you need to.

A session object has a callback mechanism to notify an object when it has been associated with a session and when it is no longer associated with a session. That is, when you call session.setAttribute("someName", someObject), the session object can notify the object that it is being associated with a session. When the session terminates, the session object can also notify the object that it is no longer associated with the session.

This notification is on an object-by-object basis. Although it might seem strange at first, the notification technique is actually very flexible. You can write objects that are session-aware and can perform their own cleanup. If you are using standard objects, such as a JDBC Connection object, you can create a special session cleanup object that releases your database connection.

The HttpSessionBindingListener Interface

The HttpSessionBindingListener interface defines notification methods that the session object uses to notify objects when they are added to or removed from a session. There are two methods in the interface:


public void valueBound(HttpSessionBindingEvent event);
public void valueUnbound(HttpSessionBindingEvent event);

As you might have guessed, valueBound is called when an object is added to a session; valueUnbound is called when the object is removed from a session. Listing 12.6 shows an example class that listens for valueBound and valueUnbound messages and counts the number of sessions that are bound to each instance of the class.

Listing 12.6 Source Code for BindListener.java
package examples;

import javax.servlet.http.*;

/** Counts the number of sessions that are bound to this object. */

public class BindListener implements HttpSessionBindingListener
{
// The current session count
    protected int numSessions;

    public BindListener()
    {
        numSessions = 0;
    }

// Every time this object is added to a session,
// valueBound is called.
    public synchronized void valueBound(HttpSessionBindingEvent event)
    {
        numSessions++;
    }

// Every time this object is removed from a session,
// valueUnbound is called.
    public synchronized void valueUnbound(HttpSessionBindingEvent event)
    {
        numSessions--;
    }

// Returns the current number of bound sessions
    public int getNumSessions()
    {
        return numSessions;
    }
}

To test the BindListener class, you need to observe what happens when you access it from multiple sessions and also see what happens when you invalidate a session that contains a BindListener object. You should expect to see the session count go up whenever the object is added to a session, and you should see the count go down when the object is removed from a session or when the session it belongs to is invalidated.

Listing 12.7 shows a test harness JSP that exercises the BindListener class. By selecting various hyperlinks, you can remove the BindListener object from the session or invalidate the session.

Listing 12.7 Source Code for BindTest.jsp
<%@ page language="java" import="examples.BindListener" %>

<html>
<body bgcolor="#ffffff">

<%-- Set up a static BindListener shared by all instances of this JSP.

     There is probably only one instance, but just in case the server creates

     multiple instances, this page can handle it. --%>
<%!
    protected static BindListener listener = new BindListener();
%>

<%

    BindListener l = null;

// Allow the browser to pass a "removeListener" parameter to remove
// a listener from the session.

    if (request.getParameter("removeListener") != null)
    {
        session.removeAttribute("listener");
    }

// Allow the browser to pass a resetSession parameter to clear out
// the session.
    else if (request.getParameter("resetSession") != null)
    {
// See whether there is already a session.
        HttpSession oldSession = request.getSession(false);

// If there is already a session, invalidate it.
        if (oldSession != null)
        {
            l = (BindListener)
                oldSession.getAttribute("listener");
            oldSession.invalidate();

// Tell the user that the session was reset and show that the
// bind counts have been updated. Make sure that there was a
// listener on the old session, too.

            if (l != null)
            {
%>
Your current session was reset. The listener now has <%=l.getNumSessions()%>
active sessions.<p>
<%
            } else {
%>
Your old session didn't have a listener.<p>
<%
            }

            l = null;
        }
    }
    else
    {
// See if the listener is already in the session.
         l = (BindListener)
            session.getAttribute("listener");

// If not, add the global copy of the listener to the session.
        if (l == null)
        {
// Put the global listener variable into the session.
            session.setAttribute("listener", listener);
            l = listener;
        }
    }
%>
<%
    if (l != null)
    {
%>
You have a listener bound to your session.
<%
    } else {
%>
You do not have a listener bound to your session.
<%
    }
%>
There are currently <%=listener.getNumSessions()%> sessions holding onto the
bind listener.
<p>
<table>
<tr>
<td>
<A href="BindTest.jsp">Refresh Form</A>
<td>
<A href="BindTest.jsp?removeListener">Remove Listener</A>
<td>
<A href="BindTest.jsp?resetSession">Reset Session</A>
</table>
</body>
</html>

Figure 12.5 shows several browser sessions running BindTest.jsp.

Figure 12.5. The BindListener object keeps track of how many sessions it belongs to.

graphics/12fig05.jpg

The HttpSessionListener and HttpSessionActivationListener Interfaces

Because sessions are not permanent, it's useful to know when a session is about to go away. Conversely, it's also helpful to know when they are created. Objects that are associated with sessions can receive notification of lifecycle events so that they can respond appropriately. For example, if an object provided a session specific access to a file, you would want to make sure that the file was opened on session creation and was flushed and closed when the session ended.

Objects that want to know when a session is created or destroyed can implement the HttpSessionListener interface. It consists of only two methods:


public void sessionCreated(HttpSessionEvent se)
public void sessionDestroyed(HttpSessionEvent se)

Unlike an object that implements the HttpSessionBindingListener interface, you must configure the class to receive events in the deployment descriptor for the Web application. In addition to creating and destroying sessions, some containers may also passivate and activate sessions. A container that passivates a session puts it away momentarily. Sometime later, the session may be returned to service, or activated. Containers may do this to persist or migrate sessions, so that requests can be handled by several Java Virtual Machines (JVMs). By implementing the HttpSessionActivationListener interface, objects can receive notification of passivation or activation.


public void sessionDidActivate(HttpSessionEvent se)
public void sessionWillPassivate(HttpSessionEvent se)
    [ Team LiB ] Previous Section Next Section