1 package servletunit; 2 3 // StrutsTestCase - a JUnit extension for testing Struts actions 4 // within the context of the ActionServlet. 5 // Copyright (C) 2002 Deryl Seale 6 // 7 // This library is free software; you can redistribute it and/or 8 // modify it under the terms of the Apache Software License as 9 // published by the Apache Software Foundation; either version 1.1 10 // of the License, or (at your option) any later version. 11 // 12 // This library is distributed in the hope that it will be useful, 13 // but WITHOUT ANY WARRANTY; without even the implied warranty of 14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 // Apache Software Foundation Licens for more details. 16 // 17 // You may view the full text here: http://www.apache.org/LICENSE.txt 18 19 import org.apache.commons.logging.Log; 20 import org.apache.commons.logging.LogFactory; 21 22 import javax.servlet.RequestDispatcher; 23 import javax.servlet.Servlet; 24 import javax.servlet.ServletContext; 25 import javax.servlet.ServletException; 26 import java.io.InputStream; 27 import java.io.File; 28 import java.io.FileInputStream; 29 import java.net.MalformedURLException; 30 import java.net.URL; 31 import java.util.Enumeration; 32 import java.util.Hashtable; 33 import java.util.Set; 34 35 /** 36 * This class simulates a ServletContext. 37 */ 38 public class ServletContextSimulator implements ServletContext 39 { 40 41 private Hashtable initParameters; 42 private Hashtable attributes; 43 private RequestDispatcherSimulator dispatcher = null; 44 private static Log logger = LogFactory.getLog( ServletContextSimulator.class ); 45 private File contextDirectory; 46 47 public ServletContextSimulator() { 48 this.initParameters = new Hashtable(); 49 this.attributes = new Hashtable(); 50 } 51 52 /** 53 * Returns the servlet container attribute with the given name, 54 * or <code>null</code> if there is no attribute by that name. 55 * An attribute allows a servlet container to give the 56 * servlet additional information not 57 * already provided by this interface. See your 58 * server documentation for information about its attributes. 59 * A list of supported attributes can be retrieved using 60 * <code>getAttributeNames</code>. 61 * 62 * <p>The attribute is returned as a <code>java.lang.Object</code> 63 * or some subclass. 64 * Attribute names should follow the same convention as package 65 * names. The Java Servlet API specification reserves names 66 * matching <code>java.*</code>, <code>javax.*</code>, 67 * and <code>sun.*</code>. 68 * 69 * 70 * @param name a <code>String</code> specifying the name 71 * of the attribute 72 * 73 * @return an <code>Object</code> containing the value 74 * of the attribute, or <code>null</code> 75 * if no attribute exists matching the given 76 * name 77 * 78 * @see ServletContext#getAttributeNames 79 * 80 */ 81 public Object getAttribute(String name) 82 { 83 return attributes.get(name); 84 } 85 86 /** 87 * Returns an <code>Enumeration</code> containing the 88 * attribute names available 89 * within this servlet context. Use the 90 * {@link #getAttribute} method with an attribute name 91 * to get the value of an attribute. 92 * 93 * @return an <code>Enumeration</code> of attribute 94 * names 95 * 96 * @see #getAttribute 97 * 98 */ 99 public Enumeration getAttributeNames() 100 { 101 return attributes.keys(); 102 } 103 104 /** 105 * Unsupported in this version. 106 */ 107 public ServletContext getContext(String uripath) 108 { 109 throw new UnsupportedOperationException("getContext operation is not supported!"); 110 } 111 112 /** 113 * Returns a <code>String</code> containing the value of the named 114 * context-wide initialization parameter, or <code>null</code> if the 115 * parameter does not exist. 116 * 117 * <p>This method can make available configuration information useful 118 * to an entire "web application". For example, it can provide a 119 * webmaster's email address or the name of a system that holds 120 * critical data. 121 * 122 * @param s a <code>String</code> containing the name of the 123 * parameter whose value is requested 124 * 125 * @return a <code>String</code> containing at least the 126 * servlet container name and version number 127 * 128 * @see javax.servlet.ServletConfig#getInitParameter 129 */ 130 public String getInitParameter(String s) 131 { 132 return (String) initParameters.get(s); 133 } 134 135 /** 136 * Returns the names of the context's initialization parameters as an 137 * <code>Enumeration</code> of <code>String</code> objects, or an 138 * empty <code>Enumeration</code> if the context has no initialization 139 * parameters. 140 * 141 * @return an <code>Enumeration</code> of <code>String</code> 142 * objects containing the names of the context's 143 * initialization parameters 144 * 145 * @see javax.servlet.ServletConfig#getInitParameter 146 */ 147 public Enumeration getInitParameterNames() 148 { 149 return initParameters.keys(); 150 } 151 152 /** 153 * Sets a named initialization parameter with the supplied 154 * <code>String</code> value. 155 * 156 * @param key a <code>String</code> specifying the name 157 * of the initialization parameter 158 * 159 * @param value a <code>String</code> value for this initialization 160 * parameter 161 * 162 */ 163 public void setInitParameter(String key,String value) 164 { 165 initParameters.put(key,value); 166 } 167 168 /** 169 * Returns the major version of the Java Servlet API that this 170 * Web server supports. All implementations that comply 171 * with Version 2.3 must have this method 172 * return the integer 2. 173 * 174 * @return 2 175 * 176 */ 177 public int getMajorVersion() 178 { 179 return 2; 180 } 181 182 /** 183 * Unsupported in this version. 184 */ 185 public String getMimeType(String file) 186 { 187 throw new UnsupportedOperationException("getMimeType operation is not supported!"); 188 } 189 190 /** 191 * Returns the minor version of the Servlet API that this 192 * Web server supports. All implementations that comply 193 * with Version 2.3 must have this method 194 * return the integer 1. 195 * 196 * @return 3 197 * 198 */ 199 public int getMinorVersion() 200 { 201 return 3; 202 } 203 204 public RequestDispatcher getNamedDispatcher(String s) 205 { 206 throw new UnsupportedOperationException("getNamedDispatcher operation is not supported!"); 207 } 208 209 public String getRealPath(String path) 210 { 211 if ((contextDirectory == null) || (path == null)) 212 return null; 213 else 214 return (new File(contextDirectory, path)).getAbsolutePath(); 215 } 216 217 /** 218 * 219 * Returns a {@link RequestDispatcher} object that acts 220 * as a wrapper for the resource located at the given path. 221 * A <code>RequestDispatcher</code> object can be used to forward 222 * a request to the resource or to include the resource in a response. 223 * The resource can be dynamic or static. 224 * 225 * <p>The pathname must begin with a "/" and is interpreted as relative 226 * to the current context root. Use <code>getContext</code> to obtain 227 * a <code>RequestDispatcher</code> for resources in foreign contexts. 228 * This method returns <code>null</code> if the <code>ServletContext</code> 229 * cannot return a <code>RequestDispatcher</code>. 230 * 231 * @param urlpath a <code>String</code> specifying the pathname 232 * to the resource 233 * 234 * @return a <code>RequestDispatcher</code> object 235 * that acts as a wrapper for the resource 236 * at the specified path 237 * 238 * @see RequestDispatcher 239 * @see ServletContext#getContext 240 * 241 */ 242 public RequestDispatcher getRequestDispatcher(String urlpath) 243 { 244 dispatcher = new RequestDispatcherSimulator(urlpath); 245 return dispatcher; 246 } 247 248 /** 249 * Returns the mock RequestDispatcher object used in this test. 250 * The RequestDispatcherSimulator contains forwarding information 251 * that can be used in test validation. 252 */ 253 public RequestDispatcherSimulator getRequestDispatcherSimulator() { 254 return dispatcher; 255 } 256 257 /** 258 * TODO: add appropriate comments 259 */ 260 public URL getResource(String path) throws MalformedURLException 261 { 262 try { 263 File file = getResourceAsFile(path); 264 265 if (file.exists()) { 266 return file.toURL(); 267 } 268 else { 269 if(!path.startsWith("/")){ 270 path = "/" + path; 271 } 272 return this.getClass().getResource(path); 273 } 274 } catch (Exception e) { 275 return null; 276 } 277 } 278 279 /** 280 * Returns the resource located at the named path as 281 * an <code>InputStream</code> object. 282 * 283 * <p>The data in the <code>InputStream</code> can be 284 * of any type or length. The path must be specified according 285 * to the rules given in <code>getResource</code>. 286 * This method returns <code>null</code> if no resource exists at 287 * the specified path. 288 * 289 * <p>Meta-information such as content length and content type 290 * that is available via <code>getResource</code> 291 * method is lost when using this method. 292 * 293 * <p>The servlet container must implement the URL handlers 294 * and <code>URLConnection</code> objects necessary to access 295 * the resource. 296 * 297 * <p>In this mock implementation, this method first looks for 298 * the supplied pathname in the underlying filesystem; if it 299 * does not exist there, the default Java classloader is used. 300 * 301 * 302 * @param path a <code>String</code> specifying the path 303 * to the resource 304 * 305 * @return the <code>InputStream</code> returned to the 306 * servlet, or <code>null</code> if no resource 307 * exists at the specified path 308 * 309 * 310 */ 311 public InputStream getResourceAsStream(String path) 312 { 313 try { 314 File file = getResourceAsFile(path); 315 316 if (file.exists()) { 317 return new FileInputStream(file); 318 } 319 else { 320 if(!path.startsWith("/")){ 321 path = "/" + path; 322 } 323 return this.getClass().getResourceAsStream(path); 324 } 325 } catch (Exception e) { 326 System.out.println("caught error: " + e); 327 e.printStackTrace(); 328 return null; 329 } 330 } 331 332 /** 333 * Attempts to load a resource from the underlying file system 334 * and return a file handle to it. 335 * It first treats the path as an absolute path. If no file is found, 336 * it attempts to treat the path as relative to the context directory. 337 * If no file is found, it attempts to treat the path as relative to 338 * the current directory. 339 * If all these options fail, the returned file will return false() 340 * to calls to File.exists(). 341 * @param path the relative or context-relative path to the file 342 * @return the refernce to the file (which may or may not exist) 343 */ 344 public File getResourceAsFile(String path){ 345 File file = new File(path); 346 347 // If the path is relative then apply the contextDirectory path if it exists. 348 if (!file.exists()) 349 { 350 if(!path.startsWith("/")){ 351 path = "/" + path; 352 } 353 if((getContextDirectory() != null)) 354 { 355 file = new File(getContextDirectory().getAbsolutePath() + path); 356 }else{ 357 //try using current directory 358 file = new File(new File(".").getAbsolutePath() + path); 359 } 360 } 361 return file; 362 363 } 364 365 /** 366 * Unsupported in this version. 367 */ 368 public Set getResourcePaths() 369 { 370 throw new UnsupportedOperationException("getResourcePaths operation is not supported!"); 371 } 372 373 /** 374 * Returns the name and version of the servlet container on which 375 * the servlet is running. 376 * 377 * <p>The form of the returned string is 378 * <i>servername</i>/<i>versionnumber</i>. 379 * For example, the JavaServer Web Development Kit may return the string 380 * <code>JavaServer Web Dev Kit/1.0</code>. 381 * 382 * <p>The servlet container may return other optional information 383 * after the primary string in parentheses, for example, 384 * <code>JavaServer Web Dev Kit/1.0 (JDK 1.1.6; Windows NT 4.0 x86)</code>. 385 * 386 * 387 * @return a <code>String</code> containing at least the 388 * servlet container name and version number 389 * 390 */ 391 public String getServerInfo() 392 { 393 return "MockServletEngine/1.9.5"; 394 } 395 396 /** 397 * Unsupported in this version. 398 */ 399 public Servlet getServlet(String name) throws ServletException 400 { 401 throw new UnsupportedOperationException("getServlet operation is not supported!"); 402 } 403 404 /** 405 * Unsupported in this version. 406 */ 407 public String getServletContextName() 408 { 409 throw new UnsupportedOperationException("getServletContextName operation is not supported!"); 410 } 411 412 /** 413 * Unsupported in this version. 414 */ 415 public Enumeration getServletNames() 416 { 417 throw new UnsupportedOperationException("getServletNames operation is not supported!"); 418 } 419 420 /** 421 * Unsupported in this version. 422 */ 423 public Enumeration getServlets() 424 { 425 throw new UnsupportedOperationException("getServlets operation is not supported!"); 426 } 427 428 /** 429 * @deprecated As of Java Servlet API 2.1, use 430 * @link ServletContext.log(String message, Throwable throwable) 431 * instead. 432 * 433 * <p>This method was originally defined to write an 434 * exception's stack trace and an explanatory error message 435 * to the servlet log file. 436 * 437 */ 438 public void log(Exception exception, String msg) 439 { 440 logger.info(msg + "\n" + exception.getClass() + " - " + exception.getMessage()); 441 } 442 443 /** 444 * 445 * Writes the specified message to a servlet log file, which is usually 446 * an event log. The message provides explanatory information about 447 * an exception or error or an action the servlet engine takes. The name 448 * and type of the servlet log file is specific to the servlet engine. 449 * 450 * 451 * @param msg a <code>String</code> specifying the explanatory 452 * message to be written to the log file 453 * 454 */ 455 public void log(String msg) 456 { 457 logger.info(msg); 458 } 459 460 /** 461 * Writes the stack trace and an explanatory message 462 * for a given <code>Throwable</code> exception 463 * to the servlet log file. The name and type of the servlet log 464 * file is specific to the servlet engine, but it is usually an event log. 465 * 466 * 467 * @param message a <code>String</code> that 468 * describes the error or exception 469 * 470 * @param throwable the <code>Throwable</code> error 471 * or exception 472 * 473 */ 474 public void log(String message, Throwable throwable) 475 { 476 logger.info(message + "\n" + throwable.getClass() + " - " + throwable.getMessage()); 477 } 478 479 /** 480 * Removes the attribute with the given name from 481 * the servlet context. After removal, subsequent calls to 482 * {@link #getAttribute} to retrieve the attribute's value 483 * will return <code>null</code>. 484 485 * <p>If listeners are configured on the <code>ServletContext</code> the 486 * container notifies them accordingly. 487 488 * 489 * 490 * @param name a <code>String</code> specifying the name 491 * of the attribute to be removed 492 * 493 */ 494 public void removeAttribute(String name) 495 { 496 attributes.remove(name); 497 } 498 499 /** 500 * 501 * Binds an object to a given attribute name in this servlet context. If 502 * the name specified is already used for an attribute, this 503 * method will replace the attribute with the new to the new attribute. 504 * <p>If listeners are configured on the <code>ServletContext</code> the 505 * container notifies them accordingly. 506 * <p> 507 * If a null value is passed, the effect is the same as calling 508 * <code>removeAttribute()</code>. 509 * 510 * <p>Attribute names should follow the same convention as package 511 * names. The Java Servlet API specification reserves names 512 * matching <code>java.*</code>, <code>javax.*</code>, and 513 * <code>sun.*</code>. 514 * 515 * 516 * @param name a <code>String</code> specifying the name 517 * of the attribute 518 * 519 * @param object an <code>Object</code> representing the 520 * attribute to be bound 521 * 522 * 523 * 524 */ 525 public void setAttribute(String name, Object object) 526 { 527 attributes.put(name,object); 528 } 529 530 /** 531 * Unsupported in this version. 532 */ 533 public Set getResourcePaths(String path) { 534 throw new UnsupportedOperationException("getResourcePaths operation is not supported!"); 535 } 536 537 /** 538 * Sets the absolute context directory to be used in the getRealPath() method. 539 * @param contextDirectory the absolute path of the root context directory for this application. 540 */ 541 public void setContextDirectory(File contextDirectory) { 542 this.contextDirectory = contextDirectory; 543 } 544 545 public File getContextDirectory() { 546 return contextDirectory; 547 } 548 549 550 }