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 }