KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > nl > justobjects > pushlet > core > SessionManager


1 // Copyright (c) 2000 Just Objects B.V. <just@justobjects.nl>
2
// Distributable under LGPL license. See terms of license at gnu.org.
3

4 package nl.justobjects.pushlet.core;
5
6 import nl.justobjects.pushlet.util.Log;
7 import nl.justobjects.pushlet.util.Rand;
8 import nl.justobjects.pushlet.util.Sys;
9
10 import java.util.*;
11
12 /**
13  * Routes Events to Sessions.
14  *
15  * @version $Id: SessionManager.java,v 1.5 2005/02/28 15:58:05 justb Exp $
16  * @author Just van den Broecke - Just Objects &copy;
17  **/

18 public class SessionManager implements ConfigDefs {
19
20     /** Singleton pattern: single instance. */
21     private static SessionManager instance;
22
23     static {
24         // Singleton + factory pattern: create single instance
25
// from configured class name
26
String JavaDoc className = Config.getProperty(SESSION_MANAGER_CLASS);
27
28         try {
29             instance = (SessionManager) Class.forName(className).newInstance();
30             Log.info("SessionManager created className=" + className);
31         } catch (Throwable JavaDoc t) {
32             Log.fatal("Cannot instantiate SessionManager className=" + className, t);
33         }
34     }
35
36     /** Timer to schedule session leasing TimerTasks. */
37     private Timer timer;
38     private final long TIMER_INTERVAL_MILLIS = 60000;
39
40     /** Map of active sessions, keyed by their id. */
41     private Map sessions = Collections.synchronizedMap(new HashMap(13));
42
43     /** Shadow cache of active Sessions. */
44     private Session[] sessionCache = new Session[0];
45
46     /** Flag indicating subscriptions have changed. */
47     private volatile boolean sessionCacheDirty = false;
48
49     /** Singleton pattern: private constructor. */
50     private SessionManager() {
51     }
52
53     /** Create new Session (but add later). */
54     public Session createSession(Event anEvent) {
55         // Trivial
56
return new Session(createSessionId());
57     }
58
59     /** Create unique Session id. */
60     public String JavaDoc createSessionId() {
61         // Create a unique session id
62
// In 99.9999 % of the cases this should be generated at once
63
String JavaDoc id = null;
64         while (true) {
65             id = Rand.randomName(Config.getIntProperty(SESSION_ID_SIZE));
66             if (!hasSession(id)) {
67                 // Created unique session id
68
break;
69             }
70         }
71         return id;
72     }
73
74     /** Singleton pattern: get single instance. */
75     public static SessionManager getInstance() {
76         return instance;
77     }
78
79     /** Get number of listening Sessions. */
80     public Session getSession(String JavaDoc anId) {
81         return (Session) sessions.get(anId);
82     }
83
84     /** Get copy of listening Sessions. */
85     public Session[] getSessions() {
86         return (Session[]) sessions.values().toArray(new Session[0]);
87     }
88
89     /** Get number of listening Sessions. */
90     public int getSessionCount() {
91         return sessions.size();
92     }
93
94     /** Get status info. */
95     public String JavaDoc getStatus() {
96         Session[] sessions = getSessions();
97         String JavaDoc statusInfo = "SessionMgr: " + sessions.length + " sessions \\n";
98         for (int i = 0; i < sessions.length; i++) {
99             statusInfo = statusInfo + sessions[i] + "\\n";
100         }
101         return statusInfo;
102     }
103
104     /** Is Session present?. */
105     public boolean hasSession(String JavaDoc anId) {
106         return sessions.containsKey(anId);
107     }
108
109     /** Add session. */
110     public void addSession(Session session) {
111         // log(session.getId() + " at " + session.getAddress() + " adding ");
112
sessions.put(session.getId(), session);
113         sessionCacheDirty = true;
114         info(session.getId() + " at " + session.getAddress() + " added ");
115     }
116
117     /** Register session for removal. */
118     public Session removeSession(Session aSession) {
119         Session session = (Session) sessions.remove(aSession.getId());
120         if (session != null) {
121             sessionCacheDirty = true;
122             info(session.getId() + " at " + session.getAddress() + " removed ");
123         }
124         return session;
125     }
126
127     public Session[] getSnapshot() {
128         // If no session change return immediately.
129
if (!sessionCacheDirty) {
130             return sessionCache;
131         }
132
133         // Session cache is dirty: recreate
134
synchronized (sessionCache) {
135             // ASSERT: cache is dirty, need to update cache
136
// Copy all sessions into cache
137
// toArray() expands cache size if required
138
sessionCache = (Session[]) sessions.values().toArray(sessionCache);
139
140             // Mark session cache actualized
141
sessionCacheDirty = false;
142
143             return sessionCache;
144         }
145     }
146
147
148     /** Util: stdout printing. */
149     public void start() {
150         if (timer != null) {
151             stop();
152         }
153         timer = new Timer(false);
154         timer.schedule(new AgingTimerTask(), TIMER_INTERVAL_MILLIS, TIMER_INTERVAL_MILLIS);
155         info("started; interval=" + TIMER_INTERVAL_MILLIS + "ms");
156     }
157
158     /** Util: stdout printing. */
159     public void stop() {
160         if (timer != null) {
161             timer.cancel();
162             timer = null;
163         }
164         sessions.clear();
165         sessionCache = new Session[0];
166         info("stopped");
167     }
168
169     /** Util: stdout printing. */
170     private void info(String JavaDoc s) {
171         Log.info("SessionManager: " + new Date() + " " + s);
172     }
173
174     /** Util: stdout printing. */
175     private void warn(String JavaDoc s) {
176         Log.warn("SessionManager: " + s);
177     }
178
179     /** Util: stdout printing. */
180     private void debug(String JavaDoc s) {
181         Log.debug("SessionManager: " + s);
182     }
183
184     /** Manages session timeouts. */
185     private class AgingTimerTask extends TimerTask {
186         private long lastRun = Sys.now();
187
188         public void run() {
189             long now = Sys.now();
190             long delta = now - lastRun;
191             lastRun = now;
192             // info("tick " + delta);
193

194             Session[] sessions = getSnapshot();
195             Session nextSession = null;
196             for (int i = 0; i < sessions.length; i++) {
197                 nextSession = sessions[i];
198                 // There may be holes in the cache arrray
199
if (nextSession == null) {
200                     break;
201                 }
202
203                 try {
204                     // Age the lease
205
nextSession.age(delta);
206
207                     // Stop session if lease expired
208
if (nextSession.isExpired()) {
209                         info("Session expired: " + nextSession);
210                         nextSession.stop();
211                     }
212                 } catch (Throwable JavaDoc t) {
213                     warn("Error in timer task : " + t);
214                 }
215             }
216         }
217     }
218 }
219
220 /*
221  * $Log: SessionManager.java,v $
222  * Revision 1.5 2005/02/28 15:58:05 justb
223  * added SimpleListener example
224  *
225  * Revision 1.4 2005/02/28 12:45:59 justb
226  * introduced Command class
227  *
228  * Revision 1.3 2005/02/28 09:14:55 justb
229  * sessmgr/dispatcher factory/singleton support
230  *
231  * Revision 1.2 2005/02/25 15:13:01 justb
232  * session id generation more robust
233  *
234  * Revision 1.1 2005/02/21 16:59:09 justb
235  * SessionManager and session lease introduced
236  *
237
238  *
239  */

240
Popular Tags