001 package com.mockrunner.mock.web;
002
003 import java.lang.reflect.Constructor;
004
005 import javax.servlet.http.HttpServletRequest;
006 import javax.servlet.http.HttpServletResponse;
007 import javax.servlet.jsp.JspFactory;
008
009 import com.mockrunner.base.NestedApplicationException;
010
011 /**
012 * Used to create all types of web mock objects. Maintains
013 * the necessary dependencies between the mock objects.
014 * If you use the mock objects returned by this
015 * factory in your tests you can be sure that they are all
016 * up to date.
017 */
018 public class WebMockObjectFactory
019 {
020 private HttpServletRequest wrappedRequest;
021 private HttpServletResponse wrappedResponse;
022 private MockHttpServletRequest request;
023 private MockHttpServletResponse response;
024 private MockServletConfig config;
025 private MockServletContext context;
026 private MockHttpSession session;
027 private MockPageContext pageContext;
028 private MockFilterConfig filterConfig;
029 private MockFilterChain filterChain;
030 private JspFactory jspFactory;
031
032 /**
033 * Creates a new set of mock objects.
034 */
035 public WebMockObjectFactory()
036 {
037 createMockObjects();
038 }
039
040 /**
041 * Creates a set of mock objects based on another one.
042 * The created mock objects will have their own
043 * request and session objects, but they will share
044 * one <code>ServletContext</code>.
045 * @param factory the other factory
046 * @see com.mockrunner.base.BaseTestCase#createWebMockObjectFactory(WebMockObjectFactory)
047 */
048 public WebMockObjectFactory(WebMockObjectFactory factory)
049 {
050 createMockObjectsBasedOn(factory);
051 }
052
053 /**
054 * Creates a set of mock objects based on another one.
055 * You can specify, if the created mock objects should
056 * share the same session. They will share one
057 * <code>ServletContext</code> anyway.
058 * @param factory the other factory
059 * @param createNewSession <code>true</code> creates a new session,
060 * <code>false</code> uses the session from factory
061 * @see com.mockrunner.base.BaseTestCase#createWebMockObjectFactory(WebMockObjectFactory, boolean)
062 */
063 public WebMockObjectFactory(WebMockObjectFactory factory, boolean createNewSession)
064 {
065 createMockObjectsBasedOn(factory, createNewSession);
066 }
067
068 private void createMockObjects()
069 {
070 createNewMockObjects(true);
071 context = createMockServletContext();
072 setUpDependencies();
073 JspFactory.setDefaultFactory(jspFactory);
074 }
075
076 private void createMockObjectsBasedOn(WebMockObjectFactory factory)
077 {
078 createMockObjectsBasedOn(factory, true);
079 }
080
081 private void createMockObjectsBasedOn(WebMockObjectFactory factory, boolean createNewSession)
082 {
083 createNewMockObjects(createNewSession);
084 if(!createNewSession) session = factory.getMockSession();
085 context = factory.getMockServletContext();
086 setUpDependencies();
087 JspFactory.setDefaultFactory(jspFactory);
088 }
089
090 private void createNewMockObjects(boolean createNewSession)
091 {
092 request = createMockRequest();
093 response = createMockResponse();
094 wrappedRequest = request;
095 wrappedResponse = response;
096 if(createNewSession) session = createMockSession();
097 config = createMockServletConfig();
098 filterChain = createMockFilterChain();
099 filterConfig = createMockFilterConfig();
100 jspFactory = createMockJspFactory();
101 }
102
103 private void setUpDependencies()
104 {
105 config.setServletContext(context);
106 request.setSession(session);
107 session.setupServletContext(context);
108 pageContext = createMockPageContext();
109 pageContext.setServletConfig(config);
110 pageContext.setServletRequest(request);
111 pageContext.setServletResponse(response);
112 filterConfig.setupServletContext(context);
113 setUpJspFactory();
114 }
115
116 private void setUpJspFactory()
117 {
118 if(jspFactory instanceof MockJspFactory)
119 {
120 ((MockJspFactory)jspFactory).setPageContext(pageContext);
121 }
122 }
123
124 /**
125 * Sets the default <code>JspFactory</code> by calling
126 * <code>JspFactory.setDefaultFactory()</code>.
127 * @param jspFactory the <code>JspFactory</code>
128 */
129 public void setDefaultJspFactory(JspFactory jspFactory)
130 {
131 JspFactory.setDefaultFactory(jspFactory);
132 this.jspFactory = jspFactory;
133 setUpJspFactory();
134 }
135
136 /**
137 * Refreshes the mock objects dependencies. May be called after setting request
138 * and response wrappers.
139 */
140 public void refresh()
141 {
142 pageContext = new MockPageContext(config, wrappedRequest, wrappedResponse);
143 setUpJspFactory();
144 }
145
146 /**
147 * Creates the {@link com.mockrunner.mock.web.MockServletContext} using <code>new</code>.
148 * This method can be overridden to return a subclass of {@link com.mockrunner.mock.web.MockServletContext}.
149 * @return the {@link com.mockrunner.mock.web.MockServletContext}
150 */
151 public MockServletContext createMockServletContext()
152 {
153 return new MockServletContext();
154 }
155
156 /**
157 * Creates the {@link com.mockrunner.mock.web.MockServletConfig} using <code>new</code>.
158 * This method can be overridden to return a subclass of {@link com.mockrunner.mock.web.MockServletConfig}.
159 * @return the {@link com.mockrunner.mock.web.MockServletConfig}
160 */
161 public MockServletConfig createMockServletConfig()
162 {
163 return new MockServletConfig();
164 }
165
166 /**
167 * Creates the {@link com.mockrunner.mock.web.MockHttpServletResponse} using <code>new</code>.
168 * This method can be overridden to return a subclass of {@link com.mockrunner.mock.web.MockHttpServletResponse}.
169 * @return the {@link com.mockrunner.mock.web.MockHttpServletResponse}
170 */
171 public MockHttpServletResponse createMockResponse()
172 {
173 return new MockHttpServletResponse();
174 }
175
176 /**
177 * Creates the {@link com.mockrunner.mock.web.MockHttpServletRequest} using <code>new</code>.
178 * This method can be overridden to return a subclass of {@link com.mockrunner.mock.web.MockHttpServletRequest}.
179 * @return the {@link com.mockrunner.mock.web.MockHttpServletRequest}
180 */
181 public MockHttpServletRequest createMockRequest()
182 {
183 return new MockHttpServletRequest();
184 }
185
186 /**
187 * Creates the {@link com.mockrunner.mock.web.MockHttpSession} using <code>new</code>.
188 * This method can be overridden to return a subclass of {@link com.mockrunner.mock.web.MockHttpSession}.
189 * @return the {@link com.mockrunner.mock.web.MockHttpSession}
190 */
191 public MockHttpSession createMockSession()
192 {
193 return new MockHttpSession();
194 }
195
196 /**
197 * Creates the {@link com.mockrunner.mock.web.MockPageContext} using <code>new</code>.
198 * This method can be overridden to return a subclass of {@link com.mockrunner.mock.web.MockPageContext}.
199 * @return the {@link com.mockrunner.mock.web.MockPageContext}
200 */
201 public MockPageContext createMockPageContext()
202 {
203 return new MockPageContext();
204 }
205
206 /**
207 * Creates the {@link com.mockrunner.mock.web.MockFilterConfig} using <code>new</code>.
208 * This method can be overridden to return a subclass of {@link com.mockrunner.mock.web.MockFilterConfig}.
209 * @return the {@link com.mockrunner.mock.web.MockFilterConfig}
210 */
211 public MockFilterConfig createMockFilterConfig()
212 {
213 return new MockFilterConfig();
214 }
215
216 /**
217 * Creates the {@link com.mockrunner.mock.web.MockFilterChain} using <code>new</code>.
218 * This method can be overridden to return a subclass of {@link com.mockrunner.mock.web.MockFilterChain}.
219 * @return the {@link com.mockrunner.mock.web.MockFilterChain}
220 */
221 public MockFilterChain createMockFilterChain()
222 {
223 return new MockFilterChain();
224 }
225
226 /**
227 * Creates the {@link com.mockrunner.mock.web.MockJspFactory} using <code>new</code>.
228 * This method can be overridden to return a subclass of {@link com.mockrunner.mock.web.MockJspFactory}.
229 * @return the {@link com.mockrunner.mock.web.MockJspFactory}
230 */
231 public MockJspFactory createMockJspFactory()
232 {
233 return new MockJspFactory();
234 }
235
236 /**
237 * Returns the <code>MockServletConfig</code>
238 * @return the <code>MockServletConfig</code>
239 */
240 public MockServletConfig getMockServletConfig()
241 {
242 return config;
243 }
244
245 /**
246 * Returns the {@link com.mockrunner.mock.web.MockServletContext}.
247 * @return the {@link com.mockrunner.mock.web.MockServletContext}
248 */
249 public MockServletContext getMockServletContext()
250 {
251 return context;
252 }
253
254 /**
255 * Returns the {@link com.mockrunner.mock.web.MockHttpServletRequest}.
256 * @return the {@link com.mockrunner.mock.web.MockHttpServletRequest}
257 */
258 public MockHttpServletRequest getMockRequest()
259 {
260 return request;
261 }
262
263 /**
264 * Returns the {@link com.mockrunner.mock.web.MockHttpServletResponse}.
265 * @return the {@link com.mockrunner.mock.web.MockHttpServletResponse}
266 */
267 public MockHttpServletResponse getMockResponse()
268 {
269 return response;
270 }
271
272 /**
273 * Returns the wrapped <code>HttpServletRequest</code>. If no
274 * wrapper is specified, this method returns the mock request itself.
275 * @return the wrapped <code>HttpServletRequest</code>
276 */
277 public HttpServletRequest getWrappedRequest()
278 {
279 return wrappedRequest;
280 }
281
282 /**
283 * Returns the wrapped <code>HttpServletResponse</code>. If no
284 * wrapper is specified, this method returns the mock response itself.
285 * @return the wrapped <code>HttpServletRequest</code>
286 */
287 public HttpServletResponse getWrappedResponse()
288 {
289 return wrappedResponse;
290 }
291
292 /**
293 * Returns the {@link com.mockrunner.mock.web.MockHttpSession}.
294 * @return the {@link com.mockrunner.mock.web.MockHttpSession}
295 */
296 public MockHttpSession getMockSession()
297 {
298 return session;
299 }
300
301 /**
302 * Returns the {@link com.mockrunner.mock.web.MockHttpSession}.
303 * @return the {@link com.mockrunner.mock.web.MockHttpSession}
304 * @deprecated use {@link #getMockSession}
305 */
306 public MockHttpSession getSession()
307 {
308 return getMockSession();
309 }
310
311 /**
312 * Returns the {@link com.mockrunner.mock.web.MockPageContext}.
313 * @return the {@link com.mockrunner.mock.web.MockPageContext}
314 */
315 public MockPageContext getMockPageContext()
316 {
317 return pageContext;
318 }
319
320 /**
321 * Returns the {@link com.mockrunner.mock.web.MockFilterConfig}.
322 * @return the {@link com.mockrunner.mock.web.MockFilterConfig}
323 */
324 public MockFilterConfig getMockFilterConfig()
325 {
326 return filterConfig;
327 }
328
329 /**
330 * Returns the {@link com.mockrunner.mock.web.MockFilterChain}.
331 * @return the {@link com.mockrunner.mock.web.MockFilterChain}
332 */
333 public MockFilterChain getMockFilterChain()
334 {
335 return filterChain;
336 }
337
338 /**
339 * Returns the {@link com.mockrunner.mock.web.MockJspFactory}.
340 * If the current <code>JspFactory</code> is not an instance
341 * of {@link com.mockrunner.mock.web.MockJspFactory}, <code>null</code>
342 * will be returned.
343 * @return the {@link com.mockrunner.mock.web.MockJspFactory}
344 */
345 public MockJspFactory getMockJspFactory()
346 {
347 if(jspFactory instanceof MockJspFactory)
348 {
349 return (MockJspFactory)jspFactory;
350 }
351 return null;
352 }
353
354 /**
355 * Returns the <code>JspFactory</code>.
356 * @return the <code>JspFactory</code>
357 */
358 public JspFactory getJspFactory()
359 {
360 return jspFactory;
361 }
362
363 /**
364 * Can be used to add a request wrapper. All the
365 * test modules are using the wrapped request returned by
366 * {@link #getWrappedRequest}. The method {@link #getMockRequest}
367 * returns the mock request without any wrapper.
368 * Usually the wrapper is of type <code>javax.servlet.http.HttpServletRequestWrapper</code>.
369 * That's not absolutely necessary but the wrapper must define a constructor
370 * that takes a single <code>javax.servlet.http.HttpServletRequest</code> argument
371 * and must implement <code>javax.servlet.http.HttpServletRequest</code>.
372 * @param wrapper the wrapper class
373 */
374 public void addRequestWrapper(Class wrapper)
375 {
376 try
377 {
378 Constructor constructor = wrapper.getConstructor(new Class[] {HttpServletRequest.class});
379 wrappedRequest = (HttpServletRequest)constructor.newInstance(new Object[] {wrappedRequest});
380 }
381 catch(Exception exc)
382 {
383 throw new NestedApplicationException(exc);
384 }
385 }
386
387 /**
388 * Can be used to add a request wrapper.
389 * All the test modules are using the wrapped request returned by
390 * {@link #getWrappedRequest}. The method {@link #getMockRequest}
391 * returns the mock request without any wrapper. Usually the wrapper is
392 * an instance of <code>javax.servlet.http.HttpServletRequestWrapper</code>
393 * and wraps the current request but that's not absolutely necessary.
394 * However, be careful if you want to add custom mock versions of
395 * <code>javax.servlet.http.HttpServletRequest</code>.
396 * @param wrapper the request wrapper
397 */
398 public void addRequestWrapper(HttpServletRequest wrapper)
399 {
400 wrappedRequest = wrapper;
401 }
402
403 /**
404 * Can be used to add a response wrapper. All the
405 * test modules are using the wrapped response returned by
406 * {@link #getWrappedResponse}. The method {@link #getMockResponse}
407 * returns the mock response without any wrapper.
408 * Usually the wrapper is of type <code>javax.servlet.http.HttpServletResponseWrapper</code>.
409 * That's not absolutely necessary but the wrapper must define a constructor
410 * that takes a single <code>javax.servlet.http.HttpServletResponse</code> argument
411 * and must implement <code>javax.servlet.http.HttpServletResponse</code>.
412 * @param wrapper the wrapper class
413 */
414 public void addResponseWrapper(Class wrapper)
415 {
416 try
417 {
418 Constructor constructor = wrapper.getConstructor(new Class[] {HttpServletResponse.class});
419 wrappedResponse = (HttpServletResponse)constructor.newInstance(new Object[] {wrappedResponse});
420 }
421 catch(Exception exc)
422 {
423 throw new NestedApplicationException(exc);
424 }
425 }
426
427 /**
428 * Can be used to add a response wrapper.
429 * All the test modules are using the wrapped response returned by
430 * {@link #getWrappedResponse}. The method {@link #getMockResponse}
431 * returns the mock response without any wrapper. Usually the wrapper is
432 * an instance of <code>javax.servlet.http.HttpServletResponseWrapper</code>
433 * and wraps the current response but that's not absolutely necessary.
434 * However, be careful if you want to add custom mock versions of
435 * <code>javax.servlet.http.HttpServletResponse</code>.
436 * @param wrapper the wrapper
437 */
438 public void addResponseWrapper(HttpServletResponse wrapper)
439 {
440 wrappedResponse = wrapper;
441 }
442 }