View Javadoc

1   // ========================================================================
2   // Copyright (c) 2009 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at 
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses. 
12  // ========================================================================
13  
14  package org.eclipse.jetty.webapp;
15  
16  import java.io.File;
17  import java.lang.reflect.Method;
18  import java.net.URL;
19  import java.util.ArrayList;
20  import java.util.EventListener;
21  import java.util.HashMap;
22  import java.util.HashSet;
23  import java.util.Iterator;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.Set;
27  
28  import javax.servlet.Servlet;
29  import javax.servlet.UnavailableException;
30  
31  import org.eclipse.jetty.http.security.Constraint;
32  import org.eclipse.jetty.security.ConstraintAware;
33  import org.eclipse.jetty.security.ConstraintMapping;
34  import org.eclipse.jetty.security.SecurityHandler;
35  import org.eclipse.jetty.security.authentication.FormAuthenticator;
36  import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
37  import org.eclipse.jetty.servlet.FilterHolder;
38  import org.eclipse.jetty.servlet.FilterMapping;
39  import org.eclipse.jetty.servlet.ServletHandler;
40  import org.eclipse.jetty.servlet.ServletHolder;
41  import org.eclipse.jetty.servlet.ServletMapping;
42  import org.eclipse.jetty.util.LazyList;
43  import org.eclipse.jetty.util.Loader;
44  import org.eclipse.jetty.util.log.Log;
45  import org.eclipse.jetty.util.resource.Resource;
46  import org.eclipse.jetty.xml.XmlParser;
47  
48  
49  
50  /**
51   * WebXmlProcessor
52   *
53   */
54  public class WebXmlProcessor
55  {
56      public static final String WEB_PROCESSOR = "org.eclipse.jetty.webProcessor";
57      public static final String METADATA_COMPLETE = "org.eclipse.jetty.metadataComplete";
58      public static final String WEBXML_VERSION = "org.eclipse.jetty.webXmlVersion";
59      public static final String WEBXML_CLASSNAMES = "org.eclipse.jetty.webXmlClassNames";
60      
61      protected WebAppContext _context;
62      protected XmlParser _xmlParser;
63      protected Descriptor _webDefaultsRoot;
64      protected Descriptor _webXmlRoot;
65      protected List<Descriptor> _webFragmentRoots = new ArrayList<Descriptor>();   
66      protected Descriptor _webOverrideRoot;
67      
68      protected ServletHandler _servletHandler;
69      protected SecurityHandler _securityHandler;
70      protected Object _filters; 
71      protected Object _filterMappings;
72      protected Object _servlets;
73      protected Object _servletMappings;
74      protected Object _listeners;
75      protected Object _welcomeFiles;
76      protected Set<String> _newRoles = new HashSet<String>();
77      protected List<ConstraintMapping> _newConstraintMappings;
78      protected Map _errorPages;
79      protected boolean _hasJSP;
80      protected String _jspServletName;
81      protected String _jspServletClass;
82      protected boolean _defaultWelcomeFileList;
83     
84  
85      public class Descriptor
86      {
87          protected Resource _xml;
88          protected XmlParser.Node _root;
89          protected boolean _metadataComplete;
90          protected boolean _hasOrdering;
91          protected int _version;
92          protected ArrayList<String> _classNames;
93          
94          public Descriptor (Resource xml)
95          {
96              _xml = xml;
97          }
98          
99          public void parse ()
100         throws Exception
101         {
102             if (_root == null)
103             {
104                 _root = _xmlParser.parse(_xml.getURL().toString());
105                 processVersion();
106                 processOrdering();
107             }
108         }
109         
110         public boolean isMetaDataComplete()
111         {
112             return _metadataComplete;
113         }
114         
115         
116         public XmlParser.Node getRoot ()
117         {
118             return _root;
119         }
120         
121         public int getVersion ()
122         {
123             return _version;
124         }
125         
126         public Resource getResource ()
127         {
128             return _xml;
129         }
130         
131         public void process()
132         throws Exception
133         {
134             WebXmlProcessor.this.process(_root);
135         }
136         
137         private void processVersion ()
138         {
139             String version = _root.getAttribute("version", "DTD");
140             if ("2.5".equals(version))
141                 _version = 25;
142             else if ("2.4".equals(version))
143                 _version = 24;
144             else if ("3.0".equals(version))
145                 _version = 30;
146             else if ("DTD".equals(version))
147             {
148                 _version = 23;
149                 String dtd = _xmlParser.getDTD();
150                 if (dtd != null && dtd.indexOf("web-app_2_2") >= 0) _version = 22;
151             }
152 
153             if (_version < 25)
154                 _metadataComplete = true; // does not apply before 2.5
155             else
156                 _metadataComplete = Boolean.valueOf((String)_root.getAttribute("metadata-complete", "false")).booleanValue();
157 
158             Log.debug(_xml.toString()+": Calculated metadatacomplete = " + _metadataComplete + " with version=" + version);     
159         }
160         
161         private void processOrdering ()
162         {
163             //TODO
164         }
165         
166         private void processClassNames ()
167         {
168             _classNames = new ArrayList<String>();          
169             Iterator iter = _root.iterator();
170 
171             while (iter.hasNext())
172             {
173                 Object o = iter.next();
174                 if (!(o instanceof XmlParser.Node)) continue;
175                 XmlParser.Node node = (XmlParser.Node) o;
176                 String name = node.getTag();
177                 if ("servlet".equals(name))
178                 {
179                     String className = node.getString("servlet-class", false, true);
180                     if (className != null)
181                         _classNames.add(className);
182                 }
183                 else if ("filter".equals(name))
184                 {
185                     String className = node.getString("filter-class", false, true);
186                     if (className != null)
187                         _classNames.add(className);
188                 }
189                 else if ("listener".equals(name))
190                 {
191                     String className = node.getString("listener-class", false, true);
192                     if (className != null)
193                         _classNames.add(className);
194                 }                    
195             }
196         }
197         
198         public ArrayList<String> getClassNames ()
199         {
200             return _classNames;
201         }
202     }
203     
204   
205     
206     
207     public static XmlParser webXmlParser() throws ClassNotFoundException
208     {
209         XmlParser xmlParser=new XmlParser();
210         //set up cache of DTDs and schemas locally        
211         URL dtd22=Loader.getResource(Servlet.class,"javax/servlet/resources/web-app_2_2.dtd",true);
212         URL dtd23=Loader.getResource(Servlet.class,"javax/servlet/resources/web-app_2_3.dtd",true);
213         URL j2ee14xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/j2ee_1_4.xsd",true);
214         URL webapp24xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/web-app_2_4.xsd",true);
215         URL webapp25xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/web-app_2_5.xsd",true);
216         URL webapp30xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/web-app_3_0.xsd",true);
217         URL webcommon30xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/web-common_3_0.xsd",true);
218         URL webfragment30xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/web-fragment_3_0.xsd",true);
219         URL schemadtd=Loader.getResource(Servlet.class,"javax/servlet/resources/XMLSchema.dtd",true);
220         URL xmlxsd=Loader.getResource(Servlet.class,"javax/servlet/resources/xml.xsd",true);
221         URL webservice11xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/j2ee_web_services_client_1_1.xsd",true);
222         URL webservice12xsd=Loader.getResource(Servlet.class,"javax/servlet/resources/javaee_web_services_client_1_2.xsd",true);
223         URL datatypesdtd=Loader.getResource(Servlet.class,"javax/servlet/resources/datatypes.dtd",true);
224 
225         URL jsp20xsd = null;
226         URL jsp21xsd = null;
227 
228         try
229         {
230             Class jsp_page = Loader.loadClass(WebXmlConfiguration.class, "javax.servlet.jsp.JspPage");
231             jsp20xsd = jsp_page.getResource("/javax/servlet/resources/jsp_2_0.xsd");
232             jsp21xsd = jsp_page.getResource("/javax/servlet/resources/jsp_2_1.xsd");
233         }
234         catch (Exception e)
235         {
236             Log.ignore(e);
237         }
238         finally
239         {
240             if (jsp20xsd == null) jsp20xsd = Loader.getResource(Servlet.class, "javax/servlet/resources/jsp_2_0.xsd", true);
241             if (jsp21xsd == null) jsp21xsd = Loader.getResource(Servlet.class, "javax/servlet/resources/jsp_2_1.xsd", true);
242         }
243         
244         redirect(xmlParser,"web-app_2_2.dtd",dtd22);
245         redirect(xmlParser,"-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN",dtd22);
246         redirect(xmlParser,"web.dtd",dtd23);
247         redirect(xmlParser,"web-app_2_3.dtd",dtd23);
248         redirect(xmlParser,"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN",dtd23);
249         redirect(xmlParser,"XMLSchema.dtd",schemadtd);
250         redirect(xmlParser,"http://www.w3.org/2001/XMLSchema.dtd",schemadtd);
251         redirect(xmlParser,"-//W3C//DTD XMLSCHEMA 200102//EN",schemadtd);
252         redirect(xmlParser,"jsp_2_0.xsd",jsp20xsd);
253         redirect(xmlParser,"http://java.sun.com/xml/ns/j2ee/jsp_2_0.xsd",jsp20xsd);
254         redirect(xmlParser,"jsp_2_1.xsd",jsp21xsd);
255         redirect(xmlParser,"http://java.sun.com/xml/ns/javaee/jsp_2_1.xsd",jsp21xsd);
256         redirect(xmlParser,"j2ee_1_4.xsd",j2ee14xsd);
257         redirect(xmlParser,"http://java.sun.com/xml/ns/j2ee/j2ee_1_4.xsd",j2ee14xsd);
258         redirect(xmlParser,"web-app_2_4.xsd",webapp24xsd);
259         redirect(xmlParser,"http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd",webapp24xsd);
260         redirect(xmlParser,"web-app_2_5.xsd",webapp25xsd);
261         redirect(xmlParser,"http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd",webapp25xsd);
262         redirect(xmlParser,"web-app_3_0.xsd",webapp30xsd);
263         redirect(xmlParser,"http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd",webapp30xsd);
264         redirect(xmlParser,"web-common_3_0.xsd",webcommon30xsd);
265         redirect(xmlParser,"http://java.sun.com/xml/ns/javaee/web-common_3_0.xsd",webcommon30xsd);
266         redirect(xmlParser,"web-fragment_3_0.xsd",webfragment30xsd);
267         redirect(xmlParser,"http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd",webfragment30xsd);
268         redirect(xmlParser,"xml.xsd",xmlxsd);
269         redirect(xmlParser,"http://www.w3.org/2001/xml.xsd",xmlxsd);
270         redirect(xmlParser,"datatypes.dtd",datatypesdtd);
271         redirect(xmlParser,"http://www.w3.org/2001/datatypes.dtd",datatypesdtd);
272         redirect(xmlParser,"j2ee_web_services_client_1_1.xsd",webservice11xsd);
273         redirect(xmlParser,"http://www.ibm.com/webservices/xsd/j2ee_web_services_client_1_1.xsd",webservice11xsd);
274         redirect(xmlParser,"javaee_web_services_client_1_2.xsd",webservice12xsd);
275         redirect(xmlParser,"http://www.ibm.com/webservices/xsd/javaee_web_services_client_1_2.xsd",webservice12xsd);
276         
277         return xmlParser;
278     }
279 
280     /* ------------------------------------------------------------------------------- */
281     protected static void redirect(XmlParser parser, String resource, URL source)
282     {
283         if (source != null) parser.redirectEntity(resource, source);
284     }
285     
286     
287     public WebXmlProcessor (WebAppContext context) throws ClassNotFoundException
288     {
289         _context = context;
290         _xmlParser = webXmlParser();
291     }
292     
293     public void parseDefaults (Resource webDefaults)
294     throws Exception
295     {
296         _webDefaultsRoot =  new Descriptor(webDefaults); 
297         _webDefaultsRoot.parse();
298     }
299     
300     public void parseWebXml (Resource webXml)
301     throws Exception
302     {
303         _webXmlRoot = new Descriptor(webXml);
304         _webXmlRoot.parse();
305         _webXmlRoot.processClassNames();
306         _context.setAttribute(METADATA_COMPLETE, Boolean.valueOf(_webXmlRoot.isMetaDataComplete()));
307         _context.setAttribute(WEBXML_VERSION, Integer.valueOf(_webXmlRoot.getVersion()));
308         _context.setAttribute(WEBXML_CLASSNAMES, _webXmlRoot.getClassNames());
309     }
310     
311     public void parseFragment (Resource fragment)
312     throws Exception
313     {
314         if (_webXmlRoot.isMetaDataComplete())
315             return; //do not process anything else if main web.xml file is complete
316         
317         //Metadata-complete is not set, or there is no web.xml
318         Descriptor frag = new Descriptor(fragment);
319         frag.parse();
320         _webFragmentRoots.add(frag);
321     }
322     
323     public void parseOverride (Resource override)
324     throws Exception
325     {
326         _xmlParser.setValidating(false);
327         _webOverrideRoot = new Descriptor(override);
328         _webOverrideRoot.parse();
329     }
330     
331     
332     public void processDefaults ()
333     throws Exception
334     {
335         _webDefaultsRoot.process();
336         _defaultWelcomeFileList = _context.getWelcomeFiles() != null;   
337     }
338     
339     public void processWebXml ()
340     throws Exception
341     {
342         if (_webXmlRoot!=null)
343             _webXmlRoot.process();
344     }
345     
346     public void processFragments ()
347     throws Exception
348     {
349         for (Descriptor frag : _webFragmentRoots)
350         {
351             frag.process();
352         }
353     }
354     
355     public void processOverride ()
356     throws Exception
357     {
358         _webOverrideRoot.process();
359     }
360     
361     public Descriptor getWebXml ()
362     {
363         return _webXmlRoot;
364     }
365     
366     public Descriptor getOverrideWeb ()
367     {
368         return _webOverrideRoot;
369     }
370     
371     public Descriptor getWebDefault ()
372     {
373         return _webDefaultsRoot;
374     }
375     
376     public List<Descriptor> getFragments ()
377     {
378         return _webFragmentRoots;
379     }
380     
381     
382     public void process (XmlParser.Node config)
383     throws Exception
384     {
385        
386         //Get the current objects from the context
387         _servletHandler = _context.getServletHandler();
388         _securityHandler = (SecurityHandler)_context.getSecurityHandler();
389         _filters = LazyList.array2List(_servletHandler.getFilters());
390         _filterMappings = LazyList.array2List(_servletHandler.getFilterMappings());
391         _servlets = LazyList.array2List(_servletHandler.getServlets());
392         _servletMappings = LazyList.array2List(_servletHandler.getServletMappings());
393         _listeners = LazyList.array2List(_context.getEventListeners());
394         _welcomeFiles = LazyList.array2List(_context.getWelcomeFiles());
395         
396         _newConstraintMappings=new ArrayList<ConstraintMapping>();
397         _newRoles=new HashSet<String>();
398         
399        _errorPages = _context.getErrorHandler() instanceof ErrorPageErrorHandler ? ((ErrorPageErrorHandler)_context.getErrorHandler()).getErrorPages() : null; 
400        
401         Iterator iter = config.iterator();
402         XmlParser.Node node = null;
403         while (iter.hasNext())
404         {
405             try
406             {
407                 Object o = iter.next();
408                 if (!(o instanceof XmlParser.Node)) continue;
409                 node = (XmlParser.Node) o;
410                 String name = node.getTag();
411                 initWebXmlElement(name, node);
412             }
413             catch (ClassNotFoundException e)
414             {
415                 throw e;
416             }
417             catch (Exception e)
418             {
419                 Log.warn("Configuration problem at " + node, e);
420                 throw new UnavailableException("Configuration problem");
421             }
422         }
423 
424         //Set the context with the results of the processing
425         _servletHandler.setFilters((FilterHolder[]) LazyList.toArray(_filters, FilterHolder.class));
426         _servletHandler.setFilterMappings((FilterMapping[]) LazyList.toArray(_filterMappings, FilterMapping.class));
427         _servletHandler.setServlets((ServletHolder[]) LazyList.toArray(_servlets, ServletHolder.class));
428         _servletHandler.setServletMappings((ServletMapping[]) LazyList.toArray(_servletMappings, ServletMapping.class));
429         _context.setEventListeners((EventListener[]) LazyList.toArray(_listeners, EventListener.class));
430         _context.setWelcomeFiles((String[]) LazyList.toArray(_welcomeFiles, String.class));
431         // TODO jaspi check this
432         if (_securityHandler instanceof ConstraintAware)
433         {
434             for (String role : _newRoles)
435                 ((ConstraintAware)_securityHandler).addRole(role);
436             for (ConstraintMapping mapping : _newConstraintMappings)
437                 ((ConstraintAware)_securityHandler).addConstraintMapping(mapping);
438         }
439 
440         if (_errorPages != null && _context.getErrorHandler() instanceof ErrorPageErrorHandler)
441             ((ErrorPageErrorHandler)_context.getErrorHandler()).setErrorPages(_errorPages);
442     }
443     
444 
445   
446     
447     /* ------------------------------------------------------------ */
448     /**
449      * Handle web.xml element. This method is called for each top level element
450      * within the web.xml file. It may be specialized by derived WebAppHandlers
451      * to provide additional configuration and handling.
452      * 
453      * @param element The element name
454      * @param node The node containing the element.
455      */
456     protected void initWebXmlElement(String element, XmlParser.Node node) throws Exception
457     {
458         if ("display-name".equals(element))
459             initDisplayName(node);
460         else if ("description".equals(element))
461         {
462         }
463         else if ("context-param".equals(element))
464             initContextParam(node);
465         else if ("servlet".equals(element))
466             initServlet(node);
467         else if ("servlet-mapping".equals(element))
468             initServletMapping(node);
469         else if ("session-config".equals(element))
470             initSessionConfig(node);
471         else if ("mime-mapping".equals(element))
472             initMimeConfig(node);
473         else if ("welcome-file-list".equals(element))
474             initWelcomeFileList(node);
475         else if ("locale-encoding-mapping-list".equals(element))
476             initLocaleEncodingList(node);
477         else if ("error-page".equals(element))
478             initErrorPage(node);
479         else if ("taglib".equals(element))
480             initTagLib(node);
481         else if ("jsp-config".equals(element))
482             initJspConfig(node);
483         else if ("resource-ref".equals(element))
484         {
485             if (Log.isDebugEnabled()) Log.debug("No implementation: " + node);
486         }
487         else if ("security-constraint".equals(element))
488             initSecurityConstraint(node);
489         else if ("login-config".equals(element))
490             initLoginConfig(node);
491         else if ("security-role".equals(element))
492             initSecurityRole(node);
493         else if ("filter".equals(element))
494             initFilter(node);
495         else if ("filter-mapping".equals(element))
496             initFilterMapping(node);
497         else if ("listener".equals(element))
498             initListener(node);
499         else if ("distributable".equals(element))
500             initDistributable(node);
501         else if ("web-fragment".equals(element))
502         {
503         }
504         else
505         {
506             if (Log.isDebugEnabled())
507             {
508                 Log.debug("Element {} not handled in {}", element, this);
509                 Log.debug(node.toString());
510             }
511         }
512     }
513 
514     /* ------------------------------------------------------------ */
515     protected void initDisplayName(XmlParser.Node node)
516     {
517         _context.setDisplayName(node.toString(false, true));
518     }
519 
520     /* ------------------------------------------------------------ */
521     protected void initContextParam(XmlParser.Node node)
522     {
523         String name = node.getString("param-name", false, true);
524         String value = node.getString("param-value", false, true);
525         if (Log.isDebugEnabled()) Log.debug("ContextParam: " + name + "=" + value);
526         _context.getInitParams().put(name, value);
527     }
528 
529     /* ------------------------------------------------------------ */
530     protected void initFilter(XmlParser.Node node)
531     {
532         String name = node.getString("filter-name", false, true);
533         FilterHolder holder = _servletHandler.getFilter(name);
534         if (holder == null)
535         {
536             holder = _servletHandler.newFilterHolder();
537             holder.setName(name);
538             _filters = LazyList.add(_filters, holder);
539         }
540 
541         String filter_class = node.getString("filter-class", false, true);
542         if (filter_class != null) holder.setClassName(filter_class);
543 
544         Iterator iter = node.iterator("init-param");
545         while (iter.hasNext())
546         {
547             XmlParser.Node paramNode = (XmlParser.Node) iter.next();
548             String pname = paramNode.getString("param-name", false, true);
549             String pvalue = paramNode.getString("param-value", false, true);
550             holder.setInitParameter(pname, pvalue);
551         }
552 
553         String async=node.getString("async-supported",false,true);
554         if (async!=null)
555             holder.setAsyncSupported(async.length()==0||Boolean.valueOf(async));
556         
557         String timeout=node.getString("async-timeout",false,true);
558         // TODO set it
559     }
560 
561     /* ------------------------------------------------------------ */
562     protected void initFilterMapping(XmlParser.Node node)
563     {
564         String filter_name = node.getString("filter-name", false, true);
565 
566         FilterMapping mapping = new FilterMapping();
567 
568         mapping.setFilterName(filter_name);
569 
570         ArrayList paths = new ArrayList();
571         Iterator iter = node.iterator("url-pattern");
572         while (iter.hasNext())
573         {
574             String p = ((XmlParser.Node) iter.next()).toString(false, true);
575             p = normalizePattern(p);
576             paths.add(p);
577         }
578         mapping.setPathSpecs((String[]) paths.toArray(new String[paths.size()]));
579 
580         ArrayList names = new ArrayList();
581         iter = node.iterator("servlet-name");
582         while (iter.hasNext())
583         {
584             String n = ((XmlParser.Node) iter.next()).toString(false, true);
585             names.add(n);
586         }
587         mapping.setServletNames((String[]) names.toArray(new String[names.size()]));
588 
589         int dispatcher=FilterMapping.DEFAULT;
590         iter=node.iterator("dispatcher");
591         while(iter.hasNext())
592         {
593             String d=((XmlParser.Node)iter.next()).toString(false,true);
594             dispatcher|=FilterMapping.dispatch(d);
595         }
596         mapping.setDispatches(dispatcher);
597 
598         _filterMappings = LazyList.add(_filterMappings, mapping);
599     }
600 
601     /* ------------------------------------------------------------ */
602     protected String normalizePattern(String p)
603     {
604         if (p != null && p.length() > 0 && !p.startsWith("/") && !p.startsWith("*")) return "/" + p;
605         return p;
606     }
607 
608     /* ------------------------------------------------------------ */
609     protected void initServlet(XmlParser.Node node)
610     {
611         String id = node.getAttribute("id");
612 
613         // initialize holder
614         String servlet_name = node.getString("servlet-name", false, true);
615         ServletHolder holder = _servletHandler.getServlet(servlet_name);
616         if (holder == null)
617         {
618             holder = _servletHandler.newServletHolder();
619             holder.setName(servlet_name);
620             _servlets = LazyList.add(_servlets, holder);
621         }
622 
623         // init params
624         Iterator iParamsIter = node.iterator("init-param");
625         while (iParamsIter.hasNext())
626         {
627             XmlParser.Node paramNode = (XmlParser.Node) iParamsIter.next();
628             String pname = paramNode.getString("param-name", false, true);
629             String pvalue = paramNode.getString("param-value", false, true);
630             holder.setInitParameter(pname, pvalue);
631         }
632 
633         String servlet_class = node.getString("servlet-class", false, true);
634 
635         // Handle JSP
636         if (id != null && id.equals("jsp"))
637         {
638             _jspServletName = servlet_name;
639             _jspServletClass = servlet_class;
640             try
641             {
642                 Loader.loadClass(this.getClass(), servlet_class);
643                 _hasJSP = true;
644             }
645             catch (ClassNotFoundException e)
646             {
647                 Log.info("NO JSP Support for {}, did not find {}", _context.getContextPath(), servlet_class);
648                 _hasJSP = false;
649                 _jspServletClass = servlet_class = "org.eclipse.jetty.servlet.NoJspServlet";
650             }
651             
652             // set the JSP log
653             if (_hasJSP)
654             {
655                 try
656                 {
657                     Class<?> logFactory = Loader.loadClass(this.getClass(),"org.eclipse.jetty.jsp.JettyLog");
658                     Method init = logFactory.getMethod("init");
659                     Log.debug("Init JSP loggging "+init);
660                     init.invoke(null);
661                 }
662                 catch (Exception e)
663                 {
664                     Log.warn(e.toString());
665                     Log.ignore(e);
666                 }       
667             }
668             
669             if (holder.getInitParameter("scratchdir") == null)
670             {
671                 File tmp = _context.getTempDirectory();
672                 File scratch = new File(tmp, "jsp");
673                 if (!scratch.exists()) scratch.mkdir();
674                 holder.setInitParameter("scratchdir", scratch.getAbsolutePath());
675 
676                 if ("?".equals(holder.getInitParameter("classpath")))
677                 {
678                     String classpath = _context.getClassPath();
679                     Log.debug("classpath=" + classpath);
680                     if (classpath != null) holder.setInitParameter("classpath", classpath);
681                 }
682             }
683         }
684         if (servlet_class != null) holder.setClassName(servlet_class);
685 
686         // Handler JSP file
687         String jsp_file = node.getString("jsp-file", false, true);
688         if (jsp_file != null)
689         {
690             holder.setForcedPath(jsp_file);
691             holder.setClassName(_jspServletClass);
692         }
693 
694         // handle startup
695         XmlParser.Node startup = node.get("load-on-startup");
696         if (startup != null)
697         {
698             String s = startup.toString(false, true).toLowerCase();
699             if (s.startsWith("t"))
700             {
701                 Log.warn("Deprecated boolean load-on-startup.  Please use integer");
702                 holder.setInitOrder(1);
703             }
704             else
705             {
706                 int order = 0;
707                 try
708                 {
709                     if (s != null && s.trim().length() > 0) order = Integer.parseInt(s);
710                 }
711                 catch (Exception e)
712                 {
713                     Log.warn("Cannot parse load-on-startup " + s + ". Please use integer");
714                     Log.ignore(e);
715                 }
716                 holder.setInitOrder(order);
717             }
718         }
719 
720         Iterator sRefsIter = node.iterator("security-role-ref");
721         while (sRefsIter.hasNext())
722         {
723             XmlParser.Node securityRef = (XmlParser.Node) sRefsIter.next();
724             String roleName = securityRef.getString("role-name", false, true);
725             String roleLink = securityRef.getString("role-link", false, true);
726             if (roleName != null && roleName.length() > 0 && roleLink != null && roleLink.length() > 0)
727             {
728                 if (Log.isDebugEnabled()) Log.debug("link role " + roleName + " to " + roleLink + " for " + this);
729                 holder.setUserRoleLink(roleName, roleLink);
730             }
731             else
732             {
733                 Log.warn("Ignored invalid security-role-ref element: " + "servlet-name=" + holder.getName() + ", " + securityRef);
734             }
735         }
736 
737         XmlParser.Node run_as = node.get("run-as");
738         if (run_as != null)
739         {
740             String roleName = run_as.getString("role-name", false, true);
741             if (roleName != null)
742                 holder.setRunAsRole(roleName);
743         }
744 
745         String async=node.getString("async-supported",false,true);
746         if (async!=null)
747             holder.setAsyncSupported(async.length()==0||Boolean.valueOf(async));
748 
749         String timeout=node.getString("async-timeout",false,true);
750         // TODO set it
751     }
752 
753     /* ------------------------------------------------------------ */
754     protected void initServletMapping(XmlParser.Node node)
755     {
756         String servlet_name = node.getString("servlet-name", false, true);
757         ServletMapping mapping = new ServletMapping();
758         mapping.setServletName(servlet_name);
759 
760         ArrayList paths = new ArrayList();
761         Iterator iter = node.iterator("url-pattern");
762         while (iter.hasNext())
763         {
764             String p = ((XmlParser.Node) iter.next()).toString(false, true);
765             p = normalizePattern(p);
766             paths.add(p);
767         }
768         mapping.setPathSpecs((String[]) paths.toArray(new String[paths.size()]));
769 
770         _servletMappings = LazyList.add(_servletMappings, mapping);
771     }
772 
773     /* ------------------------------------------------------------ */
774     protected void initListener(XmlParser.Node node)
775     {
776         String className = node.getString("listener-class", false, true);
777         Object listener = null;
778         try
779         {
780             Class listenerClass = _context.loadClass(className);
781             listener = newListenerInstance(listenerClass);
782             if (!(listener instanceof EventListener))
783             {
784                 Log.warn("Not an EventListener: " + listener);
785                 return;
786             }
787             _listeners = LazyList.add(_listeners, listener);
788         }
789         catch (Exception e)
790         {
791             Log.warn("Could not instantiate listener " + className, e);
792             return;
793         }
794     }
795 
796     /* ------------------------------------------------------------ */
797     protected Object newListenerInstance(Class clazz) throws InstantiationException, IllegalAccessException
798     {
799         return clazz.newInstance();
800     }
801 
802     /* ------------------------------------------------------------ */
803     protected void initDistributable(XmlParser.Node node)
804     {
805         // the element has no content, so its simple presence
806         // indicates that the webapp is distributable...
807         if (!_context.isDistributable()) 
808             _context.setDistributable(true);
809     }
810 
811     /* ------------------------------------------------------------ */
812     protected void initSessionConfig(XmlParser.Node node)
813     {
814         XmlParser.Node tNode = node.get("session-timeout");
815         if (tNode != null)
816         {
817             int timeout = Integer.parseInt(tNode.toString(false, true));
818             _context.getSessionHandler().getSessionManager().setMaxInactiveInterval(timeout * 60);
819         }
820     }
821 
822     /* ------------------------------------------------------------ */
823     protected void initMimeConfig(XmlParser.Node node)
824     {
825         String extension = node.getString("extension", false, true);
826         if (extension != null && extension.startsWith(".")) extension = extension.substring(1);
827         String mimeType = node.getString("mime-type", false, true);
828         _context.getMimeTypes().addMimeMapping(extension, mimeType);
829     }
830 
831     /* ------------------------------------------------------------ */
832     protected void initWelcomeFileList(XmlParser.Node node)
833     {
834         if (_defaultWelcomeFileList) 
835             _welcomeFiles = null; // erase welcome files from default web.xml
836 
837         _defaultWelcomeFileList = false;
838         Iterator iter = node.iterator("welcome-file");
839         while (iter.hasNext())
840         {
841             XmlParser.Node indexNode = (XmlParser.Node) iter.next();
842             String welcome = indexNode.toString(false, true);
843             _welcomeFiles = LazyList.add(_welcomeFiles, welcome);
844         }
845     }
846 
847     /* ------------------------------------------------------------ */
848     protected void initLocaleEncodingList(XmlParser.Node node)
849     {
850         Iterator iter = node.iterator("locale-encoding-mapping");
851         while (iter.hasNext())
852         {
853             XmlParser.Node mapping = (XmlParser.Node) iter.next();
854             String locale = mapping.getString("locale", false, true);
855             String encoding = mapping.getString("encoding", false, true);
856             _context.addLocaleEncoding(locale, encoding);
857         }
858     }
859 
860     /* ------------------------------------------------------------ */
861     protected void initErrorPage(XmlParser.Node node)
862     {
863         String error = node.getString("error-code", false, true);
864         if (error == null || error.length() == 0) error = node.getString("exception-type", false, true);
865         String location = node.getString("location", false, true);
866 
867         if (_errorPages == null)
868             _errorPages = new HashMap();
869         _errorPages.put(error, location);
870     }
871 
872     /* ------------------------------------------------------------ */
873     protected void initTagLib(XmlParser.Node node)
874     {
875         String uri = node.getString("taglib-uri", false, true);
876         String location = node.getString("taglib-location", false, true);
877 
878         _context.setResourceAlias(uri, location);
879     }
880 
881     /* ------------------------------------------------------------ */
882     protected void initJspConfig(XmlParser.Node node)
883     {
884         for (int i = 0; i < node.size(); i++)
885         {
886             Object o = node.get(i);
887             if (o instanceof XmlParser.Node && "taglib".equals(((XmlParser.Node) o).getTag())) initTagLib((XmlParser.Node) o);
888         }
889 
890         // Map URLs from jsp property groups to JSP servlet.
891         // this is more JSP stupidness creaping into the servlet spec
892         Iterator iter = node.iterator("jsp-property-group");
893         Object paths = null;
894         while (iter.hasNext())
895         {
896             XmlParser.Node group = (XmlParser.Node) iter.next();
897             Iterator iter2 = group.iterator("url-pattern");
898             while (iter2.hasNext())
899             {
900                 String url = ((XmlParser.Node) iter2.next()).toString(false, true);
901                 url = normalizePattern(url);
902                 paths = LazyList.add(paths, url);
903             }
904         }
905 
906         if (LazyList.size(paths) > 0)
907         {
908             String jspName = getJSPServletName();
909             if (jspName != null)
910             {
911                 ServletMapping mapping = new ServletMapping();
912                 mapping.setServletName(jspName);
913                 mapping.setPathSpecs(LazyList.toStringArray(paths));
914                 _servletMappings = LazyList.add(_servletMappings, mapping);
915             }
916         }
917     }
918 
919     /* ------------------------------------------------------------ */
920     protected void initSecurityConstraint(XmlParser.Node node)
921     {
922         Constraint scBase = new Constraint();
923 
924         try
925         {
926             XmlParser.Node auths = node.get("auth-constraint");
927 
928             if (auths != null)
929             {
930                 scBase.setAuthenticate(true);
931                 // auth-constraint
932                 Iterator iter = auths.iterator("role-name");
933                 Object roles = null;
934                 while (iter.hasNext())
935                 {
936                     String role = ((XmlParser.Node) iter.next()).toString(false, true);
937                     roles = LazyList.add(roles, role);
938                 }
939                 scBase.setRoles(LazyList.toStringArray(roles));
940             }
941 
942             XmlParser.Node data = node.get("user-data-constraint");
943             if (data != null)
944             {
945                 data = data.get("transport-guarantee");
946                 String guarantee = data.toString(false, true).toUpperCase();
947                 if (guarantee == null || guarantee.length() == 0 || "NONE".equals(guarantee))
948                     scBase.setDataConstraint(Constraint.DC_NONE);
949                 else if ("INTEGRAL".equals(guarantee))
950                     scBase.setDataConstraint(Constraint.DC_INTEGRAL);
951                 else if ("CONFIDENTIAL".equals(guarantee))
952                     scBase.setDataConstraint(Constraint.DC_CONFIDENTIAL);
953                 else
954                 {
955                     Log.warn("Unknown user-data-constraint:" + guarantee);
956                     scBase.setDataConstraint(Constraint.DC_CONFIDENTIAL);
957                 }
958             }
959             Iterator iter = node.iterator("web-resource-collection");
960             while (iter.hasNext())
961             {
962                 XmlParser.Node collection = (XmlParser.Node) iter.next();
963                 String name = collection.getString("web-resource-name", false, true);
964                 Constraint sc = (Constraint) scBase.clone();
965                 sc.setName(name);
966 
967                 Iterator iter2 = collection.iterator("url-pattern");
968                 while (iter2.hasNext())
969                 {
970                     String url = ((XmlParser.Node) iter2.next()).toString(false, true);
971                     url = normalizePattern(url);
972 
973                     Iterator iter3 = collection.iterator("http-method");
974                     if (iter3.hasNext())
975                     {
976                         while (iter3.hasNext())
977                         {
978                             String method = ((XmlParser.Node) iter3.next()).toString(false, true);
979                             ConstraintMapping mapping = new ConstraintMapping();
980                             mapping.setMethod(method);
981                             mapping.setPathSpec(url);
982                             mapping.setConstraint(sc);
983                             _newConstraintMappings.add(mapping);
984                         }
985                     }
986                     else
987                     {
988                         ConstraintMapping mapping = new ConstraintMapping();
989                         mapping.setPathSpec(url);
990                         mapping.setConstraint(sc);
991                         _newConstraintMappings.add(mapping);
992                     }
993                 }
994             }
995         }
996         catch (CloneNotSupportedException e)
997         {
998             Log.warn(e);
999         }
1000 
1001     }
1002 
1003     /* ------------------------------------------------------------ */
1004     protected void initLoginConfig(XmlParser.Node node) throws Exception
1005     {
1006         XmlParser.Node method = node.get("auth-method");
1007         if (method != null)
1008         {
1009             XmlParser.Node name = node.get("realm-name");
1010             _securityHandler.setRealmName(name == null ? "default" : name.toString(false, true));
1011             _securityHandler.setAuthMethod(method.toString(false, true));
1012             
1013             
1014             if (Constraint.__FORM_AUTH.equals(_securityHandler.getAuthMethod()))
1015             {  
1016                 XmlParser.Node formConfig = node.get("form-login-config");
1017                 if (formConfig != null)
1018                 {
1019                     String loginPageName = null;
1020                     XmlParser.Node loginPage = formConfig.get("form-login-page");
1021                     if (loginPage != null) 
1022                         loginPageName = loginPage.toString(false, true);
1023                     String errorPageName = null;
1024                     XmlParser.Node errorPage = formConfig.get("form-error-page");
1025                     if (errorPage != null) 
1026                         errorPageName = errorPage.toString(false, true);
1027                     _securityHandler.setInitParameter(FormAuthenticator.__FORM_LOGIN_PAGE,loginPageName);
1028                     _securityHandler.setInitParameter(FormAuthenticator.__FORM_ERROR_PAGE,errorPageName);
1029                 }
1030                 else
1031                 {
1032                     throw new IllegalArgumentException("!form-login-config");
1033                 }
1034             }
1035         }
1036     }
1037 
1038     /* ------------------------------------------------------------ */
1039     protected void initSecurityRole(XmlParser.Node node)
1040     {
1041         XmlParser.Node roleNode = node.get("role-name");
1042         String role = roleNode.toString(false, true);
1043         _newRoles.add(role);
1044     }
1045 
1046     /* ------------------------------------------------------------ */
1047     protected String getJSPServletName()
1048     {
1049         if (_jspServletName == null)
1050         {
1051             Map.Entry entry = _context.getServletHandler().getHolderEntry("test.jsp");
1052             if (entry != null)
1053             {
1054                 ServletHolder holder = (ServletHolder) entry.getValue();
1055                 _jspServletName = holder.getName();
1056             }
1057         }
1058         return _jspServletName;
1059     }
1060 }