KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > winstone > WebAppConfiguration


1 /*
2  * Copyright 2003-2006 Rick Knowles <winstone-devel at lists sourceforge net>
3  * Distributed under the terms of either:
4  * - the common development and distribution license (CDDL), v1.0; or
5  * - the GNU Lesser General Public License, v2.1 or later
6  */

7 package winstone;
8
9 import java.io.File JavaDoc;
10 import java.io.IOException JavaDoc;
11 import java.io.InputStream JavaDoc;
12 import java.io.PrintWriter JavaDoc;
13 import java.io.StringWriter JavaDoc;
14 import java.lang.reflect.Constructor JavaDoc;
15 import java.net.MalformedURLException JavaDoc;
16 import java.net.URL JavaDoc;
17 import java.net.URLClassLoader JavaDoc;
18 import java.util.ArrayList JavaDoc;
19 import java.util.Arrays JavaDoc;
20 import java.util.Collection JavaDoc;
21 import java.util.Collections JavaDoc;
22 import java.util.Comparator JavaDoc;
23 import java.util.Enumeration JavaDoc;
24 import java.util.HashMap JavaDoc;
25 import java.util.HashSet JavaDoc;
26 import java.util.Hashtable JavaDoc;
27 import java.util.Iterator JavaDoc;
28 import java.util.List JavaDoc;
29 import java.util.Map JavaDoc;
30 import java.util.Set JavaDoc;
31 import java.util.StringTokenizer JavaDoc;
32
33 import javax.servlet.ServletContext JavaDoc;
34 import javax.servlet.ServletContextAttributeEvent JavaDoc;
35 import javax.servlet.ServletContextAttributeListener JavaDoc;
36 import javax.servlet.ServletContextEvent JavaDoc;
37 import javax.servlet.ServletContextListener JavaDoc;
38 import javax.servlet.ServletException JavaDoc;
39 import javax.servlet.ServletRequestAttributeListener JavaDoc;
40 import javax.servlet.ServletRequestListener JavaDoc;
41 import javax.servlet.http.HttpServletResponse JavaDoc;
42 import javax.servlet.http.HttpSessionActivationListener JavaDoc;
43 import javax.servlet.http.HttpSessionAttributeListener JavaDoc;
44 import javax.servlet.http.HttpSessionListener JavaDoc;
45
46 import org.w3c.dom.Node JavaDoc;
47 import org.w3c.dom.NodeList JavaDoc;
48
49 /**
50  * Models the web.xml file's details ... basically just a bunch of configuration
51  * details, plus the actual instances of mounted servlets.
52  *
53  * @author <a HREF="mailto:rick_knowles@hotmail.com">Rick Knowles</a>
54  * @version $Id: WebAppConfiguration.java,v 1.44 2006/08/27 07:19:47 rickknowles Exp $
55  */

56 public class WebAppConfiguration implements ServletContext JavaDoc, Comparator JavaDoc {
57 // private static final String ELEM_DESCRIPTION = "description";
58
private static final String JavaDoc ELEM_DISPLAY_NAME = "display-name";
59     private static final String JavaDoc ELEM_SERVLET = "servlet";
60     private static final String JavaDoc ELEM_SERVLET_MAPPING = "servlet-mapping";
61     private static final String JavaDoc ELEM_SERVLET_NAME = "servlet-name";
62     private static final String JavaDoc ELEM_FILTER = "filter";
63     private static final String JavaDoc ELEM_FILTER_MAPPING = "filter-mapping";
64     private static final String JavaDoc ELEM_FILTER_NAME = "filter-name";
65     private static final String JavaDoc ELEM_DISPATCHER = "dispatcher";
66     private static final String JavaDoc ELEM_URL_PATTERN = "url-pattern";
67     private static final String JavaDoc ELEM_WELCOME_FILES = "welcome-file-list";
68     private static final String JavaDoc ELEM_WELCOME_FILE = "welcome-file";
69     private static final String JavaDoc ELEM_SESSION_CONFIG = "session-config";
70     private static final String JavaDoc ELEM_SESSION_TIMEOUT = "session-timeout";
71     private static final String JavaDoc ELEM_MIME_MAPPING = "mime-mapping";
72     private static final String JavaDoc ELEM_MIME_EXTENSION = "extension";
73     private static final String JavaDoc ELEM_MIME_TYPE = "mime-type";
74     private static final String JavaDoc ELEM_CONTEXT_PARAM = "context-param";
75     private static final String JavaDoc ELEM_PARAM_NAME = "param-name";
76     private static final String JavaDoc ELEM_PARAM_VALUE = "param-value";
77     private static final String JavaDoc ELEM_LISTENER = "listener";
78     private static final String JavaDoc ELEM_LISTENER_CLASS = "listener-class";
79     private static final String JavaDoc ELEM_DISTRIBUTABLE = "distributable";
80     private static final String JavaDoc ELEM_ERROR_PAGE = "error-page";
81     private static final String JavaDoc ELEM_EXCEPTION_TYPE = "exception-type";
82     private static final String JavaDoc ELEM_ERROR_CODE = "error-code";
83     private static final String JavaDoc ELEM_ERROR_LOCATION = "location";
84     private static final String JavaDoc ELEM_SECURITY_CONSTRAINT = "security-constraint";
85     private static final String JavaDoc ELEM_LOGIN_CONFIG = "login-config";
86     private static final String JavaDoc ELEM_SECURITY_ROLE = "security-role";
87     private static final String JavaDoc ELEM_ROLE_NAME = "role-name";
88     private static final String JavaDoc ELEM_ENV_ENTRY = "env-entry";
89     private static final String JavaDoc ELEM_LOCALE_ENC_MAP_LIST = "locale-encoding-mapping-list";
90     private static final String JavaDoc ELEM_LOCALE_ENC_MAPPING = "locale-encoding-mapping";
91     private static final String JavaDoc ELEM_LOCALE = "locale";
92     private static final String JavaDoc ELEM_ENCODING = "encoding";
93     private static final String JavaDoc ELEM_JSP_CONFIG = "jsp-config";
94     private static final String JavaDoc ELEM_JSP_PROPERTY_GROUP = "jsp-property-group";
95     
96     private static final String JavaDoc DISPATCHER_REQUEST = "REQUEST";
97     private static final String JavaDoc DISPATCHER_FORWARD = "FORWARD";
98     private static final String JavaDoc DISPATCHER_INCLUDE = "INCLUDE";
99     private static final String JavaDoc DISPATCHER_ERROR = "ERROR";
100     private static final String JavaDoc JSP_SERVLET_NAME = "JspServlet";
101     private static final String JavaDoc JSP_SERVLET_MAPPING = "*.jsp";
102     private static final String JavaDoc JSPX_SERVLET_MAPPING = "*.jspx";
103     private static final String JavaDoc JSP_SERVLET_LOG_LEVEL = "WARNING";
104     private static final String JavaDoc INVOKER_SERVLET_NAME = "invoker";
105     private static final String JavaDoc INVOKER_SERVLET_CLASS = "winstone.invoker.InvokerServlet";
106     private static final String JavaDoc DEFAULT_INVOKER_PREFIX = "/servlet/";
107     private static final String JavaDoc DEFAULT_SERVLET_NAME = "default";
108     private static final String JavaDoc DEFAULT_SERVLET_CLASS = "winstone.StaticResourceServlet";
109     private static final String JavaDoc DEFAULT_REALM_CLASS = "winstone.realm.ArgumentsRealm";
110     private static final String JavaDoc DEFAULT_JNDI_MGR_CLASS = "winstone.jndi.WebAppJNDIManager";
111     private static final String JavaDoc RELOADING_CL_CLASS = "winstone.classLoader.ReloadingClassLoader";
112     private static final String JavaDoc ERROR_SERVLET_NAME = "winstoneErrorServlet";
113     private static final String JavaDoc ERROR_SERVLET_CLASS = "winstone.ErrorServlet";
114     
115     private static final String JavaDoc WEB_INF = "WEB-INF";
116     private static final String JavaDoc CLASSES = "classes/";
117     private static final String JavaDoc LIB = "lib";
118     
119     static final String JavaDoc JSP_SERVLET_CLASS = "org.apache.jasper.servlet.JspServlet";
120     
121     private HostConfiguration ownerHostConfig;
122     private Cluster cluster;
123     private String JavaDoc webRoot;
124     private String JavaDoc prefix;
125     private String JavaDoc contextName;
126     private ClassLoader JavaDoc loader;
127     private String JavaDoc displayName;
128     private Map JavaDoc attributes;
129     private Map JavaDoc initParameters;
130     private Map JavaDoc sessions;
131     private Map JavaDoc mimeTypes;
132     private Map JavaDoc servletInstances;
133     private Map JavaDoc filterInstances;
134     private ServletContextAttributeListener JavaDoc contextAttributeListeners[];
135     private ServletContextListener JavaDoc contextListeners[];
136     private ServletRequestListener JavaDoc requestListeners[];
137     private ServletRequestAttributeListener JavaDoc requestAttributeListeners[];
138     private HttpSessionActivationListener JavaDoc sessionActivationListeners[];
139     private HttpSessionAttributeListener JavaDoc sessionAttributeListeners[];
140     private HttpSessionListener JavaDoc sessionListeners[];
141     private Throwable JavaDoc contextStartupError;
142     private Map JavaDoc 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 JavaDoc welcomeFiles[];
151     private Integer JavaDoc sessionTimeout;
152     private Class JavaDoc[] errorPagesByExceptionKeysSorted;
153     private Map JavaDoc errorPagesByException;
154     private Map JavaDoc errorPagesByCode;
155     private Map JavaDoc localeEncodingMap;
156     private String JavaDoc defaultServletName;
157     private String JavaDoc errorServletName;
158     private JNDIManager jndiManager;
159     private AccessLogger accessLogger;
160     private Map JavaDoc filterMatchCache;
161     private boolean useSavedSessions;
162     
163     public static boolean booleanArg(Map JavaDoc args, String JavaDoc name, boolean defaultTrue) {
164         String JavaDoc value = (String JavaDoc) 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 JavaDoc stringArg(Map JavaDoc args, String JavaDoc name, String JavaDoc defaultValue) {
172         return (String JavaDoc) (args.get(name) == null ? defaultValue : args.get(name));
173     }
174
175     public static int intArg(Map JavaDoc args, String JavaDoc name, int defaultValue) {
176         return Integer.parseInt(stringArg(args, name, "" + defaultValue));
177     }
178
179     public static String JavaDoc getTextFromNode(Node JavaDoc node) {
180         if (node == null) {
181             return null;
182         }
183         Node JavaDoc child = node.getFirstChild();
184         if (child == null) {
185             return "";
186         }
187         String JavaDoc textNode = child.getNodeValue();
188         if (textNode == null) {
189             return "";
190         } else {
191             return textNode.trim();
192         }
193     }
194     
195     public static boolean useSavedSessions(Map JavaDoc args) {
196         return booleanArg(args, "useSavedSessions", false);
197     }
198     
199     /**
200      * Constructor. This parses the xml and sets up for basic routing
201      */

202     public WebAppConfiguration(HostConfiguration ownerHostConfig, Cluster cluster, String JavaDoc webRoot,
203             String JavaDoc prefix, ObjectPool objectPool, Map JavaDoc startupArgs, Node JavaDoc elm,
204             ClassLoader JavaDoc parentClassLoader, File JavaDoc parentClassPaths[], String JavaDoc contextName) {
205         this.ownerHostConfig = ownerHostConfig;
206         this.webRoot = webRoot;
207         this.prefix = prefix;
208         this.contextName = contextName;
209
210         List JavaDoc localLoaderClassPathFiles = new ArrayList JavaDoc();
211         this.loader = buildWebAppClassLoader(startupArgs, parentClassLoader,
212                 webRoot, localLoaderClassPathFiles);
213         
214         // Build switch values
215
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         // Check jasper is available
221
if (useJasper) {
222             try {
223                 Class.forName(JSP_SERVLET_CLASS, false, this.loader);
224             } catch (Throwable JavaDoc 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 JavaDoc err) {
236                 Logger.log(Logger.WARNING, Launcher.RESOURCES,
237                         "WebAppConfig.InvokerNotFound");
238                 useInvoker = false;
239             }
240         }
241
242         this.attributes = new Hashtable JavaDoc();
243         this.initParameters = new HashMap JavaDoc();
244         this.sessions = new Hashtable JavaDoc();
245
246         this.servletInstances = new HashMap JavaDoc();
247         this.filterInstances = new HashMap JavaDoc();
248         this.filterMatchCache = new HashMap JavaDoc();
249
250         List JavaDoc contextAttributeListeners = new ArrayList JavaDoc();
251         List JavaDoc contextListeners = new ArrayList JavaDoc();
252         List JavaDoc requestListeners = new ArrayList JavaDoc();
253         List JavaDoc requestAttributeListeners = new ArrayList JavaDoc();
254         List JavaDoc sessionActivationListeners = new ArrayList JavaDoc();
255         List JavaDoc sessionAttributeListeners = new ArrayList JavaDoc();
256         List JavaDoc sessionListeners = new ArrayList JavaDoc();
257
258         this.errorPagesByException = new HashMap JavaDoc();
259         this.errorPagesByCode = new HashMap JavaDoc();
260         boolean distributable = false;
261
262         this.exactServletMatchMounts = new Hashtable JavaDoc();
263         List JavaDoc localFolderPatterns = new ArrayList JavaDoc();
264         List JavaDoc localExtensionPatterns = new ArrayList JavaDoc();
265
266         List JavaDoc lfpRequest = new ArrayList JavaDoc();
267         List JavaDoc lfpForward = new ArrayList JavaDoc();
268         List JavaDoc lfpInclude = new ArrayList JavaDoc();
269         List JavaDoc lfpError = new ArrayList JavaDoc();
270
271         List JavaDoc localWelcomeFiles = new ArrayList JavaDoc();
272         List JavaDoc startupServlets = new ArrayList JavaDoc();
273
274         Set JavaDoc rolesAllowed = new HashSet JavaDoc();
275         List JavaDoc constraintNodes = new ArrayList JavaDoc();
276         List JavaDoc envEntryNodes = new ArrayList JavaDoc();
277         List JavaDoc localErrorPagesByExceptionList = new ArrayList JavaDoc();
278
279         Node JavaDoc loginConfigNode = null;
280
281         // Add the class loader as an implicit context listener if it implements the interface
282
addListenerInstance(this.loader, contextAttributeListeners,
283                 contextListeners, requestAttributeListeners, requestListeners,
284                 sessionActivationListeners, sessionAttributeListeners,
285                 sessionListeners);
286          
287         // init mimeTypes set
288
this.mimeTypes = new Hashtable JavaDoc();
289         String JavaDoc allTypes = Launcher.RESOURCES.getString("WebAppConfig.DefaultMimeTypes");
290         StringTokenizer JavaDoc mappingST = new StringTokenizer JavaDoc(allTypes, ":", false);
291         for (; mappingST.hasMoreTokens();) {
292             String JavaDoc mapping = mappingST.nextToken();
293             int delimPos = mapping.indexOf('=');
294             if (delimPos == -1)
295                 continue;
296             String JavaDoc extension = mapping.substring(0, delimPos);
297             String JavaDoc mimeType = mapping.substring(delimPos + 1);
298             this.mimeTypes.put(extension.toLowerCase(), mimeType);
299         }
300
301         this.localeEncodingMap = new HashMap JavaDoc();
302         String JavaDoc encodingMapSet = Launcher.RESOURCES.getString("WebAppConfig.EncodingMap");
303         StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(encodingMapSet, ";");
304         for (; st.hasMoreTokens();) {
305             String JavaDoc 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         // init jsp mappings set
314
List JavaDoc jspMappings = new ArrayList JavaDoc();
315         jspMappings.add(JSP_SERVLET_MAPPING);
316         jspMappings.add(JSPX_SERVLET_MAPPING);
317
318         // Add required context atttributes
319
File JavaDoc tmpDir = new File JavaDoc(new File JavaDoc(new File JavaDoc(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         // Parse the web.xml file
325
if (elm != null) {
326             NodeList JavaDoc children = elm.getChildNodes();
327             for (int n = 0; n < children.getLength(); n++) {
328                 Node JavaDoc child = children.item(n);
329                 if (child.getNodeType() != Node.ELEMENT_NODE)
330                     continue;
331                 String JavaDoc 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                 // Session config elements
349
else if (nodeName.equals(ELEM_SESSION_CONFIG)) {
350                     for (int m = 0; m < child.getChildNodes().getLength(); m++) {
351                         Node JavaDoc timeoutElm = child.getChildNodes().item(m);
352                         if ((timeoutElm.getNodeType() == Node.ELEMENT_NODE)
353                                 && (timeoutElm.getNodeName().equals(ELEM_SESSION_TIMEOUT))) {
354                             String JavaDoc timeoutStr = getTextFromNode(child);
355                             if (!timeoutStr.equals("")) {
356                                 this.sessionTimeout = Integer.valueOf(timeoutStr);
357                             }
358                         }
359                     }
360                 }
361
362                 // Construct the security roles
363
else if (child.getNodeName().equals(ELEM_SECURITY_ROLE)) {
364                     for (int m = 0; m < child.getChildNodes().getLength(); m++) {
365                         Node JavaDoc 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                 // Construct the servlet instances
374
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                 // Construct the servlet instances
384
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                 // Construct the servlet instances
391
else if (nodeName.equals(ELEM_LISTENER)) {
392                     String JavaDoc listenerClass = null;
393                     for (int m = 0; m < child.getChildNodes().getLength(); m++) {
394                         Node JavaDoc 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 JavaDoc listener = Class.forName(listenerClass, true,
403                                     this.loader);
404                             Object JavaDoc 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 JavaDoc err) {
412                             Logger.log(Logger.WARNING, Launcher.RESOURCES,
413                                     "WebAppConfig.InvalidListener",
414                                     listenerClass);
415                         }
416                 }
417
418                 // Process the servlet mappings
419
else if (nodeName.equals(ELEM_SERVLET_MAPPING)) {
420                     String JavaDoc name = null;
421                     List JavaDoc mappings = new ArrayList JavaDoc();
422
423                     // Parse the element and extract
424
NodeList JavaDoc mappingChildren = child.getChildNodes();
425                     for (int k = 0; k < mappingChildren.getLength(); k++) {
426                         Node JavaDoc mapChild = mappingChildren.item(k);
427                         if (mapChild.getNodeType() != Node.ELEMENT_NODE)
428                             continue;
429                         String JavaDoc 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 JavaDoc i = mappings.iterator(); i.hasNext(); ) {
437                         processMapping(name, (String JavaDoc) i.next(), this.exactServletMatchMounts,
438                                 localFolderPatterns, localExtensionPatterns);
439                     }
440                 }
441
442                 // Process the filter mappings
443
else if (nodeName.equals(ELEM_FILTER_MAPPING)) {
444                     String JavaDoc filterName = null;
445                     List JavaDoc mappings = new ArrayList JavaDoc();
446                     boolean onRequest = false;
447                     boolean onForward = false;
448                     boolean onInclude = false;
449                     boolean onError = false;
450
451                     // Parse the element and extract
452
for (int k = 0; k < child.getChildNodes().getLength(); k++) {
453                         Node JavaDoc mapChild = child.getChildNodes().item(k);
454                         if (mapChild.getNodeType() != Node.ELEMENT_NODE)
455                             continue;
456                         String JavaDoc 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 JavaDoc 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 JavaDoc i = mappings.iterator(); i.hasNext(); ) {
484                         String JavaDoc item = (String JavaDoc) 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                 // Process the list of welcome files
503
else if (nodeName.equals(ELEM_WELCOME_FILES)) {
504                     for (int m = 0; m < child.getChildNodes().getLength(); m++) {
505                         Node JavaDoc welcomeFile = child.getChildNodes().item(m);
506                         if ((welcomeFile.getNodeType() == Node.ELEMENT_NODE)
507                                 && welcomeFile.getNodeName().equals(ELEM_WELCOME_FILE)) {
508                             String JavaDoc welcomeStr = getTextFromNode(welcomeFile);
509                             if (!welcomeStr.equals("")) {
510                                 localWelcomeFiles.add(welcomeStr);
511                             }
512                         }
513                     }
514                 }
515                 
516                 // Process the error pages
517
else if (nodeName.equals(ELEM_ERROR_PAGE)) {
518                     String JavaDoc code = null;
519                     String JavaDoc exception = null;
520                     String JavaDoc location = null;
521
522                     // Parse the element and extract
523
for (int k = 0; k < child.getChildNodes().getLength(); k++) {
524                         Node JavaDoc errorChild = child.getChildNodes().item(k);
525                         if (errorChild.getNodeType() != Node.ELEMENT_NODE)
526                             continue;
527                         String JavaDoc 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 JavaDoc exceptionClass = Class.forName(exception
540                                     .trim(), false, this.loader);
541                             localErrorPagesByExceptionList.add(exceptionClass);
542                             this.errorPagesByException.put(exceptionClass,
543                                     location.trim());
544                         } catch (ClassNotFoundException JavaDoc err) {
545                             Logger.log(Logger.ERROR, Launcher.RESOURCES,
546                                             "WebAppConfig.ExceptionNotFound",
547                                             exception);
548                         }
549                 }
550
551                 // Process the list of welcome files
552
else if (nodeName.equals(ELEM_MIME_MAPPING)) {
553                     String JavaDoc extension = null;
554                     String JavaDoc mimeType = null;
555                     for (int m = 0; m < child.getChildNodes().getLength(); m++) {
556                         Node JavaDoc 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 JavaDoc[] { extension, mimeType });
572                 }
573
574                 // Process the list of welcome files
575
else if (nodeName.equals(ELEM_CONTEXT_PARAM)) {
576                     String JavaDoc name = null;
577                     String JavaDoc value = null;
578                     for (int m = 0; m < child.getChildNodes().getLength(); m++) {
579                         Node JavaDoc 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 JavaDoc[] {
594                                         name, value });
595                 }
596
597                 // Process locale encoding mapping elements
598
else if (nodeName.equals(ELEM_LOCALE_ENC_MAP_LIST)) {
599                     for (int m = 0; m < child.getChildNodes().getLength(); m++) {
600                         Node JavaDoc 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 JavaDoc localeName = "";
605                             String JavaDoc encoding = "";
606                             for (int l = 0; l < mappingNode.getChildNodes().getLength(); l++) {
607                                 Node JavaDoc 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                 // Record the url mappings for jsp files if set
622
else if (nodeName.equals(ELEM_JSP_CONFIG)) {
623                     for (int m = 0; m < child.getChildNodes().getLength(); m++) {
624                         Node JavaDoc 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 JavaDoc urlPatternNode = propertyGroupNode.getChildNodes().item(l);
629                                 if ((urlPatternNode.getNodeType() == Node.ELEMENT_NODE)
630                                         && urlPatternNode.getNodeName().equals(ELEM_URL_PATTERN)) {
631                                     String JavaDoc jm = getTextFromNode(urlPatternNode);
632                                     if (!jm.equals("")) {
633                                         jspMappings.add(jm);
634                                     }
635                                 }
636                             }
637                         }
638                     }
639                 }
640             }
641         }
642         
643         // If not distributable, remove the cluster reference
644
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         // Build the login/security role instance
653
if (!constraintNodes.isEmpty() && (loginConfigNode != null)) {
654             String JavaDoc 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             // Load the appropriate auth class
661
if (authMethod == null) {
662                 authMethod = "BASIC";
663             } else {
664                 authMethod = WinstoneResourceBundle.globalReplace(authMethod, "-", "");
665             }
666             String JavaDoc realmClassName = stringArg(startupArgs, "realmClassName",
667                     DEFAULT_REALM_CLASS).trim();
668             String JavaDoc authClassName = "winstone.auth."
669                     + authMethod.substring(0, 1).toUpperCase()
670                     + authMethod.substring(1).toLowerCase()
671                     + "AuthenticationHandler";
672             try {
673                 // Build the realm
674
Class JavaDoc realmClass = Class.forName(realmClassName);
675                 Constructor JavaDoc realmConstr = realmClass
676                         .getConstructor(new Class JavaDoc[] {Set JavaDoc.class, Map JavaDoc.class });
677                 this.authenticationRealm = (AuthenticationRealm) realmConstr
678                         .newInstance(new Object JavaDoc[] { rolesAllowed, startupArgs });
679
680                 // Build the authentication handler
681
Class JavaDoc authClass = Class.forName(authClassName);
682                 Constructor JavaDoc authConstr = authClass
683                         .getConstructor(new Class JavaDoc[] { Node JavaDoc.class, List JavaDoc.class,
684                                 Set JavaDoc.class, AuthenticationRealm.class });
685                 this.authenticationHandler = (AuthenticationHandler) authConstr
686                         .newInstance(new Object JavaDoc[] { loginConfigNode,
687                                 constraintNodes, rolesAllowed,
688                                 authenticationRealm });
689             } catch (ClassNotFoundException JavaDoc err) {
690                 Logger.log(Logger.DEBUG, Launcher.RESOURCES,
691                         "WebAppConfig.AuthDisabled", authMethod);
692             } catch (Throwable JavaDoc err) {
693                 Logger.log(Logger.ERROR, Launcher.RESOURCES,
694                         "WebAppConfig.AuthError", new String JavaDoc[] { 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         // Instantiate the JNDI manager
702
String JavaDoc jndiMgrClassName = stringArg(startupArgs, "webappJndiClassName",
703                 DEFAULT_JNDI_MGR_CLASS).trim();
704         if (useJNDI) {
705             try {
706                 // Build the realm
707
Class JavaDoc jndiMgrClass = Class.forName(jndiMgrClassName, true, this.loader);
708                 Constructor JavaDoc jndiMgrConstr = jndiMgrClass.getConstructor(new Class JavaDoc[] {
709                         Map JavaDoc.class, List JavaDoc.class, ClassLoader JavaDoc.class });
710                 this.jndiManager = (JNDIManager) jndiMgrConstr.newInstance(new Object JavaDoc[] {
711                         null, envEntryNodes, this.loader });
712                 if (this.jndiManager != null)
713                     this.jndiManager.setup();
714             } catch (ClassNotFoundException JavaDoc err) {
715                 Logger.log(Logger.DEBUG, Launcher.RESOURCES,
716                         "WebAppConfig.JNDIDisabled");
717             } catch (Throwable JavaDoc err) {
718                 Logger.log(Logger.ERROR, Launcher.RESOURCES,
719                         "WebAppConfig.JNDIError", jndiMgrClassName, err);
720             }
721         }
722         
723         String JavaDoc loggerClassName = stringArg(startupArgs, "accessLoggerClassName", "").trim();
724         if (!loggerClassName.equals("")) {
725             try {
726                 // Build the realm
727
Class JavaDoc loggerClass = Class.forName(loggerClassName, true, this.loader);
728                 Constructor JavaDoc loggerConstr = loggerClass.getConstructor(new Class JavaDoc[] {
729                         WebAppConfiguration.class, Map JavaDoc.class });
730                 this.accessLogger = (AccessLogger) loggerConstr.newInstance(new Object JavaDoc[] {
731                         this, startupArgs});
732             } catch (Throwable JavaDoc 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         // Add the default index.html welcomeFile if none are supplied
742
if (localWelcomeFiles.isEmpty()) {
743             if (useJasper) {
744                 localWelcomeFiles.add("index.jsp");
745             }
746             localWelcomeFiles.add("index.html");
747         }
748
749         // Put the name filters after the url filters, then convert to string
750
// arrays
751
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 JavaDoc[]) localWelcomeFiles.toArray(new String JavaDoc[0]);
769         this.errorPagesByExceptionKeysSorted = (Class JavaDoc[]) localErrorPagesByExceptionList
770                 .toArray(new Class JavaDoc[0]);
771         Arrays.sort(this.errorPagesByExceptionKeysSorted, this);
772
773         // Put the listeners into their arrays
774
this.contextAttributeListeners = (ServletContextAttributeListener JavaDoc[]) contextAttributeListeners
775                 .toArray(new ServletContextAttributeListener JavaDoc[0]);
776         this.contextListeners = (ServletContextListener JavaDoc[]) contextListeners
777                 .toArray(new ServletContextListener JavaDoc[0]);
778         this.requestListeners = (ServletRequestListener JavaDoc[]) requestListeners
779                 .toArray(new ServletRequestListener JavaDoc[0]);
780         this.requestAttributeListeners = (ServletRequestAttributeListener JavaDoc[]) requestAttributeListeners
781                 .toArray(new ServletRequestAttributeListener JavaDoc[0]);
782         this.sessionActivationListeners = (HttpSessionActivationListener JavaDoc[]) sessionActivationListeners
783                 .toArray(new HttpSessionActivationListener JavaDoc[0]);
784         this.sessionAttributeListeners = (HttpSessionAttributeListener JavaDoc[]) sessionAttributeListeners
785                 .toArray(new HttpSessionAttributeListener JavaDoc[0]);
786         this.sessionListeners = (HttpSessionListener JavaDoc[]) sessionListeners
787                 .toArray(new HttpSessionListener JavaDoc[0]);
788
789         // If we haven't explicitly mapped the default servlet, map it here
790
if (this.defaultServletName == null)
791             this.defaultServletName = DEFAULT_SERVLET_NAME;
792         if (this.errorServletName == null)
793             this.errorServletName = ERROR_SERVLET_NAME;
794
795         // If we don't have an instance of the default servlet, mount the inbuilt one
796
if (this.servletInstances.get(this.defaultServletName) == null) {
797             boolean useDirLists = booleanArg(startupArgs, "directoryListings", true);
798             
799             Map JavaDoc staticParams = new Hashtable JavaDoc();
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             // commented cause it should be called during startup servlet
807
// defaultServlet.getRequestDispatcher(this.filterInstances);
808
this.servletInstances.put(this.defaultServletName, defaultServlet);
809             startupServlets.add(defaultServlet);
810         }
811
812         // If we don't have an instance of the default servlet, mount the inbuilt one
813
if (this.servletInstances.get(this.errorServletName) == null) {
814             ServletConfiguration errorServlet = new ServletConfiguration(
815                     this, this.errorServletName, ERROR_SERVLET_CLASS,
816                     new HashMap JavaDoc(), 0);
817             // commented cause it should be called during startup servlet
818
// errorServlet.getRequestDispatcher(this.filterInstances);
819
this.servletInstances.put(this.errorServletName, errorServlet);
820             startupServlets.add(errorServlet);
821         }
822         
823         // Initialise jasper servlet if requested
824
if (useJasper) {
825             setAttribute("org.apache.catalina.classloader", this.loader);
826             // Logger.log(Logger.DEBUG, "Setting JSP classpath: " +
827
// this.loader.getClasspath());
828
try {
829                 StringBuffer JavaDoc cp = new StringBuffer JavaDoc();
830                 for (Iterator JavaDoc i = localLoaderClassPathFiles.iterator(); i.hasNext(); ) {
831                     cp.append(((File JavaDoc) 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 JavaDoc err) {
841                 Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebAppConfig.ErrorSettingJSPPaths", err);
842             }
843
844             Map JavaDoc jspParams = new HashMap JavaDoc();
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 JavaDoc mapIt = jspMappings.iterator(); mapIt.hasNext(); ) {
851                 processMapping(JSP_SERVLET_NAME, (String JavaDoc) mapIt.next(),
852                         this.exactServletMatchMounts, localFolderPatterns,
853                         localExtensionPatterns);
854             }
855         }
856
857         // Initialise invoker servlet if requested
858
if (useInvoker) {
859             // Get generic options
860
String JavaDoc invokerPrefix = stringArg(startupArgs, "invokerPrefix",
861                     DEFAULT_INVOKER_PREFIX);
862             Map JavaDoc invokerParams = new HashMap JavaDoc();
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         // Sort the folder patterns so the longest paths are first
875
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         // Send init notifies
881
try {
882             for (int n = 0; n < this.contextListeners.length; n++) {
883                 ClassLoader JavaDoc cl = Thread.currentThread().getContextClassLoader();
884                 Thread.currentThread().setContextClassLoader(this.loader);
885                 this.contextListeners[n].contextInitialized(new ServletContextEvent JavaDoc(this));
886                 Thread.currentThread().setContextClassLoader(cl);
887             }
888         } catch (Throwable JavaDoc 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             // Load sessions if enabled
895
if (this.useSavedSessions) {
896                 WinstoneSession.loadSessions(this);
897             }
898             
899             // Initialise all the filters
900
for (Iterator JavaDoc i = this.filterInstances.values().iterator(); i.hasNext();) {
901                 FilterConfiguration config = (FilterConfiguration) i.next();
902                 try {
903                     config.getFilter();
904                 } catch (ServletException JavaDoc err) {
905                     Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebAppConfig.FilterStartupError",
906                             config.getFilterName(), err);
907                 }
908             }
909
910             // Initialise load on startup servlets
911
Object JavaDoc 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     /**
920      * Build the web-app classloader. This tries to load the preferred classloader first,
921      * but if it fails, falls back to a simple URLClassLoader.
922      */

923     private ClassLoader JavaDoc buildWebAppClassLoader(Map JavaDoc startupArgs, ClassLoader JavaDoc parentClassLoader,
924             String JavaDoc webRoot, List JavaDoc classPathFileList) {
925         List JavaDoc urlList = new ArrayList JavaDoc();
926         
927         try {
928             // Web-inf folder
929
File JavaDoc webInfFolder = new File JavaDoc(webRoot, WEB_INF);
930
931             // Classes folder
932
File JavaDoc classesFolder = new File JavaDoc(webInfFolder, CLASSES);
933             if (classesFolder.exists()) {
934                 Logger.log(Logger.DEBUG, Launcher.RESOURCES,
935                         "WebAppConfig.WebAppClasses");
936                 urlList.add(new URL JavaDoc("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             // Lib folder's jar files
945
File JavaDoc libFolder = new File JavaDoc(webInfFolder, LIB);
946             if (libFolder.exists()) {
947                 File JavaDoc jars[] = libFolder.listFiles();
948                 for (int n = 0; n < jars.length; n++) {
949                     String JavaDoc 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 JavaDoc err) {
963             throw new WinstoneException(Launcher.RESOURCES
964                     .getString("WebAppConfig.BadURL"), err);
965         } catch (IOException JavaDoc err) {
966             throw new WinstoneException(Launcher.RESOURCES
967                     .getString("WebAppConfig.IOException"), err);
968         }
969
970         URL JavaDoc jarURLs[] = (URL JavaDoc []) urlList.toArray(new URL JavaDoc[0]);
971         
972         boolean useReloading = booleanArg(startupArgs, "useServletReloading", false);
973         String JavaDoc preferredClassLoader = stringArg(startupArgs, "preferredClassLoader", "");
974         if (preferredClassLoader.equals("") && useReloading) {
975             preferredClassLoader = RELOADING_CL_CLASS;
976         }
977         
978         // Try to set up the preferred class loader, and if we fail, use the normal one
979
ClassLoader JavaDoc outputCL = null;
980         if (!preferredClassLoader.equals("")) {
981             try {
982                 Class JavaDoc preferredCL = Class.forName(preferredClassLoader, true, parentClassLoader);
983                 Constructor JavaDoc reloadConstr = preferredCL.getConstructor(new Class JavaDoc[] {
984                         (new URL JavaDoc[0]).getClass(), ClassLoader JavaDoc.class});
985                 outputCL = (ClassLoader JavaDoc) reloadConstr.newInstance(new Object JavaDoc[] {
986                         jarURLs, parentClassLoader});
987             } catch (Throwable JavaDoc err) {
988                 Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebAppConfig.CLError", err);
989             }
990         }
991
992         if (outputCL == null) {
993             outputCL = new URLClassLoader JavaDoc(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 JavaDoc listenerInstance, List JavaDoc contextAttributeListeners,
1001            List JavaDoc contextListeners, List JavaDoc requestAttributeListeners, List JavaDoc requestListeners,
1002            List JavaDoc sessionActivationListeners, List JavaDoc sessionAttributeListeners,
1003            List JavaDoc sessionListeners) {
1004        if (listenerInstance instanceof ServletContextAttributeListener JavaDoc)
1005            contextAttributeListeners.add(listenerInstance);
1006        if (listenerInstance instanceof ServletContextListener JavaDoc)
1007            contextListeners.add(listenerInstance);
1008        if (listenerInstance instanceof ServletRequestAttributeListener JavaDoc)
1009            requestAttributeListeners.add(listenerInstance);
1010        if (listenerInstance instanceof ServletRequestListener JavaDoc)
1011            requestListeners.add(listenerInstance);
1012        if (listenerInstance instanceof HttpSessionActivationListener JavaDoc)
1013            sessionActivationListeners.add(listenerInstance);
1014        if (listenerInstance instanceof HttpSessionAttributeListener JavaDoc)
1015            sessionAttributeListeners.add(listenerInstance);
1016        if (listenerInstance instanceof HttpSessionListener JavaDoc)
1017            sessionListeners.add(listenerInstance);
1018    }
1019    
1020    public String JavaDoc getContextPath() {
1021        return this.prefix;
1022    }
1023
1024    public String JavaDoc getWebroot() {
1025        return this.webRoot;
1026    }
1027
1028    public ClassLoader JavaDoc getLoader() {
1029        return this.loader;
1030    }
1031
1032    public AccessLogger getAccessLogger() {
1033        return this.accessLogger;
1034    }
1035
1036    public Map JavaDoc getFilters() {
1037        return this.filterInstances;
1038    }
1039    
1040    public String JavaDoc getContextName() {
1041        return this.contextName;
1042    }
1043
1044    public Class JavaDoc[] getErrorPageExceptions() {
1045        return this.errorPagesByExceptionKeysSorted;
1046    }
1047
1048    public Map JavaDoc getErrorPagesByException() {
1049        return this.errorPagesByException;
1050    }
1051
1052    public Map JavaDoc getErrorPagesByCode() {
1053        return this.errorPagesByCode;
1054    }
1055
1056    public Map JavaDoc getLocaleEncodingMap() {
1057        return this.localeEncodingMap;
1058    }
1059
1060    public String JavaDoc[] getWelcomeFiles() {
1061        return this.welcomeFiles;
1062    }
1063
1064    public boolean isDistributable() {
1065        return (this.cluster != null);
1066    }
1067
1068    public Map JavaDoc getFilterMatchCache() {
1069        return this.filterMatchCache;
1070    }
1071    
1072    public String JavaDoc getOwnerHostname() {
1073        return this.ownerHostConfig.getHostname();
1074    }
1075    
1076    public ServletRequestListener JavaDoc[] getRequestListeners() {
1077        return this.requestListeners;
1078    }
1079
1080    public ServletRequestAttributeListener JavaDoc[] getRequestAttributeListeners() {
1081        return this.requestAttributeListeners;
1082    }
1083
1084    public static void addJspServletParams(Map JavaDoc jspParams) {
1085        jspParams.put("logVerbosityLevel", JSP_SERVLET_LOG_LEVEL);
1086        jspParams.put("fork", "false");
1087    }
1088
1089    public int compare(Object JavaDoc one, Object JavaDoc two) {
1090        if (!(one instanceof Class JavaDoc) || !(two instanceof Class JavaDoc))
1091            throw new IllegalArgumentException JavaDoc(
1092                    "This comparator is only for sorting classes");
1093        Class JavaDoc classOne = (Class JavaDoc) one;
1094        Class JavaDoc classTwo = (Class JavaDoc) 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 JavaDoc getServletURIFromRequestURI(String JavaDoc 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    /**
1115     * Iterates through each of the servlets/filters and calls destroy on them
1116     */

1117    public void destroy() {
1118        synchronized (this.filterMatchCache) {
1119            this.filterMatchCache.clear();
1120        }
1121        
1122        Collection JavaDoc filterInstances = new ArrayList JavaDoc(this.filterInstances.values());
1123        for (Iterator JavaDoc i = filterInstances.iterator(); i.hasNext();) {
1124            try {
1125                ((FilterConfiguration) i.next()).destroy();
1126            } catch (Throwable JavaDoc err) {
1127                Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebAppConfig.ShutdownError", err);
1128            }
1129        }
1130        this.filterInstances.clear();
1131        
1132        Collection JavaDoc servletInstances = new ArrayList JavaDoc(this.servletInstances.values());
1133        for (Iterator JavaDoc i = servletInstances.iterator(); i.hasNext();) {
1134            try {
1135                ((ServletConfiguration) i.next()).destroy();
1136            } catch (Throwable JavaDoc err) {
1137                Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebAppConfig.ShutdownError", err);
1138            }
1139        }
1140        this.servletInstances.clear();
1141
1142        // Drop all sessions
1143
Collection JavaDoc sessions = new ArrayList JavaDoc(this.sessions.values());
1144        for (Iterator JavaDoc 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 JavaDoc err) {
1153                Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebAppConfig.ShutdownError", err);
1154            }
1155        }
1156        this.sessions.clear();
1157
1158        // Send destroy notifies - backwards
1159
for (int n = this.contextListeners.length - 1; n >= 0; n--) {
1160            try {
1161                ClassLoader JavaDoc cl = Thread.currentThread().getContextClassLoader();
1162                Thread.currentThread().setContextClassLoader(this.loader);
1163                this.contextListeners[n].contextDestroyed(new ServletContextEvent JavaDoc(this));
1164                this.contextListeners[n] = null;
1165                Thread.currentThread().setContextClassLoader(cl);
1166            } catch (Throwable JavaDoc err) {
1167                Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebAppConfig.ShutdownError", err);
1168            }
1169        }
1170        this.contextListeners = null;
1171        
1172        // Terminate class loader reloading thread if running
1173
if (this.loader != null) {
1174            // already shutdown/handled by the servlet context listeners
1175
// try {
1176
// Method methDestroy = this.loader.getClass().getMethod("destroy", new Class[0]);
1177
// methDestroy.invoke(this.loader, new Object[0]);
1178
// } catch (Throwable err) {
1179
// Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebAppConfig.ShutdownError", err);
1180
// }
1181
this.loader = null;
1182        }
1183
1184        // Kill JNDI manager if we have one
1185
if (this.jndiManager != null) {
1186            this.jndiManager.tearDown();
1187            this.jndiManager = null;
1188        }
1189
1190        // Kill JNDI manager if we have one
1191
if (this.accessLogger != null) {
1192            this.accessLogger.destroy();
1193            this.accessLogger = null;
1194        }
1195    }
1196
1197    /**
1198     * Triggered by the admin thread on the reloading class loader. This will
1199     * cause a full shutdown and reinstantiation of the web app - not real
1200     * graceful, but you shouldn't have reloading turned on in high load
1201     * environments.
1202     */

1203    public void resetClassLoader() throws IOException JavaDoc {
1204        this.ownerHostConfig.reloadWebApp(getContextPath());
1205    }
1206
1207    /**
1208     * Here we process url patterns into the exactMatch and patternMatch lists
1209     */

1210    private void processMapping(String JavaDoc name, String JavaDoc pattern, Map JavaDoc exactPatterns,
1211            List JavaDoc folderPatterns, List JavaDoc 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        // put the pattern in the correct list
1223
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 JavaDoc[] { name, pattern });
1234        }
1235    }
1236
1237    /**
1238     * Execute the pattern match, and try to return a servlet that matches this
1239     * URL
1240     */

1241    private ServletConfiguration urlMatch(String JavaDoc path,
1242            StringBuffer JavaDoc servletPath, StringBuffer JavaDoc pathInfo) {
1243        Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES, "WebAppConfig.URLMatch", path);
1244
1245        // Check exact matches first
1246
String JavaDoc exact = (String JavaDoc) this.exactServletMatchMounts.get(path);
1247        if (exact != null) {
1248            if (this.servletInstances.get(exact) != null) {
1249                servletPath.append(path);
1250                // pathInfo.append(""); // a hack - empty becomes null later
1251
return (ServletConfiguration) this.servletInstances.get(exact);
1252            }
1253        }
1254
1255        // Inexact mount check
1256
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        // return default servlet
1266
// servletPath.append(""); // unneeded
1267
if (this.servletInstances.get(this.defaultServletName) == null)
1268            throw new WinstoneException(Launcher.RESOURCES.getString(
1269                    "WebAppConfig.MatchedNonExistServlet",
1270                    this.defaultServletName));
1271// pathInfo.append(path);
1272
servletPath.append(path);
1273        return (ServletConfiguration) this.servletInstances.get(this.defaultServletName);
1274    }
1275
1276    /**
1277     * Constructs a session instance with the given sessionId
1278     *
1279     * @param sessionId The sessionID for the new session
1280     * @return A valid session object
1281     */

1282    public WinstoneSession makeNewSession(String JavaDoc 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    /**
1298     * Retrieves the session by id. If the web app is distributable, it asks the
1299     * other members of the cluster if it doesn't have it itself.
1300     *
1301     * @param sessionId The id of the session we want
1302     * @return A valid session instance
1303     */

1304    public WinstoneSession getSessionById(String JavaDoc 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 I'm distributable ... check remotely
1314
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    /**
1326     * Add/Remove the session from the collection
1327     */

1328    void removeSessionById(String JavaDoc sessionId) {
1329        this.sessions.remove(sessionId);
1330    }
1331    void addSession(String JavaDoc sessionId, WinstoneSession session) {
1332        this.sessions.put(sessionId, session);
1333    }
1334
1335    public void invalidateExpiredSessions() {
1336        Set JavaDoc allSessions = new HashSet JavaDoc(this.sessions.values());
1337        int expiredCount = 0;
1338        for (Iterator JavaDoc 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        // The urlMatch method will only match to non-null mappings, so we don't need
1360
// to remove anything here
1361
}
1362    
1363    /***************************************************************************
1364     *
1365     * OK ... from here to the end is the interface implementation methods for
1366     * the servletContext interface.
1367     *
1368     **************************************************************************/

1369
1370    // Application level attributes
1371
public Object JavaDoc getAttribute(String JavaDoc name) {
1372        return this.attributes.get(name);
1373    }
1374
1375    public Enumeration JavaDoc getAttributeNames() {
1376        return Collections.enumeration(this.attributes.keySet());
1377    }
1378
1379    public void removeAttribute(String JavaDoc name) {
1380        Object JavaDoc 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 JavaDoc cl = Thread.currentThread().getContextClassLoader();
1385                Thread.currentThread().setContextClassLoader(getLoader());
1386                this.contextAttributeListeners[n].attributeRemoved(
1387                        new ServletContextAttributeEvent JavaDoc(this, name, me));
1388                Thread.currentThread().setContextClassLoader(cl);
1389            }
1390    }
1391
1392    public void setAttribute(String JavaDoc name, Object JavaDoc object) {
1393        if (object == null) {
1394            removeAttribute(name);
1395        } else {
1396            Object JavaDoc 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 JavaDoc cl = Thread.currentThread().getContextClassLoader();
1401                    Thread.currentThread().setContextClassLoader(getLoader());
1402                    this.contextAttributeListeners[n].attributeReplaced(
1403                            new ServletContextAttributeEvent JavaDoc(this, name, me));
1404                    Thread.currentThread().setContextClassLoader(cl);
1405                }
1406            } else {
1407                for (int n = 0; n < this.contextAttributeListeners.length; n++) {
1408                    ClassLoader JavaDoc cl = Thread.currentThread().getContextClassLoader();
1409                    Thread.currentThread().setContextClassLoader(getLoader());
1410                    this.contextAttributeListeners[n].attributeAdded(
1411                            new ServletContextAttributeEvent JavaDoc(this, name, object));
1412                    Thread.currentThread().setContextClassLoader(cl);
1413                }
1414            }
1415        }
1416    }
1417
1418    // Application level init parameters
1419
public String JavaDoc getInitParameter(String JavaDoc name) {
1420        return (String JavaDoc) this.initParameters.get(name);
1421    }
1422
1423    public Enumeration JavaDoc getInitParameterNames() {
1424        return Collections.enumeration(this.initParameters.keySet());
1425    }
1426
1427    // Server info
1428
public String JavaDoc 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    // Weird mostly deprecated crap to do with getting servlet instances
1441
public javax.servlet.ServletContext JavaDoc getContext(String JavaDoc uri) {
1442        return this.ownerHostConfig.getWebAppByURI(uri);
1443    }
1444
1445    public String JavaDoc getServletContextName() {
1446        return this.displayName;
1447    }
1448
1449    /**
1450     * Look up the map of mimeType extensions, and return the type that matches
1451     */

1452    public String JavaDoc getMimeType(String JavaDoc fileName) {
1453        int dotPos = fileName.lastIndexOf('.');
1454        if ((dotPos != -1) && (dotPos != fileName.length() - 1)) {
1455            String JavaDoc extension = fileName.substring(dotPos + 1).toLowerCase();
1456            String JavaDoc mimeType = (String JavaDoc) this.mimeTypes.get(extension);
1457            return mimeType;
1458        } else
1459            return null;
1460    }
1461
1462    // Context level log statements
1463
public void log(String JavaDoc message) {
1464        Logger.logDirectMessage(Logger.INFO, this.contextName, message, null);
1465    }
1466
1467    public void log(String JavaDoc message, Throwable JavaDoc throwable) {
1468        Logger.logDirectMessage(Logger.ERROR, this.contextName, message, throwable);
1469    }
1470
1471    /**
1472     * Named dispatcher - this basically gets us a simple exact dispatcher (no
1473     * url matching, no request attributes and no security)
1474     */

1475    public javax.servlet.RequestDispatcher JavaDoc getNamedDispatcher(String JavaDoc 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    /**
1488     * Gets a dispatcher, which sets the request attributes, etc on a
1489     * forward/include. Doesn't execute security though.
1490     */

1491    public javax.servlet.RequestDispatcher JavaDoc getRequestDispatcher(
1492            String JavaDoc uriInsideWebapp) {
1493        if (uriInsideWebapp == null) {
1494            return null;
1495        } else if (!uriInsideWebapp.startsWith("/")) {
1496            return null;
1497        }
1498
1499        // Parse the url for query string, etc
1500
String JavaDoc 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        // Return the dispatcher
1510
StringBuffer JavaDoc servletPath = new StringBuffer JavaDoc();
1511        StringBuffer JavaDoc pathInfo = new StringBuffer JavaDoc();
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    /**
1527     * Creates the dispatcher that corresponds to a request level dispatch (ie
1528     * the initial entry point). The difference here is that we need to set up
1529     * the dispatcher so that on a forward, it executes the security checks and
1530     * the request filters, while not setting any of the request attributes for
1531     * a forward. Also, we can't return a null dispatcher in error case - instead
1532     * we have to return a dispatcher pre-init'd for showing an error page (eg 404).
1533     * A null dispatcher is interpreted to mean a successful 302 has occurred.
1534     */

1535    public RequestDispatcher getInitialDispatcher(String JavaDoc uriInsideWebapp,
1536            WinstoneRequest request, WinstoneResponse response)
1537            throws IOException JavaDoc {
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 JavaDoc sw = new StringWriter JavaDoc();
1545            PrintWriter JavaDoc pw = new PrintWriter JavaDoc(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        // Parse the url for query string, etc
1554
String JavaDoc 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        // Return the dispatcher
1563
StringBuffer JavaDoc servletPath = new StringBuffer JavaDoc();
1564        StringBuffer JavaDoc pathInfo = new StringBuffer JavaDoc();
1565        ServletConfiguration servlet = urlMatch(uriInsideWebapp, servletPath, pathInfo);
1566        if (servlet != null) {
1567            // If the default servlet was returned, we should check for welcome files
1568
if (servlet.getServletName().equals(this.defaultServletName)) {
1569                // Is path a directory ?
1570
String JavaDoc 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 JavaDoc res = new File JavaDoc(webRoot, directoryPath);
1579                if (res.exists() && res.isDirectory() &&
1580                        (request.getMethod().equals("GET") || request.getMethod().equals("HEAD"))) {
1581                    // Check for the send back with slash case
1582
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                    // Check for welcome files
1594
Logger.log(Logger.FULL_DEBUG, Launcher.RESOURCES,
1595                            "WebAppConfig.CheckWelcomeFile", servletPath.toString()
1596                                    + pathInfo.toString());
1597                    String JavaDoc welcomeFile = matchWelcomeFiles(servletPath.toString()
1598                            + pathInfo.toString(), request, queryString);
1599                    if (welcomeFile != null) {
1600                        response.sendRedirect(this.prefix + welcomeFile);
1601// + servletPath.toString()
1602
// + pathInfo.toString()
1603
// + welcomeFile
1604
// + (queryString.equals("") ? "" : "?" + queryString));
1605
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        // If we are here, return a 404
1618
return this.getErrorDispatcherByCode(HttpServletResponse.SC_NOT_FOUND,
1619                Launcher.RESOURCES.getString("StaticResourceServlet.PathNotFound",
1620                        uriInsideWebapp), null);
1621    }
1622
1623    /**
1624     * Gets a dispatcher, set up for error dispatch.
1625     */

1626    public RequestDispatcher getErrorDispatcherByClass(
1627            Throwable JavaDoc exception) {
1628
1629        // Check for exception class match
1630
Class JavaDoc exceptionClasses[] = this.errorPagesByExceptionKeysSorted;
1631        Throwable JavaDoc errWrapper = new ServletException JavaDoc(exception);
1632        
1633        while (errWrapper instanceof ServletException JavaDoc) {
1634            errWrapper = ((ServletException JavaDoc) 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 JavaDoc[] {this.errorPagesByExceptionKeysSorted[n].getName(),
1643                            errWrapper.getClass().getName()});
1644                if (exceptionClasses[n].isInstance(errWrapper)) {
1645                    String JavaDoc errorURI = (String JavaDoc) 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 JavaDoc[] {exceptionClasses[n].getName(),
1657                                    (String JavaDoc) 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        // Otherwise throw a code error
1668
Throwable JavaDoc errPassDown = exception;
1669        while ((errPassDown instanceof ServletException JavaDoc) &&
1670                (((ServletException JavaDoc) errPassDown).getRootCause() != null)) {
1671            errPassDown = ((ServletException JavaDoc) errPassDown).getRootCause();
1672        }
1673        return getErrorDispatcherByCode(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
1674                null, errPassDown);
1675    }
1676    
1677    public RequestDispatcher getErrorDispatcherByCode(
1678            int statusCode, String JavaDoc summaryMessage, Throwable JavaDoc exception) {
1679        // Check for status code match
1680
String JavaDoc errorURI = (String JavaDoc) 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        // If no dispatcher available, return a dispatcher to the default error formatter
1690
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        // Otherwise log and return null
1702
Logger.log(Logger.ERROR, Launcher.RESOURCES, "WebAppConfig.NoErrorServlet", "" + statusCode, exception);
1703        return null;
1704    }
1705
1706    /**
1707     * Build a dispatcher to the error handler if it's available. If it fails, return null.
1708     */

1709    private RequestDispatcher buildErrorDispatcher(String JavaDoc errorURI, int statusCode,
1710            String JavaDoc summaryMessage, Throwable JavaDoc exception) {
1711        // Parse the url for query string, etc
1712
String JavaDoc 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        // Get the message by recursing if none supplied
1722
ServletException JavaDoc errIterator = new ServletException JavaDoc(exception);
1723        while ((summaryMessage == null) && (errIterator != null)) {
1724            summaryMessage = errIterator.getMessage();
1725            if (errIterator.getRootCause() instanceof ServletException JavaDoc) {
1726                errIterator = (ServletException JavaDoc) errIterator.getRootCause();
1727            } else {
1728                if (summaryMessage == null) {
1729                    summaryMessage = errIterator.getRootCause().getMessage();
1730                }
1731                errIterator = null;
1732            }
1733        }
1734
1735        // Return the dispatcher
1736
StringBuffer JavaDoc servletPath = new StringBuffer JavaDoc();
1737        StringBuffer JavaDoc pathInfo = new StringBuffer JavaDoc();
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    /**
1753     * Check if any of the welcome files under this path are available. Returns the
1754     * name of the file if found, null otherwise. Returns the full internal webapp uri
1755     */

1756    private String JavaDoc matchWelcomeFiles(String JavaDoc path, WinstoneRequest request, String JavaDoc queryString) {
1757        if (!path.endsWith("/")) {
1758            path = path + "/";
1759        }
1760
1761        String JavaDoc qs = (queryString.equals("") ? "" : "?" + queryString);
1762        for (int n = 0; n < this.welcomeFiles.length; n++) {
1763            String JavaDoc welcomeFile = this.welcomeFiles[n];
1764            while (welcomeFile.startsWith("/")) {
1765                welcomeFile = welcomeFile.substring(1);
1766            }
1767            welcomeFile = path + welcomeFile;
1768            
1769            String JavaDoc exact = (String JavaDoc) this.exactServletMatchMounts.get(welcomeFile);
1770            if (exact != null) {
1771                return welcomeFile + qs;
1772            }
1773
1774            // Inexact folder mount check - note folder mounts only
1775
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 JavaDoc err) {}
1788        }
1789        return null;
1790    }
1791
1792    // Getting resources via the classloader
1793
public URL JavaDoc getResource(String JavaDoc path) throws MalformedURLException JavaDoc {
1794        if (path == null) {
1795            return null;
1796        } else if (!path.startsWith("/")) {
1797            throw new MalformedURLException JavaDoc(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 JavaDoc res = new File JavaDoc(webRoot, path.substring(1));
1803        return (res != null) && res.exists() ? res.toURL() : null;
1804    }
1805
1806    public InputStream JavaDoc getResourceAsStream(String JavaDoc path) {
1807        try {
1808            URL JavaDoc res = getResource(path);
1809            return res == null ? null : res.openStream();
1810        } catch (IOException JavaDoc err) {
1811            throw new WinstoneException(Launcher.RESOURCES
1812                    .getString("WebAppConfig.ErrorOpeningStream"), err);
1813        }
1814    }
1815
1816    public String JavaDoc getRealPath(String JavaDoc path) {
1817        // Trim the prefix
1818
if (path == null)
1819            return null;
1820        else {
1821            try {
1822                File JavaDoc res = new File JavaDoc(this.webRoot, path);
1823                if (res.isDirectory())
1824                    return res.getCanonicalPath() + "/";
1825                else
1826                    return res.getCanonicalPath();
1827            } catch (IOException JavaDoc err) {
1828                return null;
1829            }
1830        }
1831    }
1832
1833    public Set JavaDoc getResourcePaths(String JavaDoc path) {
1834        // Trim the prefix
1835
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 JavaDoc 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 JavaDoc inPath = new File JavaDoc(this.webRoot, workingPath.equals("") ? "."
1850                    : workingPath).getAbsoluteFile();
1851            if (!inPath.exists())
1852                return null;
1853            else if (!inPath.isDirectory())
1854                return null;
1855
1856            // Find all the files in this folder
1857
File JavaDoc children[] = inPath.listFiles();
1858            Set JavaDoc out = new HashSet JavaDoc();
1859            for (int n = 0; n < children.length; n++) {
1860                // Write the entry as subpath + child element
1861
String JavaDoc entry = //this.prefix +
1862
"/" + (workingPath.length() != 0 ? workingPath + "/" : "")
1863                        + children[n].getName()
1864                        + (children[n].isDirectory() ? "/" : "");
1865                out.add(entry);
1866            }
1867            return out;
1868        }
1869    }
1870
1871    /**
1872     * @deprecated
1873     */

1874    public javax.servlet.Servlet JavaDoc getServlet(String JavaDoc name) {
1875        return null;
1876    }
1877
1878    /**
1879     * @deprecated
1880     */

1881    public Enumeration JavaDoc getServletNames() {
1882        return Collections.enumeration(new ArrayList JavaDoc());
1883    }
1884
1885    /**
1886     * @deprecated
1887     */

1888    public Enumeration JavaDoc getServlets() {
1889        return Collections.enumeration(new ArrayList JavaDoc());
1890    }
1891
1892    /**
1893     * @deprecated
1894     */

1895    public void log(Exception JavaDoc exception, String JavaDoc msg) {
1896        this.log(msg, exception);
1897    }
1898
1899}
1900
Popular Tags