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