Saturday, August 29, 2009

Tracking User Sessions in a web application using Java

Sometimes we would like to keep track after users in our web application. We would like to see how many active sessions we have and even which of the users are guests and which are logged. Java supplied an Interfaces called HttpSessionListener that can help us achieving this goal. This interface supplies 2 methods:

  • sessionCreated – Activated when a new session is created.
  • sessionDestroyed – Activated when session expires and being deleted from server.

Using this 2 methods we can implement our own Session Tracker. We will store all the currently active sessions in a Set.

This is our SessionTracker class implementing HttpSessionListener. The code is pretty straight forward and easy to understand:

package com.bashan.blog.session;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import java.util.*;
public class SessionTracker implements HttpSessionListener {
  private static Set<HttpSession> sessions = new HashSet<HttpSession>();
  public void sessionCreated(HttpSessionEvent httpSessionEvent) {
    sessions.add(httpSessionEvent.getSession());
  }
  public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
    sessions.remove(httpSessionEvent.getSession());
  }
  public static List<HttpSession> getSessions() {
    List<HttpSession> sessionsList = new ArrayList<HttpSession>(sessions);
    Collections.sort(sessionsList, new SessionComparator());
    return Collections.unmodifiableList(sessionsList);
  }
  public static class SessionComparator implements Comparator<HttpSession> {
    public int compare(HttpSession session1, HttpSession session2) {
      return (int) (session1.getLastAccessedTime() - session2.getLastAccessedTime());
    }
  }
}

Note that we return the currently active sessions as a list sorted according to the last access time. Of course, you can choose another way of sorting the sessions. In addition, note that we are using a static Set member in order to store all the active sessions. You might want to consider synchronization when adding or removing objects to/from the set. I believe that the chances of a synchronization issues in this case are pretty low, but sometimes it is better not taking any chances… ;-)

Our next step is to register our SessionTracker, so the Web Server will be able to use it. This is done in the web.xml file of our Web Server. considering our web server web.xml was empty, after registering the SessionTracker it should look like:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         version="2.5">
  <listener>
    <listener-class>
      com.bashan.blog.session.SessionTracker
    </listener-class>
  </listener>
</web-app>

Now, suppose we would like to see all the active sessions in our web application. We can write a small JSP page that will show a table of all active sessions:

<%@ page import="com.bashan.blog.session.SessionTracker" %>
<%@ page import="java.util.List" %>
<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>Active Sessions</title>
    <style type="text/css">
      .bold
      {
          font-weight:bold;
      }
      .tableBorder
        {
          BORDER-RIGHT: #000000 1px solid;
          BORDER-TOP: 0px;
          BORDER-LEFT: 0px;
          BORDER-BOTTOM: #000000 1px solid
        }
      .tdBorder
        {
          BORDER-RIGHT: 0px;
          BORDER-TOP: #000000 1px solid;
          BORDER-LEFT: #000000 1px solid;
          BORDER-BOTTOM: 0px
        }
    </style>
  </head>
  <body>
  <table class="tableBorder" cellpadding="4" cellspacing="0">
    <tr>
      <td class="tdBorder bold">
        Last Activity
      </td>
      <td class="tdBorder bold">
        Created
      </td>
      <td class="tdBorder bold">
        Session ID
      </td>
    </tr>
    <%
      List<HttpSession> sessions = SessionTracker.getSessions();
      for (HttpSession currentSession : sessions)
      {
    %>
    <tr>
      <td class="tdBorder">
        <%= new Date(currentSession.getLastAccessedTime()) %>
      </td>
      <td class="tdBorder">
        <%= new Date(currentSession.getCreationTime()) %>
      </td>
      <td class="tdBorder">
        <%= currentSession.getId() %>
      </td>
    </tr>
    <%
      }
    %>
  </table>
  </body>
</html>
Assuming your web application allow users to login to the system, you probably store logged user information in the Session. It will be nice adding a column showing logged user details like user name, email or any other important information.

No comments:

Post a Comment