/******************************************************************************* * Gisgraphy Project * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA * * Copyright 2008 Gisgraphy project * David Masclet <davidmasclet@gisgraphy.com> * * *******************************************************************************/ package com.gisgraphy.webapp.listener; import java.util.LinkedHashSet; import java.util.Set; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionBindingEvent; import org.springframework.security.authentication.AuthenticationTrustResolver; import org.springframework.security.authentication.AuthenticationTrustResolverImpl; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.context.HttpSessionSecurityContextRepository; import com.gisgraphy.model.User; /** * UserCounterListener class used to count the current number of active users * for the applications. Does this by counting how many user objects are stuffed * into the session. It Also grabs these users and exposes them in the servlet * context. * * @author <a href="mailto:matt@raibledesigns.com">Matt Raible</a> */ public class UserCounterListener implements ServletContextListener, HttpSessionAttributeListener { /** * Name of user counter variable */ public static final String COUNT_KEY = "userCounter"; /** * Name of users Set in the ServletContext */ public static final String USERS_KEY = "userNames"; /** * The default event we're looking to trap. */ public static final String EVENT_KEY = HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY; private transient ServletContext servletContext; private int counter; private Set<User> users; /** * Initialize the context * * @param sce * the event */ public synchronized void contextInitialized(ServletContextEvent sce) { servletContext = sce.getServletContext(); servletContext.setAttribute((COUNT_KEY), Integer.toString(counter)); } /** * Set the servletContext, users and counter to null * * @param event * The servletContextEvent */ public synchronized void contextDestroyed(ServletContextEvent event) { servletContext = null; users = null; counter = 0; } synchronized void incrementUserCounter() { counter = Integer.parseInt((String) servletContext .getAttribute(COUNT_KEY)); counter++; servletContext.setAttribute(COUNT_KEY, Integer.toString(counter)); } synchronized void decrementUserCounter() { int counter = Integer.parseInt((String) servletContext .getAttribute(COUNT_KEY)); counter--; if (counter < 0) { counter = 0; } servletContext.setAttribute(COUNT_KEY, Integer.toString(counter)); } @SuppressWarnings("unchecked") synchronized void addUsername(User user) { users = (Set) servletContext.getAttribute(USERS_KEY); if (users == null) { users = new LinkedHashSet<User>(); } if (!users.contains(user)) { users.add(user); servletContext.setAttribute(USERS_KEY, users); incrementUserCounter(); } } @SuppressWarnings("unchecked") synchronized void removeUsername(User user) { users = (Set<User>) servletContext.getAttribute(USERS_KEY); if (users != null) { users.remove(user); } servletContext.setAttribute(USERS_KEY, users); decrementUserCounter(); } /** * This method is designed to catch when user's login and record their name * * @see javax.servlet.http.HttpSessionAttributeListener#attributeAdded(javax.servlet.http.HttpSessionBindingEvent) * @param event * the event to process */ public void attributeAdded(HttpSessionBindingEvent event) { if (event.getName().equals(EVENT_KEY) && !isAnonymous()) { SecurityContext securityContext = (SecurityContext) event .getValue(); if (securityContext.getAuthentication().getPrincipal() instanceof User) { User user = (User) securityContext.getAuthentication() .getPrincipal(); addUsername(user); } // Workaround for Jetty bug // (http://www.nabble.com/current-user-count-incorrect-tf3550268.html#a9919134) } else if (event .getName() .equals( "SPRING_SECURITY_LAST_USERNAME")) { String username = (String) event.getValue(); User user = new User(username); addUsername(user); } } private boolean isAnonymous() { AuthenticationTrustResolver resolver = new AuthenticationTrustResolverImpl(); SecurityContext ctx = SecurityContextHolder.getContext(); if (ctx != null) { Authentication auth = ctx.getAuthentication(); return resolver.isAnonymous(auth); } return true; } /** * When user's logout, remove their name from the hashMap * * @see javax.servlet.http.HttpSessionAttributeListener#attributeRemoved(javax.servlet.http.HttpSessionBindingEvent) * @param event * the session binding event */ public void attributeRemoved(HttpSessionBindingEvent event) { if (event.getName().equals(EVENT_KEY) && !isAnonymous()) { SecurityContext securityContext = (SecurityContext) event .getValue(); Authentication auth = securityContext.getAuthentication(); if (auth != null && (auth.getPrincipal() instanceof User)) { User user = (User) auth.getPrincipal(); removeUsername(user); } } } /** * Needed for Acegi Security 1.0, as it adds an anonymous user to the * session and then replaces it after authentication. * http://forum.springframework.org/showthread.php?p=63593 * * @see javax.servlet.http.HttpSessionAttributeListener#attributeReplaced(javax.servlet.http.HttpSessionBindingEvent) * @param event * the session binding event */ public void attributeReplaced(HttpSessionBindingEvent event) { if (event.getName().equals(EVENT_KEY) && !isAnonymous()) { SecurityContext securityContext = (SecurityContext) event .getValue(); if (securityContext.getAuthentication() != null) { if (securityContext.getAuthentication().getPrincipal() instanceof User) { User user = (User) securityContext.getAuthentication() .getPrincipal(); addUsername(user); } } } } }