001: /*
002: * CoadunationLib: The coaduntion implementation library.
003: * Copyright (C) 2006 Rift IT Contracting
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
018: *
019: * UserSessionManager.java
020: *
021: * The user session manager is responsible for creating new session for users.
022: */
023:
024: // the package
025: package com.rift.coad.lib.security.user;
026:
027: // java
028: import java.util.Iterator;
029: import java.util.Map;
030: import java.util.HashMap;
031:
032: // logging import
033: import org.apache.log4j.Logger;
034:
035: // coadunation
036: import com.rift.coad.lib.configuration.Configuration;
037: import com.rift.coad.lib.configuration.ConfigurationFactory;
038: import com.rift.coad.lib.security.ThreadsPermissionContainer;
039: import com.rift.coad.lib.security.ThreadPermissionSession;
040: import com.rift.coad.lib.security.UserSession;
041: import com.rift.coad.lib.thread.ThreadStateMonitor;
042:
043: /**
044: * The user session manager is responsible for creating new session for users.
045: *
046: * @author Brett Chaldecott
047: */
048: public class UserSessionManager {
049:
050: /**
051: * This object is responsible for maintaining the user session
052: */
053: public class UserSessionIndex {
054: // Private member variables
055: private Map sessionIdMap = new HashMap();
056:
057: /**
058: * The default constructor of the user session index
059: */
060: public UserSessionIndex() {
061:
062: }
063:
064: /**
065: * This method will add add a user session to the indexs appropriatly.
066: *
067: * @param userSession The reference to the user session object.
068: */
069: public synchronized void putUser(UserSession userSession) {
070: sessionIdMap.put(userSession.getSessionId(), userSession);
071: }
072:
073: /**
074: * This method returns the user session object instance.
075: *
076: * @return The reference to the user session object.
077: * @param sessionId The id of the users session
078: * @exception UserException
079: */
080: public synchronized UserSession getSessionById(String sessionId)
081: throws UserException {
082: try {
083: if (!sessionIdMap.containsKey(sessionId)) {
084: throw new UserException(
085: "No session exists for session id.");
086: }
087: UserSession userSession = (UserSession) sessionIdMap
088: .get(sessionId);
089: if (userSession.isExpired()) {
090: sessionIdMap.remove(userSession.getSessionId());
091: throw new UserException(
092: "No session exists for user.");
093: }
094: userSession.touch();
095: return userSession;
096: } catch (SecurityException ex) {
097: throw ex;
098: } catch (Exception ex) {
099: throw new UserException(
100: "Failed to retrieve the user session : "
101: + ex.getMessage(), ex);
102: }
103: }
104:
105: /**
106: * This method removes a session identifed by a session id
107: *
108: * @param sessionId The id of the users session
109: */
110: public synchronized void removeSessionById(String sessionId) {
111: if (!sessionIdMap.containsKey(sessionId)) {
112: return;
113: }
114: UserSession userSession = (UserSession) sessionIdMap
115: .get(sessionId);
116: sessionIdMap.remove(userSession.getSessionId());
117: }
118: }
119:
120: /**
121: * This is a thread that is responsible for cleaning up the old user
122: * sessions. It does not inhert from BasicThread because the environment
123: * has not been configured properly yet for a basic thread to be started.
124: */
125: public class TimeoutThread extends Thread {
126: // the classes constants
127: private final static String DELAY = "session_timeout_delay";
128: private final static long DELAY_DEFAULT = 60 * 1000;
129:
130: // private member variables
131: private ThreadStateMonitor stateMonitor = null;
132:
133: /**
134: * The constructor of the timeout thread.
135: *
136: * @exception UserException
137: */
138: public TimeoutThread() throws UserException {
139: try {
140: Configuration config = ConfigurationFactory
141: .getInstance().getConfig(this .getClass());
142: long delay = config.getLong(DELAY, DELAY_DEFAULT);
143: stateMonitor = new ThreadStateMonitor(delay);
144: } catch (Exception ex) {
145: log.error("Failed to init the timeout thread : "
146: + ex.getMessage(), ex);
147: throw new UserException(
148: "Failed to init the timeout thread : "
149: + ex.getMessage(), ex);
150: }
151: }
152:
153: /**
154: * This method runs through and removes sessions that have expired.
155: */
156: public void run() {
157: while (!stateMonitor.isTerminated()) {
158: stateMonitor.monitor();
159: Map sessionMapCopy = new HashMap();
160: synchronized (userSessionIndex) {
161: sessionMapCopy
162: .putAll(userSessionIndex.sessionIdMap);
163: }
164: for (Iterator iter = sessionMapCopy.keySet().iterator(); iter
165: .hasNext()
166: && !stateMonitor.isTerminated();) {
167: UserSession userSession = (UserSession) sessionMapCopy
168: .get(iter.next());
169: // we check the expiry date twice to deal with race
170: // conditions that exist with aquiring the lock on the
171: // user session index.
172: if (userSession.isExpired()) {
173: synchronized (userSessionIndex) {
174: if (userSession.isExpired()) {
175: userSessionIndex.sessionIdMap
176: .remove(userSession
177: .getSessionId());
178: }
179: }
180: }
181: }
182: }
183: }
184:
185: /**
186: * This method terminates the timeout thread.
187: */
188: public void terminte() {
189: stateMonitor.terminate(true);
190: }
191: }
192:
193: // the user session logger
194: private Logger log = Logger.getLogger(UserSessionManager.class
195: .getName());
196:
197: // the classes member variables
198: private UserSessionIndex userSessionIndex = new UserSessionIndex();
199: private TimeoutThread timeoutThread = null;
200: private ThreadsPermissionContainer permissions = null;
201: private UserStoreManager userStoreManager = null;
202:
203: /**
204: * Creates a new instance of UserSessionManager
205: *
206: * @param permissions The permissions for the threads.
207: * @param userStoreManager The reference to the user store manager.
208: */
209: public UserSessionManager(ThreadsPermissionContainer permissions,
210: UserStoreManager userStoreManager) {
211: this .permissions = permissions;
212: this .userStoreManager = userStoreManager;
213: }
214:
215: /**
216: * This method will create a new session for the calling thread using the
217: * supplied username.
218: *
219: * @param username The name of the user that the session must be created for.
220: * @exception UserException
221: */
222: public void initSessionForUser(String username)
223: throws UserException {
224: try {
225: UserSession user = userStoreManager.getUserInfo(username);
226: Long threadId = new Long(Thread.currentThread().getId());
227: permissions.putSession(threadId,
228: new ThreadPermissionSession(threadId, user));
229: userSessionIndex.putUser(user);
230: } catch (Exception ex) {
231: throw new UserException("Failed to init the session for ["
232: + username + "] : " + ex.getMessage(), ex);
233: }
234: }
235:
236: /**
237: * This method will create a new session for the calling thread using the
238: * supplied username.
239: *
240: * @param user The user
241: * @exception UserException
242: */
243: public void initSessionForUser(UserSession user)
244: throws UserException {
245: try {
246: Long threadId = new Long(Thread.currentThread().getId());
247: permissions.putSession(threadId,
248: new ThreadPermissionSession(threadId, user));
249: userSessionIndex.putUser(user);
250: } catch (Exception ex) {
251: throw new UserException("Failed to init the session for ["
252: + user.getName() + "] : " + ex.getMessage(), ex);
253: }
254: }
255:
256: /**
257: * This method adds a session for a user to the user session index so that
258: * it can be refered to later. It does not over ride the session on the
259: * thread as this will be done when the thread Sudo's to that user.
260: *
261: * @param user The user
262: * @exception UserException
263: */
264: public void addUserSession(UserSession user) throws UserException {
265: try {
266: userSessionIndex.putUser(user);
267: } catch (Exception ex) {
268: throw new UserException("Failed to init the session for ["
269: + user.getName() + "] : " + ex.getMessage(), ex);
270: }
271: }
272:
273: /**
274: * This method returns the user session id.
275: *
276: * @return The reference to the user session object.
277: * @param sessionId The references to the user session id.
278: * @exception UserException
279: */
280: public UserSession getSessionById(String sessionId)
281: throws UserException {
282: return userSessionIndex.getSessionById(sessionId);
283: }
284:
285: /**
286: * This method starts the clean up thread
287: *
288: * @exception UserException
289: */
290: public void startCleanup() throws UserException {
291: timeoutThread = new TimeoutThread();
292: timeoutThread.start();
293: }
294:
295: /**
296: * This method is responsible for terminating the user session store
297: */
298: public void shutdown() {
299: try {
300: timeoutThread.terminte();
301: timeoutThread.join();
302: } catch (Exception ex) {
303: log.error(
304: "Failed to wait for the time out thread to terminate "
305: + "because : " + ex.getMessage(), ex);
306: }
307: }
308: }
|