1 7 package winstone; 8 9 import java.io.File ; 10 import java.io.IOException ; 11 import java.io.InputStream ; 12 import java.io.PrintWriter ; 13 import java.io.StringWriter ; 14 import java.lang.reflect.Constructor ; 15 import java.net.MalformedURLException ; 16 import java.net.URL ; 17 import java.net.URLClassLoader ; 18 import java.util.ArrayList ; 19 import java.util.Arrays ; 20 import java.util.Collection ; 21 import java.util.Collections ; 22 import java.util.Comparator ; 23 import java.util.Enumeration ; 24 import java.util.HashMap ; 25 import java.util.HashSet ; 26 import java.util.Hashtable ; 27 import java.util.Iterator ; 28 import java.util.List ; 29 import java.util.Map ; 30 import java.util.Set ; 31 import java.util.StringTokenizer ; 32 33 import javax.servlet.ServletContext ; 34 import javax.servlet.ServletContextAttributeEvent ; 35 import javax.servlet.ServletContextAttributeListener ; 36 import javax.servlet.ServletContextEvent ; 37 import javax.servlet.ServletContextListener ; 38 import javax.servlet.ServletException ; 39 import javax.servlet.ServletRequestAttributeListener ; 40 import javax.servlet.ServletRequestListener ; 41 import javax.servlet.http.HttpServletResponse ; 42 import javax.servlet.http.HttpSessionActivationListener ; 43 import javax.servlet.http.HttpSessionAttributeListener ; 44 import javax.servlet.http.HttpSessionListener ; 45 46 import org.w3c.dom.Node ; 47 import org.w3c.dom.NodeList ; 48 49 56 public class WebAppConfiguration implements ServletContext , Comparator { 57 private static final String ELEM_DISPLAY_NAME = "display-name"; 59 private static final String ELEM_SERVLET = "servlet"; 60 private static final String ELEM_SERVLET_MAPPING = "servlet-mapping"; 61 private static final String ELEM_SERVLET_NAME = "servlet-name"; 62 private static final String ELEM_FILTER = "filter"; 63 private static final String ELEM_FILTER_MAPPING = "filter-mapping"; 64 private static final String ELEM_FILTER_NAME = "filter-name"; 65 private static final String ELEM_DISPATCHER = "dispatcher"; 66 private static final String ELEM_URL_PATTERN = "url-pattern"; 67 private static final String ELEM_WELCOME_FILES = "welcome-file-list"; 68 private static final String ELEM_WELCOME_FILE = "welcome-file"; 69 private static final String ELEM_SESSION_CONFIG = "session-config"; 70 private static final String ELEM_SESSION_TIMEOUT = "session-timeout"; 71 private static final String ELEM_MIME_MAPPING = "mime-mapping"; 72 private static final String ELEM_MIME_EXTENSION = "extension"; 73 private static final String ELEM_MIME_TYPE = "mime-type"; 74 private static final String ELEM_CONTEXT_PARAM = "context-param"; 75 private static final String ELEM_PARAM_NAME = "param-name"; 76 private static final String ELEM_PARAM_VALUE = "param-value"; 77 private static final String ELEM_LISTENER = "listener"; 78 private static final String ELEM_LISTENER_CLASS = "listener-class"; 79 private static final String ELEM_DISTRIBUTABLE = "distributable"; 80 private static final String ELEM_ERROR_PAGE = "error-page"; 81 private static final String ELEM_EXCEPTION_TYPE = "exception-type"; 82 private static final String ELEM_ERROR_CODE = "error-code"; 83 private static final String ELEM_ERROR_LOCATION = "location"; 84 private static final String ELEM_SECURITY_CONSTRAINT = "security-constraint"; 85 private static final String ELEM_LOGIN_CONFIG = "login-config"; 86 private static final String ELEM_SECURITY_ROLE = "security-role"; 87 private static final String ELEM_ROLE_NAME = "role-name"; 88 private static final String ELEM_ENV_ENTRY = "env-entry"; 89 private static final String ELEM_LOCALE_ENC_MAP_LIST = "locale-encoding-mapping-list"; 90 private static final String ELEM_LOCALE_ENC_MAPPING = "locale-encoding-mapping"; 91 private static final String ELEM_LOCALE = "locale"; 92 private static final String ELEM_ENCODING = "encoding"; 93 private static final String ELEM_JSP_CONFIG = "jsp-config"; 94 private static final String ELEM_JSP_PROPERTY_GROUP = "jsp-property-group"; 95 96 private static final String DISPATCHER_REQUEST = "REQUEST"; 97 private static final String DISPATCHER_FORWARD = "FORWARD"; 98 private static final String DISPATCHER_INCLUDE = "INCLUDE"; 99 private static final String DISPATCHER_ERROR = "ERROR"; 100 private static final String JSP_SERVLET_NAME = "JspServlet"; 101 private static final String JSP_SERVLET_MAPPING = "*.jsp"; 102 private static final String JSPX_SERVLET_MAPPING = "*.jspx"; 103 private static final String JSP_SERVLET_LOG_LEVEL = "WARNING"; 104 private static final String INVOKER_SERVLET_NAME = "invoker"; 105 private static final String INVOKER_SERVLET_CLASS = "winstone.invoker.InvokerServlet"; 106 private static final String DEFAULT_INVOKER_PREFIX = "/servlet/"; 107 private static final String DEFAULT_SERVLET_NAME = "default"; 108 private static final String DEFAULT_SERVLET_CLASS = "winstone.StaticResourceServlet"; 109 private static final String DEFAULT_REALM_CLASS = "winstone.realm.ArgumentsRealm"; 110 private static final String DEFAULT_JNDI_MGR_CLASS = "winstone.jndi.WebAppJNDIManager"; 111 private static final String RELOADING_CL_CLASS = "winstone.classLoader.ReloadingClassLoader"; 112 private static final String ERROR_SERVLET_NAME = "winstoneErrorServlet"; 113 private static final String ERROR_SERVLET_CLASS = "winstone.ErrorServlet"; 114 115 private static final String WEB_INF = "WEB-INF"; 116 private static final String CLASSES = "classes/"; 117 private static final String LIB = "lib"; 118 119 static final String JSP_SERVLET_CLASS = "org.apache.jasper.servlet.JspServlet"; 120 121 private HostConfiguration ownerHostConfig; 122 private Cluster cluster; 123 private String webRoot; 124 private String prefix; 125 private String contextName; 126 private ClassLoader loader; 127 private String displayName; 128 private Map attributes; 129 private Map initParameters; 130 private Map sessions; 131 private Map mimeTypes; 132 private Map servletInstances; 133 private Map filterInstances; 134 private ServletContextAttributeListener contextAttributeListeners[]; 135 private ServletContextListener contextListeners[]; 136 private ServletRequestListener requestListeners[]; 137 private ServletRequestAttributeListener requestAttributeListeners[]; 138 private HttpSessionActivationListener sessionActivationListeners[]; 139 private HttpSessionAttributeListener sessionAttributeListeners[]; 140 private HttpSessionListener sessionListeners[]; 141 private Throwable contextStartupError; 142 private Map exactServletMatchMounts; 143 private Mapping patternMatches[]; 144 private Mapping filterPatternsRequest[]; 145 private Mapping filterPatternsForward[]; 146 private Mapping filterPatternsInclude[]; 147 private Mapping filterPatternsError[]; 148 private AuthenticationHandler authenticationHandler; 149 private AuthenticationRealm authenticationRealm; 150 private String welcomeFiles[]; 151 private Integer sessionTimeout; 152 private Class [] errorPagesByExceptionKeysSorted; 153 private Map errorPagesByException; 154 private Map errorPagesByCode; 155 private Map localeEncodingMap; 156 private String defaultServletName; 157 private String errorServletName; 158 private JNDIManager jndiManager; 159 private AccessLogger accessLogger; 160 private Map filterMatchCache; 161 private boolean useSavedSessions; 162 163 public static boolean booleanArg(Map args, String name, boolean defaultTrue) { 164 String value = (String ) args.get(name); 165 if (defaultTrue) 166 return (value == null) || (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("yes")); 167 else 168 return (value != null) && (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("yes")); 169 } 170 171 public static String stringArg(Map args, String name, String defaultValue) { 172 return (String ) (args.get(name) == null ? defaultValue : args.get(name)); 173 } 174 175 public static int intArg(Map args, String name, int defaultValue) { 176 return Integer.parseInt(stringArg(args, name, "" + defaultValue)); 177 } 178 179 public static String getTextFromNode(Node node) { 180 if (node == null) { 181 return null; 182 } 183 Node child = node.getFirstChild(); 184 if (child == null) { 185 return ""; 186 } 187 String textNode = child.getNodeValue(); 188 if (textNode == null) { 189 return ""; 190 } else { 191 return textNode.trim(); 192 } 193 } 194 195 public static boolean useSavedSessions(Map args) { 196 return booleanArg(args, "useSavedSessions", false); 197 } 198 199 202 public WebAppConfiguration(HostConfiguration ownerHostConfig, Cluster cluster, String webRoot, 203 String prefix, ObjectPool objectPool, Map startupArgs, Node elm, 204 ClassLoader parentClassLoader, File parentClassPaths[], String contextName) { 205 this.ownerHostConfig = ownerHostConfig; 206 this.webRoot = webRoot; 207 this.prefix = prefix; 208 this.contextName = contextName; 209 210 List localLoaderClassPathFiles = new ArrayList (); 211 this.loader = buildWebAppClassLoader(startupArgs, parentClassLoader, 212 webRoot, localLoaderClassPathFiles); 213 214 boolean useJasper = booleanArg(startupArgs, "useJasper", false); 216 boolean useInvoker = booleanArg(startupArgs, "useInvoker", false); 217 boolean useJNDI = booleanArg(startupArgs, "useJNDI", false); 218 this.useSavedSessions = useSavedSessions(startupArgs); 219 220 if (useJasper) { 222 try { 223 Class.forName(JSP_SERVLET_CLASS, false, this.loader); 224 } catch (Throwable err) { 225 Logger.log(Logger.WARNING, Launcher.RESOURCES, 226 "WebAppConfig.JasperNotFound"); 227 Logger.log(Logger.DEBUG, Launcher.RESOURCES, 228 "WebAppConfig.JasperLoadException", err); 229 useJasper = false; 230 } 231 } 232 if (useInvoker) { 233 try { 234 Class.forName(INVOKER_SERVLET_CLASS, false, this.loader); 235 } catch (Throwable err) { 236 Logger.log(Logger.WARNING, Launcher.RESOURCES, 237 "WebAppConfig.InvokerNotFound"); 238 useInvoker = false; 239 } 240 } 241 242 this.attributes = new Hashtable (); 243 this.initParameters = new HashMap (); 244 this.sessions = new Hashtable (); 245 246 this.servletInstances = new HashMap (); 247 this.filterInstances = new HashMap (); 248 this.filterMatchCache = new HashMap (); 249 250 List contextAttributeListeners = new ArrayList (); 251 List contextListeners = new ArrayList (); 252 List requestListeners = new ArrayList (); 253 List requestAttributeListeners = new ArrayList (); 254 List sessionActivationListeners = new ArrayList (); 255 List sessionAttributeListeners = new ArrayList (); 256 List sessionListeners = new ArrayList (); 257 258 this.errorPagesByException = new HashMap (); 259 this.errorPagesByCode = new HashMap (); 260 boolean distributable = false; 261 262 this.exactServletMatchMounts = new Hashtable (); 263 List localFolderPatterns = new ArrayList (); 264 List localExtensionPatterns = new ArrayList (); 265 266 List lfpRequest = new ArrayList (); 267 List lfpForward = new ArrayList (); 268 List lfpInclude = new ArrayList (); 269 List lfpError = new ArrayList (); 270 271 List localWelcomeFiles = new ArrayList (); 272 List startupServlets = new ArrayList (); 273 274 Set rolesAllowed = new HashSet (); 275 List constraintNodes = new ArrayList (); 276 List envEntryNodes = new ArrayList (); 277 List localErrorPagesByExceptionList = new ArrayList (); 278 279 Node loginConfigNode = null; 280 281 addListenerInstance(this.loader, contextAttributeListeners, 283 contextListeners, requestAttributeListeners, requestListeners, 284 sessionActivationListeners, sessionAttributeListeners, 285 sessionListeners); 286 287 this.mimeTypes = new Hashtable (); 289 String allTypes = Launcher.RESOURCES.getString("WebAppConfig.DefaultMimeTypes"); 290 StringTokenizer mappingST = new StringTokenizer (allTypes, ":", false); 291 for (; mappingST.hasMoreTokens();) { 292 String mapping = mappingST.nextToken(); 293 int delimPos = mapping.indexOf('='); 294 if (delimPos == -1) 295 continue; 296 String extension = mapping.substring(0, delimPos); 297 String mimeType = mapping.substring(delimPos + 1); 298 this.mimeTypes.put(extension.toLowerCase(), mimeType); 299 } 300 301 this.localeEncodingMap = new HashMap (); 302 String encodingMapSet = Launcher.RESOURCES.getString("WebAppConfig.EncodingMap"); 303 StringTokenizer st = new StringTokenizer (encodingMapSet, ";"); 304 for (; st.hasMoreTokens();) { 305 String token = st.nextToken(); 306 int delimPos = token.indexOf("="); 307 if (delimPos == -1) 308 continue; 309 this.localeEncodingMap.put(token.substring(0, delimPos), token 310 .substring(delimPos + 1)); 311 } 312 313 List jspMappings = new ArrayList (); 315 jspMappings.add(JSP_SERVLET_MAPPING); 316 jspMappings.add(JSPX_SERVLET_MAPPING); 317 318 File tmpDir = new File (new File (new File (System.getProperty("java.io.tmpdir"), 320 "winstone.tmp"), ownerHostConfig.getHostname()), contextName); 321 tmpDir.mkdirs(); 322 this.attributes.put("javax.servlet.context.tempdir", tmpDir); 323 324 if (elm != null) { 326 NodeList children = elm.getChildNodes(); 327 for (int n = 0; n < children.getLength(); n++) { 328 Node child = children.item(n); 329 if (child.getNodeType() != Node.ELEMENT_NODE) 330 continue; 331 String nodeName = child.getNodeName(); 332 333 if (nodeName.equals(ELEM_DISPLAY_NAME)) 334 this.displayName = getTextFromNode(child); 335 336 else if (nodeName.equals(ELEM_DISTRIBUTABLE)) 337 distributable = true; 338 339 else if (nodeName.equals(ELEM_SECURITY_CONSTRAINT)) 340 constraintNodes.add(child); 341 342 else if (nodeName.equals(ELEM_ENV_ENTRY)) 343 envEntryNodes.add(child); 344 345 else if (nodeName.equals(ELEM_LOGIN_CONFIG)) 346 loginConfigNode = child; 347 348 else if (nodeName.equals(ELEM_SESSION_CONFIG)) { 350 for (int m = 0; m < child.getChildNodes().getLength(); m++) { 351 Node timeoutElm = child.getChildNodes().item(m); 352 if ((timeoutElm.getNodeType() == Node.ELEMENT_NODE) 353 && (timeoutElm.getNodeName().equals(ELEM_SESSION_TIMEOUT))) { 354 String timeoutStr = getTextFromNode(child); 355 if (!timeoutStr.equals("")) { 356 this.sessionTimeout = Integer.valueOf(timeoutStr); 357 } 358 } 359 } 360 } 361 362 else if (child.getNodeName().equals(ELEM_SECURITY_ROLE)) { 364 for (int m = 0; m < child.getChildNodes().getLength(); m++) { 365 Node roleElm = child.getChildNodes().item(m); 366 if ((roleElm.getNodeType() == Node.ELEMENT_NODE) 367 && (roleElm.getNodeName() 368 .equals(ELEM_ROLE_NAME))) 369 rolesAllowed.add(getTextFromNode(roleElm)); 370 } 371 } 372 373 else if (nodeName.equals(ELEM_SERVLET)) { 375 ServletConfiguration instance = new ServletConfiguration( 376 this, child); 377 this.servletInstances.put(instance.getServletName(), 378 instance); 379 if (instance.getLoadOnStartup() >= 0) 380 startupServlets.add(instance); 381 } 382 383 else if (nodeName.equals(ELEM_FILTER)) { 385 FilterConfiguration instance = new FilterConfiguration( 386 this, this.loader, child); 387 this.filterInstances.put(instance.getFilterName(), instance); 388 } 389 390 else if (nodeName.equals(ELEM_LISTENER)) { 392 String listenerClass = null; 393 for (int m = 0; m < child.getChildNodes().getLength(); m++) { 394 Node listenerElm = child.getChildNodes().item(m); 395 if ((listenerElm.getNodeType() == Node.ELEMENT_NODE) 396 && (listenerElm.getNodeName() 397 .equals(ELEM_LISTENER_CLASS))) 398 listenerClass = getTextFromNode(listenerElm); 399 } 400 if (listenerClass != null) 401 try { 402 Class listener = Class.forName(listenerClass, true, 403 this.loader); 404 Object listenerInstance = listener.newInstance(); 405 addListenerInstance(listenerInstance, contextAttributeListeners, 406 contextListeners, requestAttributeListeners, requestListeners, 407 sessionActivationListeners, sessionAttributeListeners, 408 sessionListeners); 409 Logger.log(Logger.DEBUG, Launcher.RESOURCES, 410 "WebAppConfig.AddListener", listenerClass); 411 } catch (Throwable err) { 412 Logger.log(Logger.WARNING, Launcher.RESOURCES, 413 "WebAppConfig.InvalidListener", 414 listenerClass); 415 } 416 } 417 418 else if (nodeName.equals(ELEM_SERVLET_MAPPING)) { 420 String name = null; 421 List mappings = new ArrayList (); 422 423 NodeList mappingChildren = child.getChildNodes(); 425 for (int k = 0; k < mappingChildren.getLength(); k++) { 426 Node mapChild = mappingChildren.item(k); 427 if (mapChild.getNodeType() != Node.ELEMENT_NODE) 428 continue; 429 String mapNodeName = mapChild.getNodeName(); 430 if (mapNodeName.equals(ELEM_SERVLET_NAME)) { 431 name = getTextFromNode(mapChild); 432 } else if (mapNodeName.equals(ELEM_URL_PATTERN)) { 433 mappings.add(getTextFromNode(mapChild)); 434 } 435 } 436 for (Iterator i = mappings.iterator(); i.hasNext(); ) { 437 processMapping(name, (String ) i.next(), this.exactServletMatchMounts, 438 localFolderPatterns, localExtensionPatterns); 439 } 440 } 441 442 else if (nodeName.equals(ELEM_FILTER_MAPPING)) { 444 String filterName = null; 445 List mappings = new ArrayList (); 446 boolean onRequest = false; 447 boolean onForward = false; 448 boolean onInclude = false; 449 boolean onError = false; 450 451 for (int k = 0; k < child.getChildNodes().getLength(); k++) { 453 Node mapChild = child.getChildNodes().item(k); 454 if (mapChild.getNodeType() != Node.ELEMENT_NODE) 455 continue; 456 String mapNodeName = mapChild.getNodeName(); 457 if (mapNodeName.equals(ELEM_FILTER_NAME)) { 458 filterName = getTextFromNode(mapChild); 459 } else if (mapNodeName.equals(ELEM_SERVLET_NAME)) { 460 mappings.add("srv:" + getTextFromNode(mapChild)); 461 } else if (mapNodeName.equals(ELEM_URL_PATTERN)) { 462 mappings.add("url:" + getTextFromNode(mapChild)); 463 } else if (mapNodeName.equals(ELEM_DISPATCHER)) { 464 String dispatcherValue = getTextFromNode(mapChild); 465 if (dispatcherValue.equals(DISPATCHER_REQUEST)) 466 onRequest = true; 467 else if (dispatcherValue.equals(DISPATCHER_FORWARD)) 468 onForward = true; 469 else if (dispatcherValue.equals(DISPATCHER_INCLUDE)) 470 onInclude = true; 471 else if (dispatcherValue.equals(DISPATCHER_ERROR)) 472 onError = true; 473 } 474 } 475 if (!onRequest && !onInclude && !onForward && !onError) { 476 onRequest = true; 477 } 478 if (mappings.isEmpty()) { 479 throw new WinstoneException(Launcher.RESOURCES.getString( 480 "WebAppConfig.BadFilterMapping", filterName)); 481 } 482 483 for (Iterator i = mappings.iterator(); i.hasNext(); ) { 484 String item = (String ) i.next(); 485 Mapping mapping = null; 486 if (item.startsWith("srv:")) { 487 mapping = Mapping.createFromLink(filterName, item.substring(4)); 488 } else { 489 mapping = Mapping.createFromURL(filterName, item.substring(4)); 490 } 491 if (onRequest) 492 lfpRequest.add(mapping); 493 if (onForward) 494 lfpForward.add(mapping); 495 if (onInclude) 496 lfpInclude.add(mapping); 497 if (onError) 498 lfpError.add(mapping); 499 } 500 } 501 502 else if (nodeName.equals(ELEM_WELCOME_FILES)) { 504 for (int m = 0; m < child.getChildNodes().getLength(); m++) { 505 Node welcomeFile = child.getChildNodes().item(m); 506 if ((welcomeFile.getNodeType() == Node.ELEMENT_NODE) 507 && welcomeFile.getNodeName().equals(ELEM_WELCOME_FILE)) { 508 String welcomeStr = getTextFromNode(welcomeFile); 509 if (!welcomeStr.equals("")) { 510 localWelcomeFiles.add(welcomeStr); 511 } 512 } 513 } 514 } 515 516 else if (nodeName.equals(ELEM_ERROR_PAGE)) { 518 String code = null; 519 String exception = null; 520 String location = null; 521 522 for (int k = 0; k < child.getChildNodes().getLength(); k++) { 524 Node errorChild = child.getChildNodes().item(k); 525 if (errorChild.getNodeType() != Node.ELEMENT_NODE) 526 continue; 527 String errorChildName = errorChild.getNodeName(); 528 if (errorChildName.equals(ELEM_ERROR_CODE)) 529 code = getTextFromNode(errorChild); 530 else if (errorChildName.equals(ELEM_EXCEPTION_TYPE)) 531 exception = getTextFromNode(errorChild); 532 else if (errorChildName.equals(ELEM_ERROR_LOCATION)) 533 location = getTextFromNode(errorChild); 534 } 535 if ((code != null) && (location != null)) 536 this.errorPagesByCode.put(code.trim(), location.trim()); 537 if ((exception != null) && (location != null)) 538 try { 539 Class exceptionClass = Class.forName(exception 540 .trim(), false, this.loader); 541 localErrorPagesByExceptionList.add(exceptionClass); 542 this.errorPagesByException.put(exceptionClass, 543 location.trim()); 544 } catch (ClassNotFoundException err) { 545 Logger.log(Logger.ERROR, Launcher.RESOURCES, 546 "WebAppConfig.ExceptionNotFound", 547 exception); 548 } 549 } 550 551 else if (nodeName.equals(ELEM_MIME_MAPPING)) { 553 String extension = null; 554 String mimeType = null; 555 for (int m = 0; m < child.getChildNodes().getLength(); m++) { 556 Node mimeTypeNode = child.getChildNodes().item(m); 557 if (mimeTypeNode.getNodeType() != Node.ELEMENT_NODE) 558 continue; 559 else if (mimeTypeNode.getNodeName().equals( 560 ELEM_MIME_EXTENSION)) 561 extension = getTextFromNode(mimeTypeNode); 562 else if (mimeTypeNode.getNodeName().equals( 563 ELEM_MIME_TYPE)) 564 mimeType = getTextFromNode(mimeTypeNode); 565 } 566 if ((extension != null) && (mimeType != null)) 567 this.mimeTypes.put(extension.toLowerCase(), mimeType); 568 else 569 Logger.log(Logger.WARNING, Launcher.RESOURCES, 570 "WebAppConfig.InvalidMimeMapping", 571 new String [] { extension, mimeType }); 572 } 573 574 else if (nodeName.equals(ELEM_CONTEXT_PARAM)) { 576 String name = null; 577 String value = null; 578 for (int m = 0; m < child.getChildNodes().getLength(); m++) { 579 Node contextParamNode = child.getChildNodes().item(m); 580 if (contextParamNode.getNodeType() != Node.ELEMENT_NODE) 581 continue; 582 else if (contextParamNode.getNodeName().equals( 583 ELEM_PARAM_NAME)) 584 name = getTextFromNode(contextParamNode); 585 else if (contextParamNode.getNodeName().equals( 586 ELEM_PARAM_VALUE)) 587 value = getTextFromNode(contextParamNode); 588 } 589 if ((name != null) && (value != null)) 590 this.initParameters.put(name, value); 591 else 592 Logger.log(Logger.WARNING, Launcher.RESOURCES, 593 "WebAppConfig.InvalidInitParam", new String [] { 594 name, value }); 595 } 596 597 else if (nodeName.equals(ELEM_LOCALE_ENC_MAP_LIST)) { 599 for (int m = 0; m < child.getChildNodes().getLength(); m++) { 600 Node mappingNode = child.getChildNodes().item(m); 601 if (mappingNode.getNodeType() != Node.ELEMENT_NODE) 602 continue; 603 else if (mappingNode.getNodeName().equals(ELEM_LOCALE_ENC_MAPPING)) { 604 String localeName = ""; 605 String encoding = ""; 606 for (int l = 0; l < mappingNode.getChildNodes().getLength(); l++) { 607 Node mappingChildNode = mappingNode.getChildNodes().item(l); 608 if (mappingChildNode.getNodeType() != Node.ELEMENT_NODE) 609 continue; 610 else if (mappingChildNode.getNodeName().equals(ELEM_LOCALE)) 611 localeName = getTextFromNode(mappingChildNode); 612 else if (mappingChildNode.getNodeName().equals(ELEM_ENCODING)) 613 encoding = getTextFromNode(mappingChildNode); 614 } 615 if (!encoding.equals("") && !localeName.equals("")) 616 this.localeEncodingMap.put(localeName, encoding); 617 } 618 } 619 } 620 621 else if (nodeName.equals(ELEM_JSP_CONFIG)) { 623 for (int m = 0; m < child.getChildNodes().getLength(); m++) { 624 Node propertyGroupNode = child.getChildNodes().item(m); 625 if ((propertyGroupNode.getNodeType() == Node.ELEMENT_NODE) 626 && propertyGroupNode.getNodeName().equals(ELEM_JSP_PROPERTY_GROUP)) { 627 for (int l = 0; l < propertyGroupNode.getChildNodes().getLength(); l++) { 628 Node urlPatternNode = propertyGroupNode.getChildNodes().item(l); 629 if ((urlPatternNode.getNodeType() == Node.ELEMENT_NODE) 630 && urlPatternNode.getNodeName().equals(ELEM_URL_PATTERN)) { 631 String jm = getTextFromNode(urlPatternNode); 632 if (!jm.equals("")) { 633 jspMappings.add(jm); 634 } 635 } 636 } 637 } 638 } 639 } 640 } 641 } 642 643 if (!distributable && (cluster != null)) { 645 Logger.log(Logger.INFO, Launcher.RESOURCES, 646 "WebAppConfig.ClusterOffNotDistributable", this.contextName); 647 } else { 648 this.cluster = cluster; 649 } 650 651 652 if (!constraintNodes.isEmpty() && (loginConfigNode != null)) { 654 String authMethod = null; 655 for (int n = 0; n < loginConfigNode.getChildNodes().getLength(); n++) { 656 if (loginConfigNode.getChildNodes().item(n).getNodeName().equals("auth-method")) { 657 authMethod = getTextFromNode(loginConfigNode.getChildNodes().item(n)); 658 } 659 } 660 if (authMethod == null) { 662 authMethod = "BASIC"; 663 } else { 664 authMethod = WinstoneResourceBundle.globalReplace(authMethod, "-", ""); 665 } 666 String realmClassName = stringArg(startupArgs, "realmClassName", 667 DEFAULT_REALM_CLASS).trim(); 668 String authClassName = "winstone.auth." 669 + authMethod.substring(0, 1).toUpperCase() 670 + authMethod.substring(1).toLowerCase() 671 + "AuthenticationHandler"; 672 try { 673 Class realmClass = Class.forName(realmClassName); 675 Constructor realmConstr = realmClass 676 .getConstructor(new Class [] {Set .class, Map .class }); 677 this.authenticationRealm = (AuthenticationRealm) realmConstr 678 .newInstance(new Object [] { rolesAllowed, startupArgs }); 679 680 Class authClass = Class.forName(authClassName); 682 Constructor authConstr = authClass 683 .getConstructor(new Class [] { Node .class, List .class, 684 Set .class, AuthenticationRealm.class }); 685 this.authenticationHandler = (AuthenticationHandler) authConstr 686 .newInstance(new Object [] { loginConfigNode, 687 constraintNodes, rolesAllowed, 688 authenticationRealm }); 689 } catch (ClassNotFoundException err) { 690 Logger.log(Logger.DEBUG, Launcher.RESOURCES, 691 "WebAppConfig.AuthDisabled", authMethod); 692 } catch (Throwable err) { 693 Logger.log(Logger.ERROR, Launcher.RESOURCES, 694 "WebAppConfig.AuthError", new String [] { authClassName, 695 realmClassName }, err); 696 } 697 } else if (!stringArg(startupArgs, "realmClassName", "").trim().equals("")) { 698 Logger.log(Logger.DEBUG, Launcher.RESOURCES, "WebAppConfig.NoWebXMLSecurityDefs"); 699 } 700 701 String jndiMgrClassName = stringArg(startupArgs, "webappJndiClassName", 703 DEFAULT_JNDI_MGR_CLASS).trim(); 704 if (useJNDI) { 705 try { 706 Class jndiMgrClass = Class.forName(jndiMgrClassName, true, this.loader); 708 Constructor jndiMgrConstr = jndiMgrClass.getConstructor(new Class [] { 709 Map .class, List .class, ClassLoader .class }); 710 this.jndiManager = (JNDIManager) jndiMgrConstr.newInstance(new Object [] { 711 null, envEntryNodes, this.loader }); 712 if (this.jndiManager != null) 713 this.jndiManager.setup(); 714 } catch (ClassNotFoundException err) { 715 Logger.log(Logger.DEBUG, Launcher.RESOURCES, 716 "WebAppConfig.JNDIDisabled"); 717 } catch (Throwable err) { 718 Logger.log(Logger.ERROR, Launcher.RESOURCES, 719 "WebAppConfig.JNDIError", jndiMgrClassName, err); 720 } 721 } 722 723 String loggerClassName = stringArg(startupArgs, "accessLoggerClassName", "").trim(); 724 if (!loggerClassName.equals("")) { 725 try { 726 Class loggerClass = Class.forName(loggerClassName, true, this.loader); 728 Constructor loggerConstr = loggerClass.getConstructor(new Class [] { 729 WebAppConfiguration.class, Map .class }); 730 this.accessLogger = (AccessLogger) loggerConstr.newInstance(new Object [] { 731 this, startupArgs}); 732 } catch (Throwable err) { 733 Logger.log(Logger.ERROR, Launcher.RESOURCES, 734 "WebAppConfig.LoggerError", loggerClassName, err); 735 } 736 } else { 737 Logger.log(Logger.DEBUG, Launcher.RESOURCES, "WebAppConfig.LoggerDisabled"); 738 739 } 740 741 if (localWelcomeFiles.isEmpty()) { 743 if (useJasper) { 744 localWelcomeFiles.add("index.jsp"); 745 } 746 localWelcomeFiles.add("index.html"); 747 } 748 749 this.filterPatternsRequest = (Mapping[]) lfpRequest.toArray(new Mapping[0]); 752 this.filterPatternsForward = (Mapping[]) lfpForward.toArray(new Mapping[0]); 753 this.filterPatternsInclude = (Mapping[]) lfpInclude.toArray(new Mapping[0]); 754 this.filterPatternsError = (Mapping[]) lfpError.toArray(new Mapping[0]); 755 756 if (this.filterPatternsRequest.length > 0) 757 Arrays.sort(this.filterPatternsRequest, 758 this.filterPatternsRequest[0]); 759 if (this.filterPatternsForward.length > 0) 760 Arrays.sort(this.filterPatternsForward, 761 this.filterPatternsForward[0]); 762 if (this.filterPatternsInclude.length > 0) 763 Arrays.sort(this.filterPatternsInclude, 764 this.filterPatternsInclude[0]); 765 if (this.filterPatternsError.length > 0) 766 Arrays.sort(this.filterPatternsError, this.filterPatternsError[0]); 767 768 this.welcomeFiles = (String []) localWelcomeFiles.toArray(new String [0]); 769 this.errorPagesByExceptionKeysSorted = (Class []) localErrorPagesByExceptionList 770 .toArray(new Class [0]); 771 Arrays.sort(this.errorPagesByExceptionKeysSorted, this); 772 773 this.contextAttributeListeners = (ServletContextAttributeListener []) contextAttributeListeners 775 .toArray(new ServletContextAttributeListener [0]); 776 this.contextListeners = (ServletContextListener []) contextListeners 777 .toArray(new ServletContextListener [0]); 778 this.requestListeners = (ServletRequestListener []) requestListeners 779 .toArray(new ServletRequestListener [0]); 780 this.requestAttributeListeners = (ServletRequestAttributeListener []) requestAttributeListeners 781 .toArray(new ServletRequestAttributeListener [0]); 782 this.sessionActivationListeners = (HttpSessionActivationListener []) sessionActivationListeners 783 .toArray(new HttpSessionActivationListener [0]); 784 this.sessionAttributeListeners = (HttpSessionAttributeListener []) sessionAttributeListeners 785 .toArray(new HttpSessionAttributeListener [0]); 786 this.sessionListeners = (HttpSessionListener []) sessionListeners 787 .toArray(new HttpSessionListener [0]); 788 789 if (this.defaultServletName == null) 791 this.defaultServletName = DEFAULT_SERVLET_NAME; 792 if (this.errorServletName == null) 793 this.errorServletName = ERROR_SERVLET_NAME; 794 795 if (this.servletInstances.get(this.defaultServletName) == null) { 797 boolean useDirLists = booleanArg(startupArgs, "directoryListings", true); 798 799 Map staticParams = new Hashtable (); 800 staticParams.put("webRoot", webRoot); 801 staticParams.put("prefix", this.prefix); 802 staticParams.put("directoryList", "" + useDirLists); 803 ServletConfiguration defaultServlet = new ServletConfiguration( 804 this, this.defaultServletName, DEFAULT_SERVLET_CLASS, 805 staticParams, 0); 806 this.servletInstances.put(this.defaultServletName, defaultServlet); 809 startupServlets.add(defaultServlet); 810 } 811 812 if (this.servletInstances.get(this.errorServletName) == null) { 814 ServletConfiguration errorServlet = new ServletConfiguration( 815 this, this.errorServletName, ERROR_SERVLET_CLASS, 816 new HashMap (), 0); 817 this.servletInstances.put(this.errorServletName, errorServlet); 820 startupServlets.add(errorServlet); 821 } 822 823 if (useJasper) { 825 setAttribute("org.apache.catalina.classloader", this.loader); 826 try { 829 StringBuffer cp = new StringBuffer (); 830 for (Iterator i = localLoaderClassPathFiles.iterator(); i.hasNext(); ) { 831 cp.append(((File ) i.next()).getCanonicalPath()).append( 832 File.pathSeparatorChar); 833 } 834 for (int n = 0; n < parentClassPaths.length; n++) { 835 cp.append(parentClassPaths[n].getCanonicalPath()).append( 836 File.pathSeparatorChar); 837 } 838 setAttribute("org.apache.catalina.jsp_classpath", 839 (cp.length() > 0 ? cp.substring(0, cp.length() - 1) : "")); 840 } catch (IOException err) { 841 Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebAppConfig.ErrorSettingJSPPaths", err); 842 } 843 844 Map jspParams = new HashMap (); 845 addJspServletParams(jspParams); 846 ServletConfiguration sc = new ServletConfiguration(this, 847 JSP_SERVLET_NAME, JSP_SERVLET_CLASS, jspParams, 3); 848 this.servletInstances.put(JSP_SERVLET_NAME, sc); 849 startupServlets.add(sc); 850 for (Iterator mapIt = jspMappings.iterator(); mapIt.hasNext(); ) { 851 processMapping(JSP_SERVLET_NAME, (String ) mapIt.next(), 852 this.exactServletMatchMounts, localFolderPatterns, 853 localExtensionPatterns); 854 } 855 } 856 857 if (useInvoker) { 859 String invokerPrefix = stringArg(startupArgs, "invokerPrefix", 861 DEFAULT_INVOKER_PREFIX); 862 Map invokerParams = new HashMap (); 863 invokerParams.put("prefix", this.prefix); 864 invokerParams.put("invokerPrefix", invokerPrefix); 865 ServletConfiguration sc = new ServletConfiguration(this, 866 INVOKER_SERVLET_NAME, INVOKER_SERVLET_CLASS, 867 invokerParams, 3); 868 this.servletInstances.put(INVOKER_SERVLET_NAME, sc); 869 processMapping(INVOKER_SERVLET_NAME, invokerPrefix + Mapping.STAR, 870 this.exactServletMatchMounts, localFolderPatterns, 871 localExtensionPatterns); 872 } 873 874 localFolderPatterns.addAll(localExtensionPatterns); 876 this.patternMatches = (Mapping[]) localFolderPatterns.toArray(new Mapping[0]); 877 if (this.patternMatches.length > 0) 878 Arrays.sort(this.patternMatches, this.patternMatches[0]); 879 880 try { 882 for (int n = 0; n < this.contextListeners.length; n++) { 883 ClassLoader cl = Thread.currentThread().getContextClassLoader(); 884 Thread.currentThread().setContextClassLoader(this.loader); 885 this.contextListeners[n].contextInitialized(new ServletContextEvent (this)); 886 Thread.currentThread().setContextClassLoader(cl); 887 } 888 } catch (Throwable err) { 889 Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebAppConfig.ContextStartupError", this.contextName, err); 890 this.contextStartupError = err; 891 } 892 893 if (this.contextStartupError == null) { 894 if (this.useSavedSessions) { 896 WinstoneSession.loadSessions(this); 897 } 898 899 for (Iterator i = this.filterInstances.values().iterator(); i.hasNext();) { 901 FilterConfiguration config = (FilterConfiguration) i.next(); 902 try { 903 config.getFilter(); 904 } catch (ServletException err) { 905 Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebAppConfig.FilterStartupError", 906 config.getFilterName(), err); 907 } 908 } 909 910 Object autoStarters[] = startupServlets.toArray(); 912 Arrays.sort(autoStarters); 913 for (int n = 0; n < autoStarters.length; n++) { 914 ((ServletConfiguration) autoStarters[n]).ensureInitialization(); 915 } 916 } 917 } 918 919 923 private ClassLoader buildWebAppClassLoader(Map startupArgs, ClassLoader parentClassLoader, 924 String webRoot, List classPathFileList) { 925 List urlList = new ArrayList (); 926 927 try { 928 File webInfFolder = new File (webRoot, WEB_INF); 930 931 File classesFolder = new File (webInfFolder, CLASSES); 933 if (classesFolder.exists()) { 934 Logger.log(Logger.DEBUG, Launcher.RESOURCES, 935 "WebAppConfig.WebAppClasses"); 936 urlList.add(new URL ("file", "", classesFolder.getCanonicalPath() + "/")); 937 classPathFileList.add(classesFolder); 938 } else { 939 Logger.log(Logger.WARNING, Launcher.RESOURCES, 940 "WebAppConfig.NoWebAppClasses", 941 classesFolder.toString()); 942 } 943 944 File libFolder = new File (webInfFolder, LIB); 946 if (libFolder.exists()) { 947 File jars[] = libFolder.listFiles(); 948 for (int n = 0; n < jars.length; n++) { 949 String jarName = jars[n].getCanonicalPath().toLowerCase(); 950 if (jarName.endsWith(".jar") || jarName.endsWith(".zip")) { 951 Logger.log(Logger.DEBUG, Launcher.RESOURCES, 952 "WebAppConfig.WebAppLib", jars[n].getName()); 953 urlList.add(jars[n].toURL()); 954 classPathFileList.add(jars[n]); 955 } 956 } 957 } else { 958 Logger.log(Logger.WARNING, Launcher.RESOURCES, 959 "WebAppConfig.NoWebAppLib", libFolder 960 .toString()); 961 } 962 } catch (MalformedURLException err) { 963 throw new WinstoneException(Launcher.RESOURCES 964 .getString("WebAppConfig.BadURL"), err); 965 } catch (IOException err) { 966 throw new WinstoneException(Launcher.RESOURCES 967 .getString("WebAppConfig.IOException"), err); 968 } 969 970 URL jarURLs[] = (URL []) urlList.toArray(new URL [0]); 971 972 boolean useReloading = booleanArg(startupArgs, "useServletReloading", false); 973 String preferredClassLoader = stringArg(startupArgs, "preferredClassLoader", ""); 974 if (preferredClassLoader.equals("") && useReloading) { 975 preferredClassLoader = RELOADING_CL_CLASS; 976 } 977 978 ClassLoader outputCL = null; 980 if (!preferredClassLoader.equals("")) { 981 try { 982 Class preferredCL = Class.forName(preferredClassLoader, true, parentClassLoader); 983 Constructor reloadConstr = preferredCL.getConstructor(new Class [] { 984 (new URL [0]).getClass(), ClassLoader .class}); 985 outputCL = (ClassLoader ) reloadConstr.newInstance(new Object [] { 986 jarURLs, parentClassLoader}); 987 } catch (Throwable err) { 988 Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebAppConfig.CLError", err); 989 } 990 } 991 992 if (outputCL == null) { 993 outputCL = new URLClassLoader (jarURLs, parentClassLoader); 994 } 995 996 Logger.log(Logger.MAX, Launcher.RESOURCES, "WebAppConfig.WebInfClassLoader", outputCL.toString()); 997 return outputCL; 998 } 999 1000 private void addListenerInstance(Object listenerInstance, List contextAttributeListeners, 1001 List contextListeners, List requestAttributeListeners, List requestListeners, 1002 List sessionActivationListeners, List sessionAttributeListeners, 1003 List sessionListeners) { 1004 if (listenerInstance instanceof ServletContextAttributeListener ) 1005 contextAttributeListeners.add(listenerInstance); 1006 if (listenerInstance instanceof ServletContextListener ) 1007 contextListeners.add(listenerInstance); 1008 if (listenerInstance instanceof ServletRequestAttributeListener ) 1009 requestAttributeListeners.add(listenerInstance); 1010 if (listenerInstance instanceof ServletRequestListener ) 1011 requestListeners.add(listenerInstance); 1012 if (listenerInstance instanceof HttpSessionActivationListener ) 1013 sessionActivationListeners.add(listenerInstance); 1014 if (listenerInstance instanceof HttpSessionAttributeListener ) 1015 sessionAttributeListeners.add(listenerInstance); 1016 if (listenerInstance instanceof HttpSessionListener ) 1017 sessionListeners.add(listenerInstance); 1018 } 1019 1020 public String getContextPath() { 1021 return this.prefix; 1022 } 1023 1024 public String getWebroot() { 1025 return this.webRoot; 1026 } 1027 1028 public ClassLoader getLoader() { 1029 return this.loader; 1030 } 1031 1032 public AccessLogger getAccessLogger() { 1033 return this.accessLogger; 1034 } 1035 1036 public Map getFilters() { 1037 return this.filterInstances; 1038 } 1039 1040 public String getContextName() { 1041 return this.contextName; 1042 } 1043 1044 public Class [] getErrorPageExceptions() { 1045 return this.errorPagesByExceptionKeysSorted; 1046 } 1047 1048 public Map getErrorPagesByException() { 1049 return this.errorPagesByException; 1050 } 1051 1052 public Map getErrorPagesByCode() { 1053 return this.errorPagesByCode; 1054 } 1055 1056 public Map getLocaleEncodingMap() { 1057 return this.localeEncodingMap; 1058 } 1059 1060 public String [] getWelcomeFiles() { 1061 return this.welcomeFiles; 1062 } 1063 1064 public boolean isDistributable() { 1065 return (this.cluster != null); 1066 } 1067 1068 public Map getFilterMatchCache() { 1069 return this.filterMatchCache; 1070 } 1071 1072 public String getOwnerHostname() { 1073 return this.ownerHostConfig.getHostname(); 1074 } 1075 1076 public ServletRequestListener [] getRequestListeners() { 1077 return this.requestListeners; 1078 } 1079 1080 public ServletRequestAttributeListener [] getRequestAttributeListeners() { 1081 return this.requestAttributeListeners; 1082 } 1083 1084 public static void addJspServletParams(Map jspParams) { 1085 jspParams.put("logVerbosityLevel", JSP_SERVLET_LOG_LEVEL); 1086 jspParams.put("fork", "false"); 1087 } 1088 1089 public int compare(Object one, Object two) { 1090 if (!(one instanceof Class ) || !(two instanceof Class )) 1091 throw new IllegalArgumentException ( 1092 "This comparator is only for sorting classes"); 1093 Class classOne = (Class ) one; 1094 Class classTwo = (Class ) two; 1095 if (classOne.isAssignableFrom(classTwo)) 1096 return 1; 1097 else if (classTwo.isAssignableFrom(classOne)) 1098 return -1; 1099 else 1100 return 0; 1101 } 1102 1103 public String getServletURIFromRequestURI(String requestURI) { 1104 if (prefix.equals("")) { 1105 return requestURI; 1106 } else if (requestURI.startsWith(prefix)) { 1107 return requestURI.substring(prefix.length()); 1108 } else { 1109 throw new WinstoneException("This shouldn't happen, " + 1110 "since we aborted earlier if we didn't match"); 1111 } 1112 } 1113 1114 1117 public void destroy() { 1118 synchronized (this.filterMatchCache) { 1119 this.filterMatchCache.clear(); 1120 } 1121 1122 Collection filterInstances = new ArrayList (this.filterInstances.values()); 1123 for (Iterator i = filterInstances.iterator(); i.hasNext();) { 1124 try { 1125 ((FilterConfiguration) i.next()).destroy(); 1126 } catch (Throwable err) { 1127 Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebAppConfig.ShutdownError", err); 1128 } 1129 } 1130 this.filterInstances.clear(); 1131 1132 Collection servletInstances = new ArrayList (this.servletInstances.values()); 1133 for (Iterator i = servletInstances.iterator(); i.hasNext();) { 1134 try { 1135 ((ServletConfiguration) i.next()).destroy(); 1136 } catch (Throwable err) { 1137 Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebAppConfig.ShutdownError", err); 1138 } 1139 } 1140 this.servletInstances.clear(); 1141 1142 Collection sessions = new ArrayList (this.sessions.values()); 1144 for (Iterator i = sessions.iterator(); i.hasNext();) { 1145 WinstoneSession session = (WinstoneSession) i.next(); 1146 try { 1147 if (this.useSavedSessions) { 1148 session.saveToTemp(); 1149 } else { 1150 session.invalidate(); 1151 } 1152 } catch (Throwable err) { 1153 Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebAppConfig.ShutdownError", err); 1154 } 1155 } 1156 this.sessions.clear(); 1157 1158 for (int n = this.contextListeners.length - 1; n >= 0; n--) { 1160 try { 1161 ClassLoader cl = Thread.currentThread().getContextClassLoader(); 1162 Thread.currentThread().setContextClassLoader(this.loader); 1163 this.contextListeners[n].contextDestroyed(new ServletContextEvent (this)); 1164 this.contextListeners[n] = null; 1165 Thread.currentThread().setContextClassLoader(cl); 1166 } catch (Throwable err) { 1167 Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebAppConfig.ShutdownError", err); 1168 } 1169 } 1170 this.contextListeners = null; 1171 1172 if (this.loader != null) { 1174 this.loader = null; 1182 } 1183 1184 if (this.jndiManager != null) { 1186 this.jndiManager.tearDown(); 1187 this.jndiManager = null; 1188 } 1189 1190 if (this.accessLogger != null) { 1192 this.accessLogger.destroy(); 1193 this.accessLogger = null; 1194 } 1195 } 1196 1197 1203 public void resetClassLoader() throws IOException { 1204 this.ownerHostConfig.reloadWebApp(getContextPath()); 1205 } 1206 1207 1210 private void processMapping(String name, String pattern, Map exactPatterns, 1211 List folderPatterns, List extensionPatterns) { 1212 1213 Mapping urlPattern = null; 1214 try { 1215 urlPattern = Mapping.createFromURL(name, pattern); 1216 } catch (WinstoneException err) { 1217 Logger.log(Logger.WARNING, Launcher.RESOURCES, "WebAppConfig.ErrorMapURL", 1218 err.getMessage()); 1219 return; 1220 } 1221 1222 if (urlPattern.getPatternType() == Mapping.EXACT_PATTERN) { 1224 exactPatterns.put(urlPattern.getUrlPattern(), name); 1225 } else if (urlPattern.getPatternType() == Mapping.FOLDER_PATTERN) { 1226 folderPatterns.add(urlPattern); 1227 } else if (urlPattern.getPatternType() == Mapping.EXTENSION_PATTERN) { 1228 extensionPatterns.add(urlPattern); 1229 } else if (urlPattern.getPatternType() == Mapping.DEFAULT_SERVLET) { 1230 this.defaultServletName = name; 1231 } else { 1232 Logger.log(Logger.WARNING, Launcher.RESOURCES, "WebAppConfig.InvalidMount", 1233 new String [] { name, pattern }); 1234 } 1235 } 1236 1237 1241 private ServletConfiguration urlMatch(String path, 1242 StringBuffer servletPath, StringBuffer pathInfo) { 1243 Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WebAppConfig.URLMatch", path); 1244 1245 String exact = (String ) this.exactServletMatchMounts.get(path); 1247 if (exact != null) { 1248 if (this.servletInstances.get(exact) != null) { 1249 servletPath.append(path); 1250 return (ServletConfiguration) this.servletInstances.get(exact); 1252 } 1253 } 1254 1255 for (int n = 0; n < this.patternMatches.length; n++) { 1257 Mapping urlPattern = this.patternMatches[n]; 1258 if (urlPattern.match(path, servletPath, pathInfo) && 1259 (this.servletInstances.get(urlPattern.getMappedTo()) != null)) { 1260 return (ServletConfiguration) this.servletInstances 1261 .get(urlPattern.getMappedTo()); 1262 } 1263 } 1264 1265 if (this.servletInstances.get(this.defaultServletName) == null) 1268 throw new WinstoneException(Launcher.RESOURCES.getString( 1269 "WebAppConfig.MatchedNonExistServlet", 1270 this.defaultServletName)); 1271 servletPath.append(path); 1273 return (ServletConfiguration) this.servletInstances.get(this.defaultServletName); 1274 } 1275 1276 1282 public WinstoneSession makeNewSession(String sessionId) { 1283 WinstoneSession ws = new WinstoneSession(sessionId); 1284 ws.setWebAppConfiguration(this); 1285 setSessionListeners(ws); 1286 if ((this.sessionTimeout != null) && (this.sessionTimeout.intValue() > 0)) { 1287 ws.setMaxInactiveInterval(this.sessionTimeout.intValue() * 60); 1288 } else { 1289 ws.setMaxInactiveInterval(-1); 1290 } 1291 ws.setLastAccessedDate(System.currentTimeMillis()); 1292 ws.sendCreatedNotifies(); 1293 this.sessions.put(sessionId, ws); 1294 return ws; 1295 } 1296 1297 1304 public WinstoneSession getSessionById(String sessionId, boolean localOnly) { 1305 if (sessionId == null) { 1306 return null; 1307 } 1308 WinstoneSession session = (WinstoneSession) this.sessions.get(sessionId); 1309 if (session != null) { 1310 return session; 1311 } 1312 1313 if ((this.cluster != null) && !localOnly) { 1315 session = this.cluster.askClusterForSession(sessionId, this); 1316 if (session != null) { 1317 this.sessions.put(sessionId, session); 1318 } 1319 return session; 1320 } else { 1321 return null; 1322 } 1323 } 1324 1325 1328 void removeSessionById(String sessionId) { 1329 this.sessions.remove(sessionId); 1330 } 1331 void addSession(String sessionId, WinstoneSession session) { 1332 this.sessions.put(sessionId, session); 1333 } 1334 1335 public void invalidateExpiredSessions() { 1336 Set allSessions = new HashSet (this.sessions.values()); 1337 int expiredCount = 0; 1338 for (Iterator i = allSessions.iterator(); i.hasNext(); ) { 1339 WinstoneSession session = (WinstoneSession) i.next(); 1340 if (!session.isNew() && session.isUnusedByRequests() && session.isExpired()) { 1341 session.invalidate(); 1342 expiredCount++; 1343 } 1344 } 1345 if (expiredCount > 0) { 1346 Logger.log(Logger.DEBUG, Launcher.RESOURCES, 1347 "WebAppConfig.InvalidatedSessions", expiredCount + ""); 1348 } 1349 } 1350 1351 public void setSessionListeners(WinstoneSession session) { 1352 session.setSessionActivationListeners(this.sessionActivationListeners); 1353 session.setSessionAttributeListeners(this.sessionAttributeListeners); 1354 session.setSessionListeners(this.sessionListeners); 1355 } 1356 1357 public void removeServletConfigurationAndMappings(ServletConfiguration config) { 1358 this.servletInstances.remove(config.getServletName()); 1359 } 1362 1363 1369 1370 public Object getAttribute(String name) { 1372 return this.attributes.get(name); 1373 } 1374 1375 public Enumeration getAttributeNames() { 1376 return Collections.enumeration(this.attributes.keySet()); 1377 } 1378 1379 public void removeAttribute(String name) { 1380 Object me = this.attributes.get(name); 1381 this.attributes.remove(name); 1382 if (me != null) 1383 for (int n = 0; n < this.contextAttributeListeners.length; n++) { 1384 ClassLoader cl = Thread.currentThread().getContextClassLoader(); 1385 Thread.currentThread().setContextClassLoader(getLoader()); 1386 this.contextAttributeListeners[n].attributeRemoved( 1387 new ServletContextAttributeEvent (this, name, me)); 1388 Thread.currentThread().setContextClassLoader(cl); 1389 } 1390 } 1391 1392 public void setAttribute(String name, Object object) { 1393 if (object == null) { 1394 removeAttribute(name); 1395 } else { 1396 Object me = this.attributes.get(name); 1397 this.attributes.put(name, object); 1398 if (me != null) { 1399 for (int n = 0; n < this.contextAttributeListeners.length; n++) { 1400 ClassLoader cl = Thread.currentThread().getContextClassLoader(); 1401 Thread.currentThread().setContextClassLoader(getLoader()); 1402 this.contextAttributeListeners[n].attributeReplaced( 1403 new ServletContextAttributeEvent (this, name, me)); 1404 Thread.currentThread().setContextClassLoader(cl); 1405 } 1406 } else { 1407 for (int n = 0; n < this.contextAttributeListeners.length; n++) { 1408 ClassLoader cl = Thread.currentThread().getContextClassLoader(); 1409 Thread.currentThread().setContextClassLoader(getLoader()); 1410 this.contextAttributeListeners[n].attributeAdded( 1411 new ServletContextAttributeEvent (this, name, object)); 1412 Thread.currentThread().setContextClassLoader(cl); 1413 } 1414 } 1415 } 1416 } 1417 1418 public String getInitParameter(String name) { 1420 return (String ) this.initParameters.get(name); 1421 } 1422 1423 public Enumeration getInitParameterNames() { 1424 return Collections.enumeration(this.initParameters.keySet()); 1425 } 1426 1427 public String getServerInfo() { 1429 return Launcher.RESOURCES.getString("ServerVersion"); 1430 } 1431 1432 public int getMajorVersion() { 1433 return 2; 1434 } 1435 1436 public int getMinorVersion() { 1437 return 5; 1438 } 1439 1440 public javax.servlet.ServletContext getContext(String uri) { 1442 return this.ownerHostConfig.getWebAppByURI(uri); 1443 } 1444 1445 public String getServletContextName() { 1446 return this.displayName; 1447 } 1448 1449 1452 public String getMimeType(String fileName) { 1453 int dotPos = fileName.lastIndexOf('.'); 1454 if ((dotPos != -1) && (dotPos != fileName.length() - 1)) { 1455 String extension = fileName.substring(dotPos + 1).toLowerCase(); 1456 String mimeType = (String ) this.mimeTypes.get(extension); 1457 return mimeType; 1458 } else 1459 return null; 1460 } 1461 1462 public void log(String message) { 1464 Logger.logDirectMessage(Logger.INFO, this.contextName, message, null); 1465 } 1466 1467 public void log(String message, Throwable throwable) { 1468 Logger.logDirectMessage(Logger.ERROR, this.contextName, message, throwable); 1469 } 1470 1471 1475 public javax.servlet.RequestDispatcher getNamedDispatcher(String name) { 1476 ServletConfiguration servlet = (ServletConfiguration) this.servletInstances.get(name); 1477 if (servlet != null) { 1478 RequestDispatcher rd = new RequestDispatcher(this, servlet); 1479 if (rd != null) { 1480 rd.setForNamedDispatcher(this.filterPatternsForward, this.filterPatternsInclude); 1481 return rd; 1482 } 1483 } 1484 return null; 1485 } 1486 1487 1491 public javax.servlet.RequestDispatcher getRequestDispatcher( 1492 String uriInsideWebapp) { 1493 if (uriInsideWebapp == null) { 1494 return null; 1495 } else if (!uriInsideWebapp.startsWith("/")) { 1496 return null; 1497 } 1498 1499 String queryString = ""; 1501 int questionPos = uriInsideWebapp.indexOf('?'); 1502 if (questionPos != -1) { 1503 if (questionPos != uriInsideWebapp.length() - 1) { 1504 queryString = uriInsideWebapp.substring(questionPos + 1); 1505 } 1506 uriInsideWebapp = uriInsideWebapp.substring(0, questionPos); 1507 } 1508 1509 StringBuffer servletPath = new StringBuffer (); 1511 StringBuffer pathInfo = new StringBuffer (); 1512 ServletConfiguration servlet = urlMatch(uriInsideWebapp, servletPath, pathInfo); 1513 if (servlet != null) { 1514 RequestDispatcher rd = new RequestDispatcher(this, servlet); 1515 if (rd != null) { 1516 rd.setForURLDispatcher(servletPath.toString(), pathInfo.toString() 1517 .equals("") ? null : pathInfo.toString(), queryString, 1518 uriInsideWebapp, this.filterPatternsForward, 1519 this.filterPatternsInclude); 1520 return rd; 1521 } 1522 } 1523 return null; 1524 } 1525 1526 1535 public RequestDispatcher getInitialDispatcher(String uriInsideWebapp, 1536 WinstoneRequest request, WinstoneResponse response) 1537 throws IOException { 1538 if (!uriInsideWebapp.equals("") && !uriInsideWebapp.startsWith("/")) { 1539 return this.getErrorDispatcherByCode( 1540 HttpServletResponse.SC_BAD_REQUEST, 1541 Launcher.RESOURCES.getString("WebAppConfig.InvalidURI", uriInsideWebapp), 1542 null); 1543 } else if (this.contextStartupError != null) { 1544 StringWriter sw = new StringWriter (); 1545 PrintWriter pw = new PrintWriter (sw, true); 1546 this.contextStartupError.printStackTrace(pw); 1547 return this.getErrorDispatcherByCode( 1548 HttpServletResponse.SC_INTERNAL_SERVER_ERROR, 1549 Launcher.RESOURCES.getString("WebAppConfig.ErrorDuringStartup", sw.toString()), 1550 this.contextStartupError); 1551 } 1552 1553 String queryString = ""; 1555 int questionPos = uriInsideWebapp.indexOf('?'); 1556 if (questionPos != -1) { 1557 if (questionPos != uriInsideWebapp.length() - 1) 1558 queryString = uriInsideWebapp.substring(questionPos + 1); 1559 uriInsideWebapp = uriInsideWebapp.substring(0, questionPos); 1560 } 1561 1562 StringBuffer servletPath = new StringBuffer (); 1564 StringBuffer pathInfo = new StringBuffer (); 1565 ServletConfiguration servlet = urlMatch(uriInsideWebapp, servletPath, pathInfo); 1566 if (servlet != null) { 1567 if (servlet.getServletName().equals(this.defaultServletName)) { 1569 String directoryPath = servletPath.toString(); 1571 if (directoryPath.endsWith("/")) { 1572 directoryPath = directoryPath.substring(0, directoryPath.length() - 1); 1573 } 1574 if (directoryPath.startsWith("/")) { 1575 directoryPath = directoryPath.substring(1); 1576 } 1577 1578 File res = new File (webRoot, directoryPath); 1579 if (res.exists() && res.isDirectory() && 1580 (request.getMethod().equals("GET") || request.getMethod().equals("HEAD"))) { 1581 if (!servletPath.toString().endsWith("/")) { 1583 Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, 1584 "WebAppConfig.FoundNonSlashDirectory", servletPath.toString()); 1585 response.sendRedirect(this.prefix 1586 + servletPath.toString() 1587 + pathInfo.toString() 1588 + "/" 1589 + (queryString.equals("") ? "" : "?" + queryString)); 1590 return null; 1591 } 1592 1593 Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, 1595 "WebAppConfig.CheckWelcomeFile", servletPath.toString() 1596 + pathInfo.toString()); 1597 String welcomeFile = matchWelcomeFiles(servletPath.toString() 1598 + pathInfo.toString(), request, queryString); 1599 if (welcomeFile != null) { 1600 response.sendRedirect(this.prefix + welcomeFile); 1601 return null; 1606 } 1607 } 1608 } 1609 1610 RequestDispatcher rd = new RequestDispatcher(this, servlet); 1611 rd.setForInitialDispatcher(servletPath.toString(), 1612 pathInfo.toString().equals("") ? null : pathInfo.toString(), queryString, 1613 uriInsideWebapp, this.filterPatternsRequest, this.authenticationHandler); 1614 return rd; 1615 } 1616 1617 return this.getErrorDispatcherByCode(HttpServletResponse.SC_NOT_FOUND, 1619 Launcher.RESOURCES.getString("StaticResourceServlet.PathNotFound", 1620 uriInsideWebapp), null); 1621 } 1622 1623 1626 public RequestDispatcher getErrorDispatcherByClass( 1627 Throwable exception) { 1628 1629 Class exceptionClasses[] = this.errorPagesByExceptionKeysSorted; 1631 Throwable errWrapper = new ServletException (exception); 1632 1633 while (errWrapper instanceof ServletException ) { 1634 errWrapper = ((ServletException ) errWrapper).getRootCause(); 1635 if (errWrapper == null) { 1636 break; 1637 } 1638 for (int n = 0; n < exceptionClasses.length; n++) { 1639 1640 Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, 1641 "WinstoneResponse.TestingException", 1642 new String [] {this.errorPagesByExceptionKeysSorted[n].getName(), 1643 errWrapper.getClass().getName()}); 1644 if (exceptionClasses[n].isInstance(errWrapper)) { 1645 String errorURI = (String ) this.errorPagesByException.get(exceptionClasses[n]); 1646 if (errorURI != null) { 1647 RequestDispatcher rd = buildErrorDispatcher(errorURI, 1648 HttpServletResponse.SC_INTERNAL_SERVER_ERROR, 1649 null, errWrapper); 1650 if (rd != null) { 1651 return rd; 1652 } 1653 } else { 1654 Logger.log(Logger.WARNING, Launcher.RESOURCES, 1655 "WinstoneResponse.SkippingException", 1656 new String [] {exceptionClasses[n].getName(), 1657 (String ) this.errorPagesByException.get(exceptionClasses[n]) }); 1658 } 1659 } else { 1660 Logger.log(Logger.WARNING, Launcher.RESOURCES, 1661 "WinstoneResponse.ExceptionNotMatched", 1662 exceptionClasses[n].getName()); 1663 } 1664 } 1665 } 1666 1667 Throwable errPassDown = exception; 1669 while ((errPassDown instanceof ServletException ) && 1670 (((ServletException ) errPassDown).getRootCause() != null)) { 1671 errPassDown = ((ServletException ) errPassDown).getRootCause(); 1672 } 1673 return getErrorDispatcherByCode(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, 1674 null, errPassDown); 1675 } 1676 1677 public RequestDispatcher getErrorDispatcherByCode( 1678 int statusCode, String summaryMessage, Throwable exception) { 1679 String errorURI = (String ) getErrorPagesByCode().get("" + statusCode); 1681 if (errorURI != null) { 1682 RequestDispatcher rd = buildErrorDispatcher(errorURI, statusCode, 1683 summaryMessage, exception); 1684 if (rd != null) { 1685 return rd; 1686 } 1687 } 1688 1689 ServletConfiguration errorServlet = (ServletConfiguration) 1691 this.servletInstances.get(this.errorServletName); 1692 if (errorServlet != null) { 1693 RequestDispatcher rd = new RequestDispatcher(this, errorServlet); 1694 if (rd != null) { 1695 rd.setForErrorDispatcher(null, null, null, statusCode, 1696 summaryMessage, exception, null, this.filterPatternsError); 1697 return rd; 1698 } 1699 } 1700 1701 Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebAppConfig.NoErrorServlet", "" + statusCode, exception); 1703 return null; 1704 } 1705 1706 1709 private RequestDispatcher buildErrorDispatcher(String errorURI, int statusCode, 1710 String summaryMessage, Throwable exception) { 1711 String queryString = ""; 1713 int questionPos = errorURI.indexOf('?'); 1714 if (questionPos != -1) { 1715 if (questionPos != errorURI.length() - 1) { 1716 queryString = errorURI.substring(questionPos + 1); 1717 } 1718 errorURI = errorURI.substring(0, questionPos); 1719 } 1720 1721 ServletException errIterator = new ServletException (exception); 1723 while ((summaryMessage == null) && (errIterator != null)) { 1724 summaryMessage = errIterator.getMessage(); 1725 if (errIterator.getRootCause() instanceof ServletException ) { 1726 errIterator = (ServletException ) errIterator.getRootCause(); 1727 } else { 1728 if (summaryMessage == null) { 1729 summaryMessage = errIterator.getRootCause().getMessage(); 1730 } 1731 errIterator = null; 1732 } 1733 } 1734 1735 StringBuffer servletPath = new StringBuffer (); 1737 StringBuffer pathInfo = new StringBuffer (); 1738 ServletConfiguration servlet = urlMatch(errorURI, servletPath, pathInfo); 1739 if (servlet != null) { 1740 RequestDispatcher rd = new RequestDispatcher(this, servlet); 1741 if (rd != null) { 1742 rd.setForErrorDispatcher(servletPath.toString(), 1743 pathInfo.toString().equals("") ? null : pathInfo.toString(), 1744 queryString, statusCode, summaryMessage, 1745 exception, errorURI, this.filterPatternsError); 1746 return rd; 1747 } 1748 } 1749 return null; 1750 } 1751 1752 1756 private String matchWelcomeFiles(String path, WinstoneRequest request, String queryString) { 1757 if (!path.endsWith("/")) { 1758 path = path + "/"; 1759 } 1760 1761 String qs = (queryString.equals("") ? "" : "?" + queryString); 1762 for (int n = 0; n < this.welcomeFiles.length; n++) { 1763 String welcomeFile = this.welcomeFiles[n]; 1764 while (welcomeFile.startsWith("/")) { 1765 welcomeFile = welcomeFile.substring(1); 1766 } 1767 welcomeFile = path + welcomeFile; 1768 1769 String exact = (String ) this.exactServletMatchMounts.get(welcomeFile); 1770 if (exact != null) { 1771 return welcomeFile + qs; 1772 } 1773 1774 for (int j = 0; j < this.patternMatches.length; j++) { 1776 Mapping urlPattern = this.patternMatches[j]; 1777 if ((urlPattern.getPatternType() == Mapping.FOLDER_PATTERN) 1778 && urlPattern.match(welcomeFile, null, null)) { 1779 return welcomeFile + qs; 1780 } 1781 } 1782 1783 try { 1784 if (getResource(welcomeFile) != null) { 1785 return welcomeFile + qs; 1786 } 1787 } catch (MalformedURLException err) {} 1788 } 1789 return null; 1790 } 1791 1792 public URL getResource(String path) throws MalformedURLException { 1794 if (path == null) { 1795 return null; 1796 } else if (!path.startsWith("/")) { 1797 throw new MalformedURLException (Launcher.RESOURCES.getString( 1798 "WebAppConfig.BadResourcePath", path)); 1799 } else if (!path.equals("/") && path.endsWith("/")) { 1800 path = path.substring(0, path.length() - 1); 1801 } 1802 File res = new File (webRoot, path.substring(1)); 1803 return (res != null) && res.exists() ? res.toURL() : null; 1804 } 1805 1806 public InputStream getResourceAsStream(String path) { 1807 try { 1808 URL res = getResource(path); 1809 return res == null ? null : res.openStream(); 1810 } catch (IOException err) { 1811 throw new WinstoneException(Launcher.RESOURCES 1812 .getString("WebAppConfig.ErrorOpeningStream"), err); 1813 } 1814 } 1815 1816 public String getRealPath(String path) { 1817 if (path == null) 1819 return null; 1820 else { 1821 try { 1822 File res = new File (this.webRoot, path); 1823 if (res.isDirectory()) 1824 return res.getCanonicalPath() + "/"; 1825 else 1826 return res.getCanonicalPath(); 1827 } catch (IOException err) { 1828 return null; 1829 } 1830 } 1831 } 1832 1833 public Set getResourcePaths(String path) { 1834 if (path == null) 1836 return null; 1837 else if (!path.startsWith("/")) 1838 throw new WinstoneException(Launcher.RESOURCES.getString( 1839 "WebAppConfig.BadResourcePath", path)); 1840 else { 1841 String workingPath = null; 1842 if (path.equals("/")) 1843 workingPath = ""; 1844 else { 1845 boolean lastCharIsSlash = path.charAt(path.length() - 1) == '/'; 1846 workingPath = path.substring(1, path.length() 1847 - (lastCharIsSlash ? 1 : 0)); 1848 } 1849 File inPath = new File (this.webRoot, workingPath.equals("") ? "." 1850 : workingPath).getAbsoluteFile(); 1851 if (!inPath.exists()) 1852 return null; 1853 else if (!inPath.isDirectory()) 1854 return null; 1855 1856 File children[] = inPath.listFiles(); 1858 Set out = new HashSet (); 1859 for (int n = 0; n < children.length; n++) { 1860 String entry = "/" + (workingPath.length() != 0 ? workingPath + "/" : "") 1863 + children[n].getName() 1864 + (children[n].isDirectory() ? "/" : ""); 1865 out.add(entry); 1866 } 1867 return out; 1868 } 1869 } 1870 1871 1874 public javax.servlet.Servlet getServlet(String name) { 1875 return null; 1876 } 1877 1878 1881 public Enumeration getServletNames() { 1882 return Collections.enumeration(new ArrayList ()); 1883 } 1884 1885 1888 public Enumeration getServlets() { 1889 return Collections.enumeration(new ArrayList ()); 1890 } 1891 1892 1895 public void log(Exception exception, String msg) { 1896 this.log(msg, exception); 1897 } 1898 1899} 1900 | Popular Tags |