001: /* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
002: *
003: * Licensed under the Apache License, Version 2.0 (the "License");
004: * you may not use this file except in compliance with the License.
005: * You may obtain a copy of the License at
006: *
007: * http://www.apache.org/licenses/LICENSE-2.0
008: *
009: * Unless required by applicable law or agreed to in writing, software
010: * distributed under the License is distributed on an "AS IS" BASIS,
011: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: * See the License for the specific language governing permissions and
013: * limitations under the License.
014: */
015:
016: package org.acegisecurity.concurrent;
017:
018: import org.acegisecurity.ui.session.HttpSessionDestroyedEvent;
019:
020: import org.springframework.context.ApplicationEvent;
021: import org.springframework.context.ApplicationListener;
022:
023: import org.springframework.util.Assert;
024: import org.apache.commons.logging.Log;
025: import org.apache.commons.logging.LogFactory;
026:
027: import java.util.ArrayList;
028: import java.util.Collections;
029: import java.util.Date;
030: import java.util.HashMap;
031: import java.util.HashSet;
032: import java.util.Iterator;
033: import java.util.List;
034: import java.util.Map;
035: import java.util.Set;
036:
037: import javax.servlet.http.HttpSession;
038:
039: /**
040: * Base implementation of {@link org.acegisecurity.concurrent.SessionRegistry}
041: * which also listens for {@link org.acegisecurity.ui.session.HttpSessionDestroyedEvent}s
042: * published in the Spring application context.
043: *
044: * <p>
045: * NB: It is important that you register the {@link org.acegisecurity.ui.session.HttpSessionEventPublisher} in
046: * <code>web.xml</code> so that this class is notified of sessions that expire.
047: * </p>
048: *
049: * @author Ben Alex
050: * @version $Id: SessionRegistryImpl.java 1991 2007-08-30 19:04:18Z luke_t $
051: */
052: public class SessionRegistryImpl implements SessionRegistry,
053: ApplicationListener {
054: //~ Static fields/initializers =====================================================================================
055:
056: protected static final Log logger = LogFactory
057: .getLog(SessionRegistryImpl.class);
058:
059: // ~ Instance fields ===============================================================================================
060:
061: private Map principals = Collections.synchronizedMap(new HashMap()); // <principal:Object,SessionIdSet>
062: private Map sessionIds = Collections.synchronizedMap(new HashMap()); // <sessionId:Object,SessionInformation>
063:
064: // ~ Methods =======================================================================================================
065:
066: public Object[] getAllPrincipals() {
067: return principals.keySet().toArray();
068: }
069:
070: public SessionInformation[] getAllSessions(Object principal,
071: boolean includeExpiredSessions) {
072: Set sessionsUsedByPrincipal = (Set) principals.get(principal);
073:
074: if (sessionsUsedByPrincipal == null) {
075: return null;
076: }
077:
078: List list = new ArrayList();
079:
080: synchronized (sessionsUsedByPrincipal) {
081: for (Iterator iter = sessionsUsedByPrincipal.iterator(); iter
082: .hasNext();) {
083: String sessionId = (String) iter.next();
084: SessionInformation sessionInformation = getSessionInformation(sessionId);
085:
086: if (sessionInformation == null) {
087: continue;
088: }
089:
090: if (includeExpiredSessions
091: || !sessionInformation.isExpired()) {
092: list.add(sessionInformation);
093: }
094: }
095: }
096:
097: return (SessionInformation[]) list
098: .toArray(new SessionInformation[] {});
099: }
100:
101: public SessionInformation getSessionInformation(String sessionId) {
102: Assert.hasText(sessionId,
103: "SessionId required as per interface contract");
104:
105: return (SessionInformation) sessionIds.get(sessionId);
106: }
107:
108: public void onApplicationEvent(ApplicationEvent event) {
109: if (event instanceof HttpSessionDestroyedEvent) {
110: String sessionId = ((HttpSession) event.getSource())
111: .getId();
112: removeSessionInformation(sessionId);
113: }
114: }
115:
116: public void refreshLastRequest(String sessionId) {
117: Assert.hasText(sessionId,
118: "SessionId required as per interface contract");
119:
120: SessionInformation info = getSessionInformation(sessionId);
121:
122: if (info != null) {
123: info.refreshLastRequest();
124: }
125: }
126:
127: public synchronized void registerNewSession(String sessionId,
128: Object principal) {
129: Assert.hasText(sessionId,
130: "SessionId required as per interface contract");
131: Assert.notNull(principal,
132: "Principal required as per interface contract");
133:
134: if (logger.isDebugEnabled()) {
135: logger.debug("Registering session " + sessionId
136: + ", for principal " + principal);
137: }
138:
139: if (getSessionInformation(sessionId) != null) {
140: removeSessionInformation(sessionId);
141: }
142:
143: sessionIds.put(sessionId, new SessionInformation(principal,
144: sessionId, new Date()));
145:
146: Set sessionsUsedByPrincipal = (Set) principals.get(principal);
147:
148: if (sessionsUsedByPrincipal == null) {
149: sessionsUsedByPrincipal = Collections
150: .synchronizedSet(new HashSet());
151: }
152:
153: sessionsUsedByPrincipal.add(sessionId);
154:
155: principals.put(principal, sessionsUsedByPrincipal);
156: }
157:
158: public void removeSessionInformation(String sessionId) {
159: Assert.hasText(sessionId,
160: "SessionId required as per interface contract");
161:
162: SessionInformation info = getSessionInformation(sessionId);
163:
164: if (info != null) {
165: if (logger.isDebugEnabled()) {
166: logger.debug("Removing session " + sessionId
167: + " from set of registered sessions");
168: }
169: sessionIds.remove(sessionId);
170:
171: Set sessionsUsedByPrincipal = (Set) principals.get(info
172: .getPrincipal());
173:
174: if (sessionsUsedByPrincipal != null) {
175: synchronized (sessionsUsedByPrincipal) {
176: if (logger.isDebugEnabled()) {
177: logger
178: .debug("Removing session "
179: + sessionId
180: + " from principal's set of registered sessions");
181: }
182:
183: sessionsUsedByPrincipal.remove(sessionId);
184:
185: if (sessionsUsedByPrincipal.size() == 0) {
186: // No need to keep object in principals Map anymore
187: if (logger.isDebugEnabled()) {
188: logger.debug("Removing principal "
189: + info.getPrincipal()
190: + " from registry");
191: }
192: principals.remove(info.getPrincipal());
193: }
194: }
195: }
196: }
197: }
198: }
|