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