views:

78

answers:

1

Is there a way to determine the number of active sessions created from a given client IP address?

+2  A: 

The standard Servlet API doesn't offer facilities for that. Best what you can do is to maintain a Map<HttpSession, String> yourself (where the String is the IP address) with and check on every ServletRequest if the HttpSession#isNew() and add it to the Map along with ServletRequest#getRemoteAddr(). Then you can get the amount of IP addresses with an active session using Collections#frequency() on Map#values(). You only need to ensure that you remove the HttpSession from the Map during HttpSessionListener#sessionDestroyed().

This all can be done in a single Listener implementing the ServletContextListener, HttpSessionListener and ServletRequestListener.

Here's a kickoff example:

public class SessionCounter implements ServletContextListener, HttpSessionListener, ServletRequestListener {

    private static final String ATTRIBUTE_NAME = "com.example.SessionCounter";
    private Map<HttpSession, String> sessions = new HashMap<HttpSession, String>();

    @Override
    public void contextInitialized(ServletContextEvent event) {
        event.getServletContext().setAttribute(ATTRIBUTE_NAME, this);
    }

    @Override
    public void requestInitialized(ServletRequestEvent event) {
        HttpServletRequest request = (HttpServletRequest) event.getServletRequest();
        HttpSession session = request.getSession();
        if (session.isNew()) {
            sessions.put(session, request.getRemoteAddr());
        }
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent event) {
        sessions.remove(event.getSession());
    }

    @Override
    public void sessionCreated(HttpSessionEvent event) {
        // NOOP. Useless since we can't obtain IP here.
    }

    @Override
    public void requestDestroyed(ServletRequestEvent event) {
        // NOOP. No logic needed.
    }

    @Override
    public void contextDestroyed(ServletContextEvent event) {
        // NOOP. No logic needed. Maybe some future cleanup?
    }

    public static SessionCounter getInstance(ServletContext context) {
        return (SessionCounter) context.getAttribute(ATTRIBUTE_NAME);
    }

    public int getCount(String remoteAddr) {
        return Collections.frequency(sessions.values(), remoteAddr);
    }

}

Define it in web.xml like follows:

<listener>
    <listener-class>com.example.SessionCounter</listener-class>
</listener>

You can use it in any servlet like follows:

SessionCounter counter = SessionCounter.getInstance(getServletContext());
int count = counter.getCount("127.0.0.1");
BalusC
I would have used a WeakHashMap on Sessions do avoid to listen to sessions. I was thinking about a `Map<String, List<HttpSession>>` first, but handle manually sessions destruction seems pretty heavy for me.
Colin Hebert
@Colin: You're then dependent on the eagerness of the GC. This makes it all less solid. It's not a cache or so.
BalusC