Saturday, March 26, 2011

Implementing a visitor counter in Java

If you're running a Java-based site, here's how you can track the number of concurrent visitors on your site. The code can be easily extended to support a variety of functions, for example tracking who of your visitors is currently logged in.

Add this to each of your JSP/JSF files:

 SessionTracker tracker = SessionTracker.getInstance();
 String agent = request.getHeader("user-agent");

 if (agent != null) {

  // Check the user-agent from the request, we don't want to track crawlers. Add as many agents as you like to exclude.
  agent = agent.toLowerCase();
  if (agent.indexOf("googlebot") == -1 && agent.indexOf("msnbot") == -1 && agent.indexOf("slurp") == -1) {

   // Current version of Opera has a bug that causes it to make two requests to a page; the other one does not have a 'cookie' header set, so only regard the 'real' request

   if (agent.toLowerCase().indexOf("opera") != -1) {
    if (request.getHeader("cookie") != null) {
     tracker.trackSession(session);
    }
   } else {
    tracker.trackSession(session);
   }
  }
 } 


And on the page(s) where you wish to print the number of visitors, add:

<%=tracker.getNumberOfSessions()%>

The actual tracking class:

import java.util.*;
import javax.servlet.http.HttpSession;

public class SessionTracker extends Thread {
 private static SessionTracker instance = null;
 private static Hashtable<String, HttpSession> data = null;

 // How long to wait between visitor checks
 private static final int sleep = 60 * 1000;
 // How long a session can be idle until it is not counted
 private static final int reapTime = 10 * 60 * 1000;

 private SessionTracker() {
  data = new Hashtable<String, HttpSession>();
 }

 public static synchronized SessionTracker getInstance() {
  if (instance == null) {
   instance = new SessionTracker();
   instance.start();
  }

  return instance;
 }

 public void trackSession(HttpSession session) {
  data.put(session.getId(), session);
 }

 public int getNumberOfSessions() {
  return data.size();
 }

 public void run() {
  while (true) {
   instance = this;

   Enumeration<String> enu = data.keys();

   while (enu.hasMoreElements()) { 
    String key = enu.nextElement();
    HttpSession session = data.get(key);
 
    long diff = System.currentTimeMillis() - session.getLastAccessedTime();
 
    if (diff > reapTime) {
     data.remove(key);
    }
   }

   synchronized(this) {
    try {
     this.wait(sleep);
    } catch (Exception e) {
     e.printStackTrace();
    }
   }
  }
 }
}

No comments:

Post a Comment