Commit | Line | Data |
---|---|---|
d5dd6a2d FT |
1 | package dolda.jsvc.util; |
2 | ||
3 | import dolda.jsvc.*; | |
4 | import java.util.*; | |
5 | import java.security.SecureRandom; | |
6 | ||
7 | public class Session implements java.io.Serializable { | |
8 | private static final Map<String, Session> sessions = new HashMap<String, Session>(); | |
48ea770f | 9 | private static final Map<Request, Session> cache = new WeakHashMap<Request, Session>(); |
d5dd6a2d FT |
10 | private static final SecureRandom prng; |
11 | private static long lastclean = 0; | |
12 | private final Map<Object, Object> props = new HashMap<Object, Object>(); | |
13 | private long ctime = System.currentTimeMillis(), atime = ctime, etime = 86400 * 1000; | |
14 | private Collection<Listener> ll = new HashSet<Listener>(); | |
15 | ||
16 | static { | |
17 | try { | |
18 | prng = SecureRandom.getInstance("SHA1PRNG"); | |
19 | } catch(java.security.NoSuchAlgorithmException e) { | |
20 | throw(new Error(e)); | |
21 | } | |
22 | } | |
23 | ||
24 | public static interface Listener { | |
25 | public void expire(Session sess); | |
26 | } | |
27 | ||
48ea770f FT |
28 | public synchronized void listen(Listener l) { |
29 | ll.add(l); | |
d5dd6a2d FT |
30 | } |
31 | ||
48ea770f FT |
32 | public synchronized Object get(Object key, Object def) { |
33 | if(props.containsKey(key)) | |
34 | return(props.get(key)); | |
35 | else | |
36 | return(def); | |
d5dd6a2d FT |
37 | } |
38 | ||
48ea770f FT |
39 | public synchronized Object put(Object key, Object val) { |
40 | return(props.put(key, val)); | |
d5dd6a2d FT |
41 | } |
42 | ||
48ea770f FT |
43 | private synchronized void expire() { |
44 | for(Listener l : ll) | |
45 | l.expire(this); | |
d5dd6a2d FT |
46 | } |
47 | ||
48ea770f FT |
48 | public synchronized static int num() { |
49 | return(sessions.size()); | |
d5dd6a2d FT |
50 | } |
51 | ||
52 | private static String newid() { | |
53 | byte[] rawid = new byte[16]; | |
54 | prng.nextBytes(rawid); | |
55 | StringBuilder buf = new StringBuilder(); | |
56 | for(byte b : rawid) { | |
57 | buf.append(Misc.int2hex((b & 0xf0) >> 4, false)); | |
58 | buf.append(Misc.int2hex(b & 0x0f, false)); | |
59 | } | |
60 | return(buf.toString()); | |
61 | } | |
62 | ||
63 | private static Session create(Request req) { | |
64 | Session sess = new Session(); | |
65 | long etime = 0; | |
66 | int ct; | |
67 | ct = Integer.parseInt(req.ctx().libconfig("jsvc.session.expire", "0")); | |
68 | if(ct > 0) | |
69 | sess.etime = ct; | |
70 | ct = Integer.parseInt(req.ctx().sysconfig("jsvc.session.expire", "0")); | |
71 | if(ct > 0) | |
72 | sess.etime = ct; | |
73 | return(sess); | |
74 | } | |
75 | ||
48ea770f | 76 | private synchronized static void clean() { |
d5dd6a2d | 77 | long now = System.currentTimeMillis(); |
48ea770f FT |
78 | for(Iterator<Session> i = sessions.values().iterator(); i.hasNext();) { |
79 | Session sess = i.next(); | |
80 | if(now > sess.atime + sess.etime) { | |
81 | i.remove(); | |
82 | sess.expire(); | |
d5dd6a2d FT |
83 | } |
84 | } | |
85 | } | |
86 | ||
48ea770f | 87 | public synchronized static Session get(Request req) { |
d5dd6a2d FT |
88 | long now = System.currentTimeMillis(); |
89 | if(now - lastclean > 3600 * 1000) { | |
90 | clean(); | |
91 | lastclean = now; | |
92 | } | |
93 | ||
48ea770f | 94 | Session sess = cache.get(req); |
70c1fc5a FT |
95 | if(sess != null) { |
96 | sess.atime = System.currentTimeMillis(); | |
48ea770f | 97 | return(sess); |
70c1fc5a | 98 | } |
48ea770f | 99 | |
d5dd6a2d FT |
100 | MultiMap<String, Cookie> cookies = Cookie.get(req); |
101 | Cookie sc = cookies.get("jsvc-session"); | |
48ea770f FT |
102 | |
103 | if(sc != null) | |
104 | sess = sessions.get(sc.value); | |
105 | if(sess == null) { | |
106 | String id = newid(); | |
107 | sess = create(req); | |
108 | sessions.put(id, sess); | |
109 | sc = new Cookie("jsvc-session", id); | |
110 | sc.expires = new Date(System.currentTimeMillis() + (86400L * 365L * 1000L)); | |
111 | sc.path = req.ctx().sysconfig("jsvc.session.path", req.rooturl().getPath()); | |
112 | String pd = req.ctx().sysconfig("jsvc.session.domain", null); | |
113 | if(pd != null) | |
114 | sc.domain = pd; | |
115 | sc.addto(req); | |
d5dd6a2d | 116 | } |
48ea770f FT |
117 | |
118 | cache.put(req, sess); | |
70c1fc5a | 119 | sess.atime = System.currentTimeMillis(); |
d5dd6a2d FT |
120 | return(sess); |
121 | } | |
122 | ||
123 | public static Session get() { | |
124 | return(get(RequestThread.request())); | |
125 | } | |
126 | } |