1 /*
2  * Copyright 2002-2009 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.Collections;
21 import java.util.Enumeration;
22 import java.util.HashMap;
23 import java.util.Iterator;
24 import java.util.LinkedHashMap;
25 import java.util.Map;
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  * Supports the Servlet 2.4 API level.
37  *
38  * <p>Used for testing the web framework; also useful for testing
39  * application controllers.
40  *
41  * @author Juergen Hoeller
42  * @author Rod Johnson
43  * @author Mark Fisher
44  * @since 1.0.2
45  */
46 public class MockHttpSession implements HttpSession {
47 
48 	public static final String SESSION_COOKIE_NAME = "JSESSION";
49 
50 	private static int nextId = 1;
51 
52 
53 	private final String id;
54 
55 	private final long creationTime = System.currentTimeMillis();
56 
57 	private int maxInactiveInterval;
58 
59 	private long lastAccessedTime = System.currentTimeMillis();
60 
61 	private final ServletContext servletContext;
62 
63 	private final Map<String, Object> attributes = new LinkedHashMap<String, Object>();
64 
65 	private boolean invalid = false;
66 
67 	private boolean isNew = true;
68 
69 
70 	/**
71 	 * Create a new MockHttpSession with a default {@link org.springframework.mock.web.MockServletContext}.
72 	 * @see org.springframework.mock.web.MockServletContext
73 	 */
MockHttpSession()74 	public MockHttpSession() {
75 		this(null);
76 	}
77 
78 	/**
79 	 * Create a new MockHttpSession.
80 	 * @param servletContext the ServletContext that the session runs in
81 	 */
MockHttpSession(ServletContext servletContext)82 	public MockHttpSession(ServletContext servletContext) {
83 		this(servletContext, null);
84 	}
85 
86 	/**
87 	 * Create a new MockHttpSession.
88 	 * @param servletContext the ServletContext that the session runs in
89 	 * @param id a unique identifier for this session
90 	 */
MockHttpSession(ServletContext servletContext, String id)91 	public MockHttpSession(ServletContext servletContext, String id) {
92 		this.servletContext = (servletContext != null ? servletContext : new MockServletContext());
93 		this.id = (id != null ? id : Integer.toString(nextId++));
94 	}
95 
96 
getCreationTime()97 	public long getCreationTime() {
98 		return this.creationTime;
99 	}
100 
getId()101 	public String getId() {
102 		return this.id;
103 	}
104 
access()105 	public void access() {
106 		this.lastAccessedTime = System.currentTimeMillis();
107 		this.isNew = false;
108 	}
109 
getLastAccessedTime()110 	public long getLastAccessedTime() {
111 		return this.lastAccessedTime;
112 	}
113 
getServletContext()114 	public ServletContext getServletContext() {
115 		return this.servletContext;
116 	}
117 
setMaxInactiveInterval(int interval)118 	public void setMaxInactiveInterval(int interval) {
119 		this.maxInactiveInterval = interval;
120 	}
121 
getMaxInactiveInterval()122 	public int getMaxInactiveInterval() {
123 		return this.maxInactiveInterval;
124 	}
125 
getSessionContext()126 	public HttpSessionContext getSessionContext() {
127 		throw new UnsupportedOperationException("getSessionContext");
128 	}
129 
getAttribute(String name)130 	public Object getAttribute(String name) {
131 		Assert.notNull(name, "Attribute name must not be null");
132 		return this.attributes.get(name);
133 	}
134 
getValue(String name)135 	public Object getValue(String name) {
136 		return getAttribute(name);
137 	}
138 
getAttributeNames()139 	public Enumeration<String> getAttributeNames() {
140 		return Collections.enumeration(this.attributes.keySet());
141 	}
142 
getValueNames()143 	public String[] getValueNames() {
144 		return this.attributes.keySet().toArray(new String[this.attributes.size()]);
145 	}
146 
setAttribute(String name, Object value)147 	public void setAttribute(String name, Object value) {
148 		Assert.notNull(name, "Attribute name must not be null");
149 		if (value != null) {
150 			this.attributes.put(name, value);
151 			if (value instanceof HttpSessionBindingListener) {
152 				((HttpSessionBindingListener) value).valueBound(new HttpSessionBindingEvent(this, name, value));
153 			}
154 		}
155 		else {
156 			removeAttribute(name);
157 		}
158 	}
159 
putValue(String name, Object value)160 	public void putValue(String name, Object value) {
161 		setAttribute(name, value);
162 	}
163 
removeAttribute(String name)164 	public void removeAttribute(String name) {
165 		Assert.notNull(name, "Attribute name must not be null");
166 		Object value = this.attributes.remove(name);
167 		if (value instanceof HttpSessionBindingListener) {
168 			((HttpSessionBindingListener) value).valueUnbound(new HttpSessionBindingEvent(this, name, value));
169 		}
170 	}
171 
removeValue(String name)172 	public void removeValue(String name) {
173 		removeAttribute(name);
174 	}
175 
176 	/**
177 	 * Clear all of this session's attributes.
178 	 */
clearAttributes()179 	public void clearAttributes() {
180 		for (Iterator<Map.Entry<String, Object>> it = this.attributes.entrySet().iterator(); it.hasNext();) {
181 			Map.Entry<String, Object> entry = it.next();
182 			String name = entry.getKey();
183 			Object value = entry.getValue();
184 			it.remove();
185 			if (value instanceof HttpSessionBindingListener) {
186 				((HttpSessionBindingListener) value).valueUnbound(new HttpSessionBindingEvent(this, name, value));
187 			}
188 		}
189 	}
190 
invalidate()191 	public void invalidate() {
192 		this.invalid = true;
193 		clearAttributes();
194 	}
195 
isInvalid()196 	public boolean isInvalid() {
197 		return this.invalid;
198 	}
199 
setNew(boolean value)200 	public void setNew(boolean value) {
201 		this.isNew = value;
202 	}
203 
isNew()204 	public boolean isNew() {
205 		return this.isNew;
206 	}
207 
208 
209 	/**
210 	 * Serialize the attributes of this session into an object that can
211 	 * be turned into a byte array with standard Java serialization.
212 	 * @return a representation of this session's serialized state
213 	 */
serializeState()214 	public Serializable serializeState() {
215 		HashMap<String, Serializable> state = new HashMap<String, Serializable>();
216 		for (Iterator<Map.Entry<String, Object>> it = this.attributes.entrySet().iterator(); it.hasNext();) {
217 			Map.Entry<String, Object> entry = it.next();
218 			String name = entry.getKey();
219 			Object value = entry.getValue();
220 			it.remove();
221 			if (value instanceof Serializable) {
222 				state.put(name, (Serializable) value);
223 			}
224 			else {
225 				// Not serializable... Servlet containers usually automatically
226 				// unbind the attribute in this case.
227 				if (value instanceof HttpSessionBindingListener) {
228 					((HttpSessionBindingListener) value).valueUnbound(new HttpSessionBindingEvent(this, name, value));
229 				}
230 			}
231 		}
232 		return state;
233 	}
234 
235 	/**
236 	 * Deserialize the attributes of this session from a state object
237 	 * created by {@link #serializeState()}.
238 	 * @param state a representation of this session's serialized state
239 	 */
240 	@SuppressWarnings("unchecked")
deserializeState(Serializable state)241 	public void deserializeState(Serializable state) {
242 		Assert.isTrue(state instanceof Map, "Serialized state needs to be of type [java.util.Map]");
243 		this.attributes.putAll((Map<String, Object>) state);
244 	}
245 
246 }
247