View Javadoc

1   package org.appfuse.webapp.listener;
2   
3   import org.appfuse.model.User;
4   import org.springframework.security.authentication.AuthenticationTrustResolver;
5   import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
6   import org.springframework.security.core.Authentication;
7   import org.springframework.security.core.context.SecurityContext;
8   import org.springframework.security.core.context.SecurityContextHolder;
9   import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
10  
11  import javax.servlet.ServletContext;
12  import javax.servlet.ServletContextEvent;
13  import javax.servlet.ServletContextListener;
14  import javax.servlet.http.HttpSessionAttributeListener;
15  import javax.servlet.http.HttpSessionBindingEvent;
16  import javax.servlet.http.HttpSessionEvent;
17  import javax.servlet.http.HttpSessionListener;
18  import java.util.LinkedHashSet;
19  import java.util.Set;
20  
21  
22  /**
23   * UserCounterListener class used to count the current number
24   * of active users for the applications.  Does this by counting
25   * how many user objects are stuffed into the session.  It also grabs
26   * these users and exposes them in the servlet context.
27   *
28   * @author <a href="mailto:matt@raibledesigns.com">Matt Raible</a>
29   */
30  public class UserCounterListener implements ServletContextListener, HttpSessionAttributeListener, HttpSessionListener {
31      /**
32       * Name of user counter variable
33       */
34      public static final String COUNT_KEY = "userCounter";
35      /**
36       * Name of users Set in the ServletContext
37       */
38      public static final String USERS_KEY = "userNames";
39      /**
40       * The default event we're looking to trap.
41       */
42      public static final String EVENT_KEY = HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY;
43      private transient ServletContext servletContext;
44      private int counter;
45      private Set<User> users;
46  
47      /**
48       * Initialize the context
49       *
50       * @param sce the event
51       */
52      public synchronized void contextInitialized(ServletContextEvent sce) {
53          servletContext = sce.getServletContext();
54          servletContext.setAttribute((COUNT_KEY), Integer.toString(counter));
55      }
56  
57      /**
58       * Set the servletContext, users and counter to null
59       *
60       * @param event The servletContextEvent
61       */
62      public synchronized void contextDestroyed(ServletContextEvent event) {
63          servletContext = null;
64          users = null;
65          counter = 0;
66      }
67  
68      synchronized void incrementUserCounter() {
69          counter = Integer.parseInt((String) servletContext.getAttribute(COUNT_KEY));
70          counter++;
71          servletContext.setAttribute(COUNT_KEY, Integer.toString(counter));
72      }
73  
74      synchronized void decrementUserCounter() {
75          int counter = Integer.parseInt((String) servletContext.getAttribute(COUNT_KEY));
76          counter--;
77  
78          if (counter < 0) {
79              counter = 0;
80          }
81  
82          servletContext.setAttribute(COUNT_KEY, Integer.toString(counter));
83      }
84  
85      @SuppressWarnings("unchecked")
86      synchronized void addUsername(User user) {
87          users = (Set<User>) servletContext.getAttribute(USERS_KEY);
88  
89          if (users == null) {
90              users = new LinkedHashSet<User>();
91          }
92  
93          if (!users.contains(user)) {
94              users.add(user);
95              servletContext.setAttribute(USERS_KEY, users);
96              incrementUserCounter();
97          }
98      }
99  
100     @SuppressWarnings("unchecked")
101     synchronized void removeUsername(User user) {
102         users = (Set<User>) servletContext.getAttribute(USERS_KEY);
103 
104         if (users != null) {
105             users.remove(user);
106         }
107 
108         servletContext.setAttribute(USERS_KEY, users);
109         decrementUserCounter();
110     }
111 
112     /**
113      * This method is designed to catch when user's login and record their name
114      *
115      * @param event the event to process
116      * @see javax.servlet.http.HttpSessionAttributeListener#attributeAdded(javax.servlet.http.HttpSessionBindingEvent)
117      */
118     public void attributeAdded(HttpSessionBindingEvent event) {
119         if (event.getName().equals(EVENT_KEY) && !isAnonymous()) {
120             SecurityContext securityContext = (SecurityContext) event.getValue();
121             if (securityContext != null && securityContext.getAuthentication().getPrincipal() instanceof User) {
122                 User user = (User) securityContext.getAuthentication().getPrincipal();
123                 addUsername(user);
124             }
125         }
126     }
127 
128     private boolean isAnonymous() {
129         AuthenticationTrustResolver resolver = new AuthenticationTrustResolverImpl();
130         SecurityContext ctx = SecurityContextHolder.getContext();
131         if (ctx != null) {
132             Authentication auth = ctx.getAuthentication();
133             return resolver.isAnonymous(auth);
134         }
135         return true;
136     }
137 
138     /**
139      * When user's logout, remove their name from the hashMap
140      *
141      * @param event the session binding event
142      * @see javax.servlet.http.HttpSessionAttributeListener#attributeRemoved(javax.servlet.http.HttpSessionBindingEvent)
143      */
144     public void attributeRemoved(HttpSessionBindingEvent event) {
145         if (event.getName().equals(EVENT_KEY) && !isAnonymous()) {
146             SecurityContext securityContext = (SecurityContext) event.getValue();
147             Authentication auth = securityContext.getAuthentication();
148             if (auth != null && (auth.getPrincipal() instanceof User)) {
149                 User user = (User) auth.getPrincipal();
150                 removeUsername(user);
151             }
152         }
153     }
154 
155     /**
156      * Needed for Acegi Security 1.0, as it adds an anonymous user to the session and
157      * then replaces it after authentication. http://forum.springframework.org/showthread.php?p=63593
158      *
159      * @param event the session binding event
160      * @see javax.servlet.http.HttpSessionAttributeListener#attributeReplaced(javax.servlet.http.HttpSessionBindingEvent)
161      */
162     public void attributeReplaced(HttpSessionBindingEvent event) {
163         if (event.getName().equals(EVENT_KEY) && !isAnonymous()) {
164             final SecurityContext securityContext = (SecurityContext) event.getValue();
165             if (securityContext.getAuthentication() != null
166                     && securityContext.getAuthentication().getPrincipal() instanceof User) {
167                 final User user = (User) securityContext.getAuthentication().getPrincipal();
168                 addUsername(user);
169             }
170         }
171     }
172     
173     public void sessionCreated(HttpSessionEvent se) { 
174     }
175     
176     public void sessionDestroyed(HttpSessionEvent se) {
177         Object obj = se.getSession().getAttribute(EVENT_KEY);
178         if (obj != null) {
179             se.getSession().removeAttribute(EVENT_KEY);
180         }
181     }
182 }