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