View Javadoc

1   /*
2    * Copyright 2009-2010 Capgemini Licensed under the Apache License, Version 2.0
3    * (the "License"); you may not use this file except in compliance with the
4    * License. You may obtain a copy of the License at
5    * 
6    * http://www.apache.org/licenses/LICENSE-2.0
7    * 
8    * Unless required by applicable law or agreed to in writing, software
9    * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11   * License for the specific language governing permissions and limitations under
12   * the License.
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   * Stateless session object, returned by the wrapped request.
38   * 
39   * @author Nicolas Richeton - Capgemini
40   * 
41   */
42  public class StatelessSession implements HttpSession, Serializable {
43  	final private static String SECURE_ALGORITHM = "SHA1PRNG"; //$NON-NLS-1$
44  
45  	final private static String NULL_VALUE = "net.sourceforge.statelessfilter.session.NullValue";
46  	/**
47  	 * Generated serial ID
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  	 * Modified attributes during the current request.
61  	 */
62  	private volatile List<String> modifiedAttributes = new Vector<String>();
63  
64  	/**
65  	 * Were this session properties (validity, maxInactiveInterval) modified
66  	 * during the current request.
67  	 */
68  	private volatile boolean propertyDirty = false;
69  
70  	/**
71  	 * Was this session modified during the current request.
72  	 */
73  	private volatile boolean dirty = false;
74  
75  	private final StatelessRequestWrapper request;
76  	private boolean valid;
77  
78  	/**
79  	 * Creates a new StatelessSession.
80  	 * 
81  	 * @param request
82  	 */
83  	public StatelessSession(StatelessRequestWrapper request) {
84  		this.request = request;
85  	}
86  
87  	/**
88  	 * @see javax.servlet.http.HttpSession#getAttribute(java.lang.String)
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 	 * @see javax.servlet.http.HttpSession#getAttributeNames()
102 	 */
103 	@SuppressWarnings("unchecked")
104 	public Enumeration getAttributeNames() {
105 		return IteratorUtils.asEnumeration(content.keySet().iterator());
106 	}
107 
108 	/**
109 	 * Get all session content.
110 	 * 
111 	 * @return
112 	 */
113 	public Map<String, Object> getContent() {
114 		return content;
115 	}
116 
117 	/**
118 	 * @see javax.servlet.http.HttpSession#getCreationTime()
119 	 */
120 	public long getCreationTime() {
121 		return creationTime;
122 	}
123 
124 	public List<String> getDirtyAttributes() {
125 		return modifiedAttributes;
126 	}
127 
128 	/**
129 	 * @see javax.servlet.http.HttpSession#getId()
130 	 */
131 	public String getId() {
132 		return id;
133 	}
134 
135 	/**
136 	 * @see javax.servlet.http.HttpSession#getLastAccessedTime()
137 	 */
138 	public long getLastAccessedTime() {
139 		return lastAccessedTime;
140 	}
141 
142 	/**
143 	 * @see javax.servlet.http.HttpSession#getMaxInactiveInterval()
144 	 */
145 	public int getMaxInactiveInterval() {
146 		return maxInactiveInterval;
147 	}
148 
149 	/**
150 	 * @see javax.servlet.http.HttpSession#getServletContext()
151 	 */
152 	public ServletContext getServletContext() {
153 		return request.getServerSession().getServletContext();
154 	}
155 
156 	/**
157 	 * @see javax.servlet.http.HttpSession#getSessionContext()
158 	 * @deprecated
159 	 */
160 	@Deprecated
161 	public HttpSessionContext getSessionContext() {
162 		throw new NotImplementedException();
163 	}
164 
165 	/**
166 	 * @see javax.servlet.http.HttpSession#getValue(java.lang.String)
167 	 * @deprecated
168 	 */
169 	@Deprecated
170 	public Object getValue(String name) {
171 		return getAttribute(name);
172 	}
173 
174 	/**
175 	 * @see javax.servlet.http.HttpSession#getValueNames()
176 	 * @deprecated
177 	 */
178 	@Deprecated
179 	public String[] getValueNames() {
180 		return (String[]) content.keySet().toArray();
181 	}
182 
183 	/**
184 	 * Init session internal values.
185 	 * 
186 	 * @throws NoSuchAlgorithmException
187 	 *             - if strong random generator not available
188 	 */
189 	public void init() throws NoSuchAlgorithmException {
190 		init(true);
191 	}
192 
193 	/**
194 	 * Init session internal values.
195 	 * <ul>
196 	 * <li>As a new session if newSession is true</li>
197 	 * <li>As an existing session if new Session if false</li>
198 	 * </ul
199 	 * 
200 	 * 
201 	 * @param newSession
202 	 * @throws NoSuchAlgorithmException
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 	 * @see javax.servlet.http.HttpSession#invalidate()
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 	 * @see javax.servlet.http.HttpSession#isNew()
236 	 */
237 	public boolean isNew() {
238 		return isNew;
239 	}
240 
241 	public boolean isPropertyDirty() {
242 		return propertyDirty;
243 	}
244 
245 	/**
246 	 * Checks session validity
247 	 * 
248 	 * @return
249 	 */
250 	public boolean isValid() {
251 		return valid;
252 	}
253 
254 	/**
255 	 * Merge session data with an external ISessionData object.
256 	 * 
257 	 * @param data
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 	 * @see javax.servlet.http.HttpSession#putValue(java.lang.String,
268 	 *      java.lang.Object)
269 	 * @deprecated
270 	 */
271 	@Deprecated
272 	public void putValue(String name, Object value) {
273 		setAttribute(name, value);
274 	}
275 
276 	/**
277 	 * @see javax.servlet.http.HttpSession#removeAttribute(java.lang.String)
278 	 */
279 	public void removeAttribute(String name) {
280 		content.remove(name);
281 		setAttributeDirty(name);
282 	}
283 
284 	/**
285 	 * @see javax.servlet.http.HttpSession#removeValue(java.lang.String)
286 	 * @deprecated
287 	 */
288 	@Deprecated
289 	public void removeValue(String name) {
290 		removeAttribute(name);
291 	}
292 
293 	/**
294 	 * @see javax.servlet.http.HttpSession#setAttribute(java.lang.String,
295 	 *      java.lang.Object)
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 	 * @see javax.servlet.http.HttpSession#setMaxInactiveInterval(int)
310 	 */
311 	public void setMaxInactiveInterval(int interval) {
312 		this.maxInactiveInterval = interval;
313 		setPropertyDirty();
314 	}
315 
316 	/**
317 	 * Set session new state.
318 	 * 
319 	 * @param b
320 	 */
321 	public void setNew(boolean b) {
322 		this.isNew = b;
323 	}
324 
325 	/**
326 	 * Set the dirty flag for attributeName and for the whole session.
327 	 * 
328 	 * @param attrName
329 	 *            Name of the attribute to be flagged.
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 }