1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.nosql.mongodb;
20
21
22 import java.net.UnknownHostException;
23 import java.util.HashSet;
24 import java.util.Random;
25 import java.util.Set;
26 import java.util.Timer;
27 import java.util.TimerTask;
28
29 import javax.servlet.http.HttpServletRequest;
30 import javax.servlet.http.HttpSession;
31
32 import org.eclipse.jetty.server.Handler;
33 import org.eclipse.jetty.server.Server;
34 import org.eclipse.jetty.server.SessionManager;
35 import org.eclipse.jetty.server.handler.ContextHandler;
36 import org.eclipse.jetty.server.session.AbstractSessionIdManager;
37 import org.eclipse.jetty.server.session.SessionHandler;
38 import org.eclipse.jetty.util.log.Log;
39 import org.eclipse.jetty.util.log.Logger;
40
41 import com.mongodb.BasicDBObject;
42 import com.mongodb.BasicDBObjectBuilder;
43 import com.mongodb.DBCollection;
44 import com.mongodb.DBCursor;
45 import com.mongodb.DBObject;
46 import com.mongodb.Mongo;
47 import com.mongodb.MongoException;
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64 public class MongoSessionIdManager extends AbstractSessionIdManager
65 {
66 private final static Logger __log = Log.getLogger("org.eclipse.jetty.server.session");
67
68 final static DBObject __version_1 = new BasicDBObject(MongoSessionManager.__VERSION,1);
69 final static DBObject __valid_false = new BasicDBObject(MongoSessionManager.__VALID,false);
70 final static DBObject __valid_true = new BasicDBObject(MongoSessionManager.__VALID,true);
71
72
73 final DBCollection _sessions;
74 protected Server _server;
75 private Timer _scavengeTimer;
76 private Timer _purgeTimer;
77 private TimerTask _scavengerTask;
78 private TimerTask _purgeTask;
79
80
81
82 private long _scavengeDelay = 30 * 60 * 1000;
83 private long _scavengePeriod = 10 * 6 * 1000;
84
85
86
87
88
89 private boolean _purge = true;
90
91
92
93
94 private long _purgeDelay = 24 * 60 * 60 * 1000;
95
96
97
98
99
100 private long _purgeInvalidAge = 24 * 60 * 60 * 1000;
101
102
103
104
105
106 private long _purgeValidAge = 7 * 24 * 60 * 60 * 1000;
107
108
109
110
111
112
113
114 protected final Set<String> _sessionsIds = new HashSet<String>();
115
116
117
118 public MongoSessionIdManager(Server server) throws UnknownHostException, MongoException
119 {
120 this(server, new Mongo().getDB("HttpSessions").getCollection("sessions"));
121 }
122
123
124 public MongoSessionIdManager(Server server, DBCollection sessions)
125 {
126 super(new Random());
127
128 _server = server;
129 _sessions = sessions;
130
131 _sessions.ensureIndex(
132 BasicDBObjectBuilder.start().add("id",1).get(),
133 BasicDBObjectBuilder.start().add("unique",true).add("sparse",false).get());
134 _sessions.ensureIndex(
135 BasicDBObjectBuilder.start().add("id",1).add("version",1).get(),
136 BasicDBObjectBuilder.start().add("unique",true).add("sparse",false).get());
137
138 }
139
140
141
142
143
144
145
146 protected void scavenge()
147 {
148 __log.debug("SessionIdManager:scavenge:called with delay" + _scavengeDelay);
149
150 synchronized (_sessionsIds)
151 {
152
153
154
155
156
157
158
159 BasicDBObject query = new BasicDBObject();
160 query.put(MongoSessionManager.__ID,new BasicDBObject("$in", _sessionsIds ));
161 query.put(MongoSessionManager.__ACCESSED, new BasicDBObject("$lt",System.currentTimeMillis() - _scavengeDelay));
162
163 DBCursor checkSessions = _sessions.find(query, new BasicDBObject(MongoSessionManager.__ID, 1));
164
165 for ( DBObject session : checkSessions )
166 {
167 __log.debug("SessionIdManager:scavenge: invalidating " + (String)session.get(MongoSessionManager.__ID));
168 invalidateAll((String)session.get(MongoSessionManager.__ID));
169 }
170 }
171
172 }
173
174
175
176
177
178
179
180
181
182
183 protected void scavengeFully()
184 {
185 __log.debug("SessionIdManager:scavengeFully");
186
187 DBCursor checkSessions = _sessions.find();
188
189 for (DBObject session : checkSessions)
190 {
191 invalidateAll((String)session.get(MongoSessionManager.__ID));
192 }
193
194 }
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214 protected void purge()
215 {
216 BasicDBObject invalidQuery = new BasicDBObject();
217
218 invalidQuery.put(MongoSessionManager.__ACCESSED, new BasicDBObject("$lt",System.currentTimeMillis() - _purgeInvalidAge));
219 invalidQuery.put(MongoSessionManager.__VALID, false);
220
221 DBCursor oldSessions = _sessions.find(invalidQuery, new BasicDBObject(MongoSessionManager.__ID, 1));
222
223 for (DBObject session : oldSessions)
224 {
225 String id = (String)session.get("id");
226
227 __log.debug("MongoSessionIdManager:purging invalid " + id);
228
229 _sessions.remove(session);
230 }
231
232 if (_purgeValidAge != 0)
233 {
234 BasicDBObject validQuery = new BasicDBObject();
235
236 validQuery.put(MongoSessionManager.__ACCESSED,new BasicDBObject("$lt",System.currentTimeMillis() - _purgeValidAge));
237 validQuery.put(MongoSessionManager.__VALID, true);
238
239 oldSessions = _sessions.find(validQuery,new BasicDBObject(MongoSessionManager.__ID,1));
240
241 for (DBObject session : oldSessions)
242 {
243 String id = (String)session.get(MongoSessionManager.__ID);
244
245 __log.debug("MongoSessionIdManager:purging valid " + id);
246
247 _sessions.remove(session);
248 }
249 }
250
251 }
252
253
254
255
256
257
258
259 protected void purgeFully()
260 {
261 BasicDBObject invalidQuery = new BasicDBObject();
262
263 invalidQuery.put(MongoSessionManager.__VALID, false);
264
265 DBCursor oldSessions = _sessions.find(invalidQuery, new BasicDBObject(MongoSessionManager.__ID, 1));
266
267 for (DBObject session : oldSessions)
268 {
269 String id = (String)session.get(MongoSessionManager.__ID);
270
271 __log.debug("MongoSessionIdManager:purging invalid " + id);
272
273 _sessions.remove(session);
274 }
275
276 }
277
278
279
280 public DBCollection getSessions()
281 {
282 return _sessions;
283 }
284
285
286
287 public boolean isPurgeEnabled()
288 {
289 return _purge;
290 }
291
292
293 public void setPurge(boolean purge)
294 {
295 this._purge = purge;
296 }
297
298
299
300
301
302 public void setScavengeDelay(long scavengeDelay)
303 {
304 this._scavengeDelay = scavengeDelay;
305 }
306
307
308
309 public void setScavengePeriod(long scavengePeriod)
310 {
311 this._scavengePeriod = scavengePeriod;
312 }
313
314
315 public void setPurgeDelay(long purgeDelay)
316 {
317 if ( isRunning() )
318 {
319 throw new IllegalStateException();
320 }
321
322 this._purgeDelay = purgeDelay;
323 }
324
325
326 public long getPurgeInvalidAge()
327 {
328 return _purgeInvalidAge;
329 }
330
331
332
333
334
335
336 public void setPurgeInvalidAge(long purgeValidAge)
337 {
338 this._purgeInvalidAge = purgeValidAge;
339 }
340
341
342 public long getPurgeValidAge()
343 {
344 return _purgeValidAge;
345 }
346
347
348
349
350
351
352
353
354 public void setPurgeValidAge(long purgeValidAge)
355 {
356 this._purgeValidAge = purgeValidAge;
357 }
358
359
360 @Override
361 protected void doStart() throws Exception
362 {
363 __log.debug("MongoSessionIdManager:starting");
364
365
366
367
368 if (_scavengeDelay > 0)
369 {
370 _scavengeTimer = new Timer("MongoSessionIdScavenger",true);
371
372 synchronized (this)
373 {
374 if (_scavengerTask != null)
375 {
376 _scavengerTask.cancel();
377 }
378
379 _scavengerTask = new TimerTask()
380 {
381 @Override
382 public void run()
383 {
384 scavenge();
385 }
386 };
387
388 _scavengeTimer.schedule(_scavengerTask,_scavengeDelay,_scavengePeriod);
389 }
390 }
391
392
393
394
395 if ( _purge )
396 {
397 _purgeTimer = new Timer("MongoSessionPurger", true);
398
399 synchronized (this)
400 {
401 if (_purgeTask != null)
402 {
403 _purgeTask.cancel();
404 }
405 _purgeTask = new TimerTask()
406 {
407 @Override
408 public void run()
409 {
410 purge();
411 }
412 };
413
414 _purgeTimer.schedule(_purgeTask,0,_purgeDelay);
415 }
416 }
417 }
418
419
420 @Override
421 protected void doStop() throws Exception
422 {
423 if (_scavengeTimer != null)
424 {
425 _scavengeTimer.cancel();
426 _scavengeTimer = null;
427 }
428
429 if (_purgeTimer != null)
430 {
431 _purgeTimer.cancel();
432 _purgeTimer = null;
433 }
434
435 super.doStop();
436 }
437
438
439
440
441
442 public boolean idInUse(String sessionId)
443 {
444
445
446
447 DBObject o = _sessions.findOne(new BasicDBObject("id",sessionId), __valid_true);
448
449 if ( o != null )
450 {
451 Boolean valid = (Boolean)o.get(MongoSessionManager.__VALID);
452
453 if ( valid == null )
454 {
455 return false;
456 }
457
458 return valid;
459 }
460
461 return false;
462 }
463
464
465 public void addSession(HttpSession session)
466 {
467 if (session == null)
468 {
469 return;
470 }
471
472
473
474
475
476 __log.debug("MongoSessionIdManager:addSession:" + session.getId());
477
478 synchronized (_sessionsIds)
479 {
480 _sessionsIds.add(session.getId());
481 }
482
483 }
484
485
486 public void removeSession(HttpSession session)
487 {
488 if (session == null)
489 {
490 return;
491 }
492
493 synchronized (_sessionsIds)
494 {
495 _sessionsIds.remove(session.getId());
496 }
497 }
498
499
500 public void invalidateAll(String sessionId)
501 {
502 synchronized (_sessionsIds)
503 {
504 _sessionsIds.remove(sessionId);
505
506
507
508
509 Handler[] contexts = _server.getChildHandlersByClass(ContextHandler.class);
510 for (int i=0; contexts!=null && i<contexts.length; i++)
511 {
512 SessionHandler sessionHandler = (SessionHandler)((ContextHandler)contexts[i]).getChildHandlerByClass(SessionHandler.class);
513 if (sessionHandler != null)
514 {
515 SessionManager manager = sessionHandler.getSessionManager();
516
517 if (manager != null && manager instanceof MongoSessionManager)
518 {
519 ((MongoSessionManager)manager).invalidateSession(sessionId);
520 }
521 }
522 }
523 }
524 }
525
526
527
528 public String getClusterId(String nodeId)
529 {
530 int dot=nodeId.lastIndexOf('.');
531 return (dot>0)?nodeId.substring(0,dot):nodeId;
532 }
533
534
535
536 public String getNodeId(String clusterId, HttpServletRequest request)
537 {
538 if (_workerName!=null)
539 return clusterId+'.'+_workerName;
540
541 return clusterId;
542 }
543
544 }