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