1 /*
2  * Copyright 2002-2011 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package org.springframework.mock.web;
18 
19 import java.io.Serializable;
20 import java.util.Enumeration;
21 import java.util.HashMap;
22 import java.util.Iterator;
23 import java.util.LinkedHashMap;
24 import java.util.Map;
25 import java.util.Vector;
26 import javax.servlet.ServletContext;
27 import javax.servlet.http.HttpSession;
28 import javax.servlet.http.HttpSessionBindingEvent;
29 import javax.servlet.http.HttpSessionBindingListener;
30 import javax.servlet.http.HttpSessionContext;
31 
32 import org.springframework.util.Assert;
33 
34 /**
35  * Mock implementation of the {@link javax.servlet.http.HttpSession} interface.
36  *
37  * <p>Compatible with Servlet 2.5 as well as Servlet 3.0.
38  *
39  * @author Juergen Hoeller
40  * @author Rod Johnson
41  * @author Mark Fisher
42  * @since 1.0.2
43  */
44 @SuppressWarnings("deprecation")
45 public class MockHttpSession implements HttpSession {
46 
47 	private static int nextId = 1;
48 
49 	private final String id;
50 
51 	private final long creationTime = System.currentTimeMillis();
52 
53 	private int maxInactiveInterval;
54 
55 	private long lastAccessedTime = System.currentTimeMillis();
56 
57 	private final ServletContext servletContext;
58 
59 	private final Map<String, Object> attributes = new LinkedHashMap<String, Object>();
60 
61 	private boolean invalid = false;
62 
63 	private boolean isNew = true;
64 
65 
66 	/**
67 	 * Create a new MockHttpSession with a default {@link MockServletContext}.
68 	 *
69 	 * @see MockServletContext
70 	 */
MockHttpSession()71 	public MockHttpSession() {
72 		this(null);
73 	}
74 
75 	/**
76 	 * Create a new MockHttpSession.
77 	 *
78 	 * @param servletContext the ServletContext that the session runs in
79 	 */
MockHttpSession(ServletContext servletContext)80 	public MockHttpSession(ServletContext servletContext) {
81 		this(servletContext, null);
82 	}
83 
84 	/**
85 	 * Create a new MockHttpSession.
86 	 *
87 	 * @param servletContext the ServletContext that the session runs in
88 	 * @param id a unique identifier for this session
89 	 */
MockHttpSession(ServletContext servletContext, String id)90 	public MockHttpSession(ServletContext servletContext, String id) {
91 		this.servletContext = (servletContext != null ? servletContext : new MockServletContext());
92 		this.id = (id != null ? id : Integer.toString(nextId++));
93 	}
94 
getCreationTime()95 	public long getCreationTime() {
96 		return this.creationTime;
97 	}
98 
getId()99 	public String getId() {
100 		return this.id;
101 	}
102 
access()103 	public void access() {
104 		this.lastAccessedTime = System.currentTimeMillis();
105 		this.isNew = false;
106 	}
107 
getLastAccessedTime()108 	public long getLastAccessedTime() {
109 		return this.lastAccessedTime;
110 	}
111 
getServletContext()112 	public ServletContext getServletContext() {
113 		return this.servletContext;
114 	}
115 
setMaxInactiveInterval(int interval)116 	public void setMaxInactiveInterval(int interval) {
117 		this.maxInactiveInterval = interval;
118 	}
119 
getMaxInactiveInterval()120 	public int getMaxInactiveInterval() {
121 		return this.maxInactiveInterval;
122 	}
123 
getSessionContext()124 	public HttpSessionContext getSessionContext() {
125 		throw new UnsupportedOperationException("getSessionContext");
126 	}
127 
getAttribute(String name)128 	public Object getAttribute(String name) {
129 		Assert.notNull(name, "Attribute name must not be null");
130 		return this.attributes.get(name);
131 	}
132 
getValue(String name)133 	public Object getValue(String name) {
134 		return getAttribute(name);
135 	}
136 
getAttributeNames()137 	public Enumeration<String> getAttributeNames() {
138 		return new Vector<String>(this.attributes.keySet()).elements();
139 	}
140 
getValueNames()141 	public String[] getValueNames() {
142 		return this.attributes.keySet().toArray(new String[this.attributes.size()]);
143 	}
144 
setAttribute(String name, Object value)145 	public void setAttribute(String name, Object value) {
146 		Assert.notNull(name, "Attribute name must not be null");
147 		if (value != null) {
148 			this.attributes.put(name, value);
149 			if (value instanceof HttpSessionBindingListener) {
150 				((HttpSessionBindingListener) value).valueBound(new HttpSessionBindingEvent(this, name, value));
151 			}
152 		}
153 		else {
154 			removeAttribute(name);
155 		}
156 	}
157 
putValue(String name, Object value)158 	public void putValue(String name, Object value) {
159 		setAttribute(name, value);
160 	}
161 
removeAttribute(String name)162 	public void removeAttribute(String name) {
163 		Assert.notNull(name, "Attribute name must not be null");
164 		Object value = this.attributes.remove(name);
165 		if (value instanceof HttpSessionBindingListener) {
166 			((HttpSessionBindingListener) value).valueUnbound(new HttpSessionBindingEvent(this, name, value));
167 		}
168 	}
169 
removeValue(String name)170 	public void removeValue(String name) {
171 		removeAttribute(name);
172 	}
173 
174 	/**
175 	 * Clear all of this session's attributes.
176 	 */
clearAttributes()177 	public void clearAttributes() {
178 		for (Iterator<Map.Entry<String, Object>> it = this.attributes.entrySet().iterator(); it.hasNext();) {
179 			Map.Entry<String, Object> entry = it.next();
180 			String name = entry.getKey();
181 			Object value = entry.getValue();
182 			it.remove();
183 			if (value instanceof HttpSessionBindingListener) {
184 				((HttpSessionBindingListener) value).valueUnbound(new HttpSessionBindingEvent(this, name, value));
185 			}
186 		}
187 	}
188 
invalidate()189 	public void invalidate() {
190 		this.invalid = true;
191 		clearAttributes();
192 	}
193 
isInvalid()194 	public boolean isInvalid() {
195 		return this.invalid;
196 	}
197 
setNew(boolean value)198 	public void setNew(boolean value) {
199 		this.isNew = value;
200 	}
201 
isNew()202 	public boolean isNew() {
203 		return this.isNew;
204 	}
205 
206 	/**
207 	 * Serialize the attributes of this session into an object that can be
208 	 * turned into a byte array with standard Java serialization.
209 	 *
210 	 * @return a representation of this session's serialized state
211 	 */
serializeState()212 	public Serializable serializeState() {
213 		HashMap<String, Serializable> state = new HashMap<String, Serializable>();
214 		for (Iterator<Map.Entry<String, Object>> it = this.attributes.entrySet().iterator(); it.hasNext();) {
215 			Map.Entry<String, Object> entry = it.next();
216 			String name = entry.getKey();
217 			Object value = entry.getValue();
218 			it.remove();
219 			if (value instanceof Serializable) {
220 				state.put(name, (Serializable) value);
221 			}
222 			else {
223 				// Not serializable... Servlet containers usually automatically
224 				// unbind the attribute in this case.
225 				if (value instanceof HttpSessionBindingListener) {
226 					((HttpSessionBindingListener) value).valueUnbound(new HttpSessionBindingEvent(this, name, value));
227 				}
228 			}
229 		}
230 		return state;
231 	}
232 
233 	/**
234 	 * Deserialize the attributes of this session from a state object created by
235 	 * {@link #serializeState()}.
236 	 *
237 	 * @param state a representation of this session's serialized state
238 	 */
239 	@SuppressWarnings("unchecked")
deserializeState(Serializable state)240 	public void deserializeState(Serializable state) {
241 		Assert.isTrue(state instanceof Map, "Serialized state needs to be of type [java.util.Map]");
242 		this.attributes.putAll((Map<String, Object>) state);
243 	}
244 
245 }
246