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