KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > opencms > main > CmsSessionManager


1 /*
2  * File : $Source: /usr/local/cvs/opencms/src/org/opencms/main/CmsSessionManager.java,v $
3  * Date : $Date: 2006/03/27 14:52:27 $
4  * Version: $Revision: 1.12 $
5  *
6  * This library is part of OpenCms -
7  * the Open Source Content Mananagement System
8  *
9  * Copyright (c) 2005 Alkacon Software GmbH (http://www.alkacon.com)
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * Lesser General Public License for more details.
20  *
21  * For further information about Alkacon Software GmbH, please see the
22  * company website: http://www.alkacon.com
23  *
24  * For further information about OpenCms, please see the
25  * project website: http://www.opencms.org
26  *
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30  */

31
32 package org.opencms.main;
33
34 import org.opencms.file.CmsObject;
35 import org.opencms.file.CmsUser;
36 import org.opencms.util.CmsStringUtil;
37 import org.opencms.util.CmsUUID;
38
39 import java.util.ArrayList JavaDoc;
40 import java.util.ConcurrentModificationException JavaDoc;
41 import java.util.HashSet JavaDoc;
42 import java.util.Hashtable JavaDoc;
43 import java.util.Iterator JavaDoc;
44 import java.util.List JavaDoc;
45 import java.util.Map JavaDoc;
46 import java.util.Set JavaDoc;
47
48 import javax.servlet.http.HttpSessionEvent JavaDoc;
49
50 import org.apache.commons.collections.Buffer;
51 import org.apache.commons.collections.BufferUtils;
52 import org.apache.commons.collections.buffer.BoundedFifoBuffer;
53 import org.apache.commons.logging.Log;
54
55 /**
56  * Keeps track of the sessions running on the OpenCms server and
57  * provides a session info storage which is used to get an overview
58  * about currently authenticated OpenCms users, as well as sending broadcasts between users.<p>
59  *
60  * For each authenticated OpenCms user, a {@link org.opencms.main.CmsSessionInfo} object
61  * holds the information about the users status.<p>
62  *
63  * When a user session is invalidated, the user info will be removed.
64  * This happens when a user log out, or when his session times out.<p>
65  *
66  * <b>Please Note:</b> The current implementation does not provide any permission checking,
67  * so all users can access the methods of this manager. Permission checking
68  * based on the current users OpenCms context may be added in a future OpenCms release.<p>
69  *
70  * @author Alexander Kandzior
71  *
72  * @version $Revision: 1.12 $
73  *
74  * @since 6.0.0
75  */

76 public class CmsSessionManager {
77
78     /** The log object for this class. */
79     private static final Log LOG = CmsLog.getLog(CmsSessionManager.class);
80
81     /** Counter for the currently active sessions. */
82     private int m_sessionCountCurrent;
83
84     /** Counter for all sessions created so far. */
85     private int m_sessionCountTotal;
86
87     /** Stores the session info objects mapped to the session id. */
88     private Map JavaDoc m_sessions;
89
90     /**
91      * Creates a new instance of the OpenCms session manager.<p>
92      */

93     protected CmsSessionManager() {
94
95         super();
96         // create a map for all sessions, these will be mapped using their session id
97
m_sessions = new Hashtable JavaDoc();
98     }
99
100     /**
101      * Returns the broadcast queue for the given session id.<p>
102      *
103      * @param sessionId the session id to get the broadcast queue for
104      *
105      * @return the broadcast queue for the given session id
106      */

107     public Buffer getBroadcastQueue(String JavaDoc sessionId) {
108
109         if (getSessionInfo(sessionId) == null) {
110             // return empty message buffer if the session is gone
111
return BufferUtils.synchronizedBuffer(new BoundedFifoBuffer(CmsSessionInfo.QUEUE_SIZE));
112         }
113         return getSessionInfo(sessionId).getBroadcastQueue();
114     }
115
116     /**
117      * Returns the number of sessions currently authenticated in the OpenCms security system.<p>
118      *
119      * @return the number of sessions currently authenticated in the OpenCms security system
120      */

121     public int getSessionCountAuthenticated() {
122
123         return m_sessions.size();
124     }
125
126     /**
127      * Returns the number of current sessions, including the sessions of not authenticated guest users.<p>
128      *
129      * @return the number of current sessions, including the sessions of not authenticated guest users
130      */

131     public int getSessionCountCurrent() {
132
133         return m_sessionCountCurrent;
134     }
135
136     /**
137      * Returns the number of total sessions generated so far, including already destroyed sessions.<p>
138      *
139      * @return the number of total sessions generated so far, including already destroyed sessions
140      */

141     public int getSessionCountTotal() {
142
143         return m_sessionCountTotal;
144     }
145
146     /**
147      * Returns the complete user session info of a user from the session storage,
148      * or <code>null</code> if this session id has no session info attached.<p>
149      *
150      * @param sessionId the session id to return the session info for
151      *
152      * @return the complete user session info of a user from the session storage
153      */

154     public CmsSessionInfo getSessionInfo(String JavaDoc sessionId) {
155
156         return (CmsSessionInfo)m_sessions.get(sessionId);
157     }
158
159     /**
160      * Returns all current session info objects.<p>
161      *
162      * @return all current session info objects
163      */

164     public List JavaDoc getSessionInfos() {
165
166         List JavaDoc result = new ArrayList JavaDoc();
167         synchronized (m_sessions) {
168             Iterator JavaDoc i = getConcurrentSessionIterator();
169             while (i.hasNext()) {
170                 CmsSessionInfo sessionInfo = (CmsSessionInfo)m_sessions.get(i.next());
171                 if (sessionInfo != null) {
172                     // may be the case in case of concurrent modification
173
result.add(sessionInfo);
174                 }
175             }
176         }
177         return result;
178     }
179
180     /**
181      * Returns a list of all active session info objects for the specified user.<p>
182      *
183      * An OpenCms user can have many active sessions.
184      * This is e.g. possible when two people have logged in to the system using the
185      * same username. Even one person can have multiple sessions if he
186      * is logged in to OpenCms with several browser windows at the same time.<p>
187      *
188      * @param userId the id of the user
189      *
190      * @return a list of all active session info objects for the specified user
191      */

192     public List JavaDoc getSessionInfos(CmsUUID userId) {
193
194         List JavaDoc userSessions = new ArrayList JavaDoc();
195         synchronized (m_sessions) {
196             Iterator JavaDoc i = getConcurrentSessionIterator();
197             while (i.hasNext()) {
198                 String JavaDoc key = (String JavaDoc)i.next();
199                 CmsSessionInfo sessionInfo = (CmsSessionInfo)m_sessions.get(key);
200                 if (userId.equals(sessionInfo.getUser().getId())) {
201                     userSessions.add(sessionInfo);
202                 }
203             }
204         }
205         return userSessions;
206     }
207
208     /**
209      * Sends a broadcast to all sessions of all currently authenticated users.<p>
210      *
211      * @param cms the OpenCms user context of the user sending the broadcast
212      *
213      * @param message the message to broadcast
214      */

215     public void sendBroadcast(CmsObject cms, String JavaDoc message) {
216
217         if (CmsStringUtil.isEmptyOrWhitespaceOnly(message)) {
218             // don't broadcast empty messages
219
return;
220         }
221         // create the broadcast
222
CmsBroadcast broadcast = new CmsBroadcast(cms.getRequestContext().currentUser(), message);
223         // send the broadcast to all authenticated sessions
224
synchronized (m_sessions) {
225             Iterator JavaDoc i = getConcurrentSessionIterator();
226             while (i.hasNext()) {
227                 CmsSessionInfo sessionInfo = (CmsSessionInfo)m_sessions.get(i.next());
228                 if (sessionInfo != null) {
229                     // double check for concurrent modification
230
sessionInfo.getBroadcastQueue().add(broadcast);
231                 }
232             }
233         }
234     }
235
236     /**
237      * Sends a broadcast to all sessions of a given user.<p>
238      *
239      * @param cms the OpenCms user context of the user sending the broadcast
240      *
241      * @param message the message to broadcast
242      * @param user the target (reciever) of the broadcast
243      */

244     public void sendBroadcast(CmsObject cms, String JavaDoc message, CmsUser user) {
245
246         if (CmsStringUtil.isEmptyOrWhitespaceOnly(message)) {
247             // don't broadcast empty messages
248
return;
249         }
250         // create the broadcast
251
CmsBroadcast broadcast = new CmsBroadcast(cms.getRequestContext().currentUser(), message);
252         List JavaDoc userSessions = getSessionInfos(user.getId());
253         Iterator JavaDoc i = userSessions.iterator();
254         // send the broadcast to all sessions of the selected user
255
synchronized (m_sessions) {
256             while (i.hasNext()) {
257                 CmsSessionInfo sessionInfo = (CmsSessionInfo)m_sessions.get(i.next());
258                 if (sessionInfo != null) {
259                     // double check for concurrent modification
260
sessionInfo.getBroadcastQueue().add(broadcast);
261                 }
262             }
263         }
264     }
265
266     /**
267      * Sends a broadcast to the specified user session.<p>
268      *
269      * @param cms the OpenCms user context of the user sending the broadcast
270      *
271      * @param message the message to broadcast
272      * @param sessionId the session id target (reciever) of the broadcast
273      */

274     public void sendBroadcast(CmsObject cms, String JavaDoc message, String JavaDoc sessionId) {
275
276         if (CmsStringUtil.isEmptyOrWhitespaceOnly(message)) {
277             // don't broadcast empty messages
278
return;
279         }
280         // send the broadcast only to the selected session
281
CmsSessionInfo sessionInfo = (CmsSessionInfo)m_sessions.get(sessionId);
282         if (sessionInfo != null) {
283             // double check for concurrent modification
284
sessionInfo.getBroadcastQueue().add(new CmsBroadcast(cms.getRequestContext().currentUser(), message));
285         }
286     }
287
288     /**
289      * @see java.lang.Object#toString()
290      */

291     public String JavaDoc toString() {
292
293         StringBuffer JavaDoc output = new StringBuffer JavaDoc();
294         synchronized (m_sessions) {
295             Iterator JavaDoc i = getConcurrentSessionIterator();
296             output.append("[CmsSessions]:\n");
297             while (i.hasNext()) {
298                 String JavaDoc key = (String JavaDoc)i.next();
299                 CmsSessionInfo sessionInfo = (CmsSessionInfo)m_sessions.get(key);
300                 output.append(key);
301                 output.append(" : ");
302                 output.append(sessionInfo.getUser().toString());
303                 output.append('\n');
304             }
305         }
306         return output.toString();
307     }
308
309     /**
310      * Adds a new session info into the session storage.<p>
311      *
312      * @param sessionInfo the session info to store for the id
313      */

314     protected void addSessionInfo(CmsSessionInfo sessionInfo) {
315
316         m_sessions.put(sessionInfo.getSessionId(), sessionInfo);
317     }
318
319     /**
320      * Called by the {@link OpenCmsListener} when a http session is created.<p>
321      *
322      * @param event the http session event
323      *
324      * @see javax.servlet.http.HttpSessionListener#sessionCreated(javax.servlet.http.HttpSessionEvent)
325      * @see OpenCmsListener#sessionCreated(HttpSessionEvent)
326      */

327     protected synchronized void sessionCreated(HttpSessionEvent JavaDoc event) {
328
329         m_sessionCountCurrent = (m_sessionCountCurrent <= 0) ? 1 : (m_sessionCountCurrent + 1);
330         m_sessionCountTotal++;
331         if (LOG.isInfoEnabled()) {
332             LOG.info(Messages.get().getBundle().key(
333                 Messages.LOG_SESSION_CREATED_2,
334                 new Integer JavaDoc(m_sessionCountTotal),
335                 new Integer JavaDoc(m_sessionCountCurrent)));
336         }
337         if (LOG.isDebugEnabled()) {
338             LOG.debug(Messages.get().getBundle().key(Messages.LOG_SESSION_CREATED_1, event.getSession().getId()));
339         }
340     }
341
342     /**
343      * Called by the {@link OpenCmsListener} when a http session is destroyed.<p>
344      *
345      * @param event the http session event
346      *
347      * @see javax.servlet.http.HttpSessionListener#sessionDestroyed(javax.servlet.http.HttpSessionEvent)
348      * @see OpenCmsListener#sessionDestroyed(HttpSessionEvent)
349      */

350     protected synchronized void sessionDestroyed(HttpSessionEvent JavaDoc event) {
351
352         m_sessionCountCurrent = (m_sessionCountCurrent <= 0) ? 0 : (m_sessionCountCurrent - 1);
353
354         String JavaDoc sessionId = event.getSession().getId();
355         // remove the session for the session info storage
356
CmsSessionInfo sessionInfo = (CmsSessionInfo)m_sessions.get(sessionId);
357         CmsUUID userId = CmsUUID.getNullUUID();
358         if (sessionInfo != null) {
359             userId = sessionInfo.getUser().getId();
360         }
361         synchronized (m_sessions) {
362             m_sessions.remove(sessionId);
363         }
364         if (!userId.isNullUUID() && getSessionInfos(userId).size() == 0) {
365             // remove the temporary locks of this user from memory
366
OpenCms.getLockManager().removeTempLocks(userId);
367         }
368
369         if (LOG.isInfoEnabled()) {
370             LOG.info(Messages.get().getBundle().key(
371                 Messages.LOG_SESSION_DESTROYED_2,
372                 new Integer JavaDoc(m_sessionCountTotal),
373                 new Integer JavaDoc(m_sessionCountCurrent)));
374         }
375         if (LOG.isDebugEnabled()) {
376             LOG.debug(Messages.get().getBundle().key(Messages.LOG_SESSION_DESTROYED_1, event.getSession().getId()));
377         }
378     }
379
380     /**
381      * Validates the sessions stored in this manager and removes
382      * any sessions that have become invalidated.<p>
383      */

384     protected void validateSessionInfos() {
385
386         synchronized (m_sessions) {
387             Iterator JavaDoc i = getConcurrentSessionIterator();
388             while (i.hasNext()) {
389                 String JavaDoc sessionId = (String JavaDoc)i.next();
390                 CmsSessionInfo sessionInfo = (CmsSessionInfo)m_sessions.get(sessionId);
391                 if (sessionInfo != null) {
392                     // may be the case in case of concurrent modification
393
if (sessionInfo.isExpired()) {
394                         // session is invalid, try to remove it
395
try {
396                             m_sessions.remove(sessionId);
397                         } catch (ConcurrentModificationException JavaDoc ex) {
398                             // ignore, better luck next time...
399
}
400                     }
401                 }
402             }
403         }
404     }
405
406     /**
407      * Returns an iterator of a copy of the keyset of the current session map,
408      * which should be used for iterators to avoid concurrent modification exceptions.<p>
409      *
410      * @return an iterator of the keyset of the current session map
411      */

412     private Iterator JavaDoc getConcurrentSessionIterator() {
413
414         Set JavaDoc keySet;
415         int count = 0;
416         do {
417             keySet = new HashSet JavaDoc(m_sessions.size());
418             try {
419                 keySet.addAll(m_sessions.keySet());
420             } catch (ConcurrentModificationException JavaDoc e) {
421                 // problem creating a copy of the keyset, try up to 5 times
422
count++;
423                 keySet = null;
424             }
425         } while ((keySet == null) && (count < 5));
426         if (keySet == null) {
427             // no success, so we return an empty set to avoid problems
428
keySet = new HashSet JavaDoc();
429         }
430         return keySet.iterator();
431     }
432 }
Popular Tags