1
2
3
4
5
6
7
8
9
10
11
12
13
14 package net.sourceforge.statelessfilter.session;
15
16 import java.io.Serializable;
17 import java.security.NoSuchAlgorithmException;
18 import java.security.SecureRandom;
19 import java.util.Enumeration;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.Vector;
23 import java.util.concurrent.ConcurrentHashMap;
24
25 import javax.servlet.ServletContext;
26 import javax.servlet.http.HttpSession;
27 import javax.servlet.http.HttpSessionContext;
28
29 import net.sourceforge.statelessfilter.backend.ISessionData;
30 import net.sourceforge.statelessfilter.wrappers.StatelessRequestWrapper;
31
32 import org.apache.commons.codec.binary.Hex;
33 import org.apache.commons.collections.IteratorUtils;
34 import org.apache.commons.lang.NotImplementedException;
35
36
37
38
39
40
41
42 public class StatelessSession implements HttpSession, Serializable {
43 final private static String SECURE_ALGORITHM = "SHA1PRNG";
44
45 final private static String NULL_VALUE = "net.sourceforge.statelessfilter.session.NullValue";
46
47
48
49 private static final long serialVersionUID = 3707021777892035588L;
50 private Map<String, Object> content;
51
52 private long creationTime;
53
54 private String id;
55 private boolean isNew;
56 private final long lastAccessedTime = 0;
57 private int maxInactiveInterval = 30 * 60;
58
59
60
61
62 private volatile List<String> modifiedAttributes = new Vector<String>();
63
64
65
66
67
68 private volatile boolean propertyDirty = false;
69
70
71
72
73 private volatile boolean dirty = false;
74
75 private final StatelessRequestWrapper request;
76 private boolean valid;
77
78
79
80
81
82
83 public StatelessSession(StatelessRequestWrapper request) {
84 this.request = request;
85 }
86
87
88
89
90 public Object getAttribute(String name) {
91 Object result = content.get(name);
92
93 if (result instanceof String && NULL_VALUE.equals(result)) {
94 result = null;
95 }
96
97 return result;
98 }
99
100
101
102
103 @SuppressWarnings("unchecked")
104 public Enumeration getAttributeNames() {
105 return IteratorUtils.asEnumeration(content.keySet().iterator());
106 }
107
108
109
110
111
112
113 public Map<String, Object> getContent() {
114 return content;
115 }
116
117
118
119
120 public long getCreationTime() {
121 return creationTime;
122 }
123
124 public List<String> getDirtyAttributes() {
125 return modifiedAttributes;
126 }
127
128
129
130
131 public String getId() {
132 return id;
133 }
134
135
136
137
138 public long getLastAccessedTime() {
139 return lastAccessedTime;
140 }
141
142
143
144
145 public int getMaxInactiveInterval() {
146 return maxInactiveInterval;
147 }
148
149
150
151
152 public ServletContext getServletContext() {
153 return request.getServerSession().getServletContext();
154 }
155
156
157
158
159
160 @Deprecated
161 public HttpSessionContext getSessionContext() {
162 throw new NotImplementedException();
163 }
164
165
166
167
168
169 @Deprecated
170 public Object getValue(String name) {
171 return getAttribute(name);
172 }
173
174
175
176
177
178 @Deprecated
179 public String[] getValueNames() {
180 return (String[]) content.keySet().toArray();
181 }
182
183
184
185
186
187
188
189 public void init() throws NoSuchAlgorithmException {
190 init(true);
191 }
192
193
194
195
196
197
198
199
200
201
202
203
204 public void init(boolean newSession) throws NoSuchAlgorithmException {
205
206 if (newSession) {
207 SecureRandom rand = SecureRandom.getInstance(SECURE_ALGORITHM);
208 byte[] data = new byte[32];
209 rand.nextBytes(data);
210 creationTime = System.currentTimeMillis();
211 id = new String(Hex.encodeHex(data)) + creationTime;
212 valid = true;
213 setPropertyDirty();
214 }
215
216 content = new ConcurrentHashMap<String, Object>();
217 isNew = newSession;
218 dirty = newSession;
219 }
220
221
222
223
224 public void invalidate() {
225 valid = false;
226 setPropertyDirty();
227 content = new ConcurrentHashMap<String, Object>();
228 }
229
230 public boolean isDirty() {
231 return dirty;
232 }
233
234
235
236
237 public boolean isNew() {
238 return isNew;
239 }
240
241 public boolean isPropertyDirty() {
242 return propertyDirty;
243 }
244
245
246
247
248
249
250 public boolean isValid() {
251 return valid;
252 }
253
254
255
256
257
258
259 public void merge(ISessionData data) {
260 content.putAll(data.getContent());
261 id = data.getId();
262 valid = data.isValid();
263 creationTime = data.getCreationTime();
264 }
265
266
267
268
269
270
271 @Deprecated
272 public void putValue(String name, Object value) {
273 setAttribute(name, value);
274 }
275
276
277
278
279 public void removeAttribute(String name) {
280 content.remove(name);
281 setAttributeDirty(name);
282 }
283
284
285
286
287
288 @Deprecated
289 public void removeValue(String name) {
290 removeAttribute(name);
291 }
292
293
294
295
296
297 public void setAttribute(String name, Object value) {
298 Object toInsert = value;
299
300 if (toInsert == null) {
301 toInsert = NULL_VALUE;
302 }
303
304 content.put(name, toInsert);
305 setAttributeDirty(name);
306 }
307
308
309
310
311 public void setMaxInactiveInterval(int interval) {
312 this.maxInactiveInterval = interval;
313 setPropertyDirty();
314 }
315
316
317
318
319
320
321 public void setNew(boolean b) {
322 this.isNew = b;
323 }
324
325
326
327
328
329
330
331 private void setAttributeDirty(String attrName) {
332 if (!modifiedAttributes.contains(attrName)) {
333 modifiedAttributes.add(attrName);
334 }
335 dirty = true;
336 }
337
338 private void setPropertyDirty() {
339 dirty = true;
340 propertyDirty = true;
341 }
342 }