View Javadoc

1   /* Copyright 2004, 2005 Acegi Technology Pty Limited
2    *
3    * Licensed under the Apache License, Version 2.0 (the "License");
4    * you may not use this file except in compliance with the License.
5    * You may obtain a copy of the License at
6    *
7    *     http://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  
16  package org.acegisecurity.concurrent;
17  
18  import java.util.ArrayList;
19  import java.util.Collections;
20  import java.util.Date;
21  import java.util.HashMap;
22  import java.util.HashSet;
23  import java.util.Iterator;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.Set;
27  
28  import javax.servlet.http.HttpSession;
29  
30  import org.acegisecurity.ui.session.HttpSessionDestroyedEvent;
31  
32  import org.springframework.context.ApplicationEvent;
33  import org.springframework.context.ApplicationListener;
34  import org.springframework.util.Assert;
35  
36  
37  /***
38   * Base implementation of {@link
39   * org.acegisecurity.concurrent.SessionRegistry} which also listens for
40   * {@link org.acegisecurity.ui.session.HttpSessionDestroyedEvent}s
41   * published in the Spring application context.
42   * 
43   * <p>
44   * NB: It is important that you register the {@link
45   * org.acegisecurity.ui.session.HttpSessionEventPublisher} in
46   * <code>web.xml</code> so that this class is notified of sessions that
47   * expire.
48   * </p>
49   *
50   * @author Ben Alex
51   * @version $Id: SessionRegistryImpl.java,v 1.2 2005/11/17 00:55:56 benalex Exp ${date}
52   */
53  public class SessionRegistryImpl implements SessionRegistry,
54      ApplicationListener {
55      //~ Instance fields ========================================================
56  
57      private Map principals = Collections.synchronizedMap(new HashMap()); // <principal:Object,SessionIdSet>
58      private Map sessionIds = Collections.synchronizedMap(new HashMap()); // <sessionId:Object,SessionInformation>
59  
60      //~ Methods ================================================================
61  
62      public SessionInformation[] getAllSessions(Object principal) {
63          Set sessionsUsedByPrincipal = (Set) principals.get(principal);
64  
65          if (sessionsUsedByPrincipal == null) {
66              return null;
67          }
68          
69          List list = new ArrayList();
70          Iterator iter = sessionsUsedByPrincipal.iterator();
71          while (iter.hasNext()) {
72          	String sessionId = (String) iter.next();
73          	list.add(getSessionInformation(sessionId));
74          }
75  
76          return (SessionInformation[]) list.toArray(new SessionInformation[] {});
77      }
78  
79      public SessionInformation getSessionInformation(String sessionId) {
80          Assert.hasText(sessionId, "SessionId required as per inerface contract");
81  
82          return (SessionInformation) sessionIds.get(sessionId);
83      }
84  
85      public void onApplicationEvent(ApplicationEvent event) {
86          if (event instanceof HttpSessionDestroyedEvent) {
87              String sessionId = ((HttpSession) event.getSource()).getId();
88              removeSessionInformation(sessionId);
89          }
90      }
91  
92      public void refreshLastRequest(String sessionId) {
93          Assert.hasText(sessionId, "SessionId required as per inerface contract");
94  
95          SessionInformation info = getSessionInformation(sessionId);
96  
97          if (info != null) {
98              info.refreshLastRequest();
99          }
100     }
101 
102     public void registerNewSession(String sessionId, Object principal)
103         throws SessionAlreadyUsedException {
104         Assert.hasText(sessionId, "SessionId required as per inerface contract");
105         Assert.notNull(principal, "Principal required as per inerface contract");
106 
107         if (getSessionInformation(sessionId) != null) {
108             throw new SessionAlreadyUsedException("Session " + sessionId
109                 + " is already is use");
110         }
111 
112         sessionIds.put(sessionId,
113             new SessionInformation(principal, sessionId, new Date()));
114 
115         Set sessionsUsedByPrincipal = (Set) principals.get(principal);
116 
117         if (sessionsUsedByPrincipal == null) {
118             sessionsUsedByPrincipal = Collections.synchronizedSet(new HashSet());
119         }
120 
121         sessionsUsedByPrincipal.add(sessionId);
122 
123         principals.put(principal, sessionsUsedByPrincipal);
124     }
125 
126     public void removeSessionInformation(String sessionId) {
127         Assert.hasText(sessionId, "SessionId required as per inerface contract");
128 
129         SessionInformation info = getSessionInformation(sessionId);
130 
131         if (info != null) {
132             sessionIds.remove(sessionId);
133 
134             Set sessionsUsedByPrincipal = (Set) principals.get(info
135                     .getPrincipal());
136 
137             if (sessionsUsedByPrincipal != null) {
138                 sessionsUsedByPrincipal.remove(sessionId);
139                 
140                 if (sessionsUsedByPrincipal.size() == 0) {
141                 	// No need to keep pbject in principals Map anymore 
142                 	principals.remove(info.getPrincipal());
143                 }
144             }
145         }
146     }
147 }