Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/mortbay/jetty/servlet/WebApplicationContext.java


1   // ========================================================================
2   // Copyright (c) 2000 Mort Bay Consulting (Australia) Pty. Ltd.
3   // $Id: WebApplicationContext.java,v 1.113 2003/11/22 16:06:03 gregwilkins Exp $
4   // ========================================================================
5   
6   package org.mortbay.jetty.servlet;
7   
8   import java.io.Externalizable;
9   import java.io.File;
10  import java.io.IOException;
11  import java.net.MalformedURLException;
12  import java.net.URL;
13  import java.security.PermissionCollection;
14  import java.util.EventListener;
15  import java.util.HashMap;
16  import java.util.HashSet;
17  import java.util.Iterator;
18  import java.util.Map;
19  import java.util.Set;
20  
21  import javax.servlet.ServletContextAttributeEvent;
22  import javax.servlet.ServletContextAttributeListener;
23  import javax.servlet.ServletContextEvent;
24  import javax.servlet.ServletContextListener;
25  import javax.servlet.UnavailableException;
26  
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  import org.mortbay.http.Authenticator;
30  import org.mortbay.http.BasicAuthenticator;
31  import org.mortbay.http.ClientCertAuthenticator;
32  import org.mortbay.http.DigestAuthenticator;
33  import org.mortbay.http.HttpException;
34  import org.mortbay.http.HttpHandler;
35  import org.mortbay.http.HttpRequest;
36  import org.mortbay.http.HttpResponse;
37  import org.mortbay.http.SecurityConstraint;
38  import org.mortbay.http.UserRealm;
39  import org.mortbay.util.JarResource;
40  import org.mortbay.util.LazyList;
41  import org.mortbay.util.LogSupport;
42  import org.mortbay.util.MultiException;
43  import org.mortbay.util.Resource;
44  import org.mortbay.xml.XmlConfiguration;
45  import org.mortbay.xml.XmlParser;
46  
47  
48  /* ------------------------------------------------------------ */
49  /** Standard web.xml configured HttpContext.
50   *
51   * This specialization of HttpContext uses the standardized web.xml
52   * to describe a web application and configure the handlers for the
53   * HttpContext.
54   *
55   * If a file named web-jetty.xml or jetty-web.xml is found in the
56   * WEB-INF directory it is applied to the context using the
57   * XmlConfiguration format.
58   *
59   * A single WebApplicationHandler instance is used to provide
60   * security, filter, sevlet and resource handling.
61   *
62   * @see org.mortbay.jetty.servlet.WebApplicationHandler
63   * @version $Id: WebApplicationContext.java,v 1.113 2003/11/22 16:06:03 gregwilkins Exp $
64   * @author Greg Wilkins (gregw)
65   */
66  public class WebApplicationContext
67      extends ServletHttpContext
68      implements Externalizable
69  {
70      private static Log log = LogFactory.getLog(WebApplicationContext.class);
71  
72      /* ------------------------------------------------------------ */
73      private String _deploymentDescriptor;
74      private String _defaultsDescriptor="org/mortbay/jetty/servlet/webdefault.xml";
75      private String _war;
76      private boolean _extract;
77      private boolean _ignorewebjetty;
78  
79      private transient String _name;
80      private transient FormAuthenticator _formAuthenticator;
81      private transient Map _resourceAliases;
82      private transient Resource _webApp;
83      private transient Resource _webInf;
84      private transient Set _warnings;
85      private transient WebApplicationHandler _webAppHandler;
86      private transient Map _tagLibMap;
87      private transient Object _contextListeners;
88      private transient Object _contextAttributeListeners;
89      private transient Map _errorPages;
90  
91      
92      /* ------------------------------------------------------------ */
93      /** Constructor. 
94       */
95      public WebApplicationContext()
96      {}
97      
98      /* ------------------------------------------------------------ */
99      /** Constructor. 
100      * @param webApp The Web application directory or WAR file.
101      */
102     public WebApplicationContext(String webApp)
103     {
104         _war=webApp;
105     }
106     
107     /* ------------------------------------------------------------ */
108     public void writeExternal(java.io.ObjectOutput out)
109         throws java.io.IOException
110     {
111         out.writeObject(getContextPath());
112         out.writeObject(getVirtualHosts());
113         HttpHandler[] handlers = getHandlers();
114         for (int i=0;i<handlers.length;i++)
115         {
116             if (handlers[i] instanceof WebApplicationHandler)
117                 break;
118             out.writeObject(handlers[i]);
119         }
120         out.writeObject(getAttributes());
121         out.writeBoolean(isRedirectNullPath());
122         out.writeInt(getMaxCachedFileSize());
123         out.writeInt(getMaxCacheSize());
124         out.writeBoolean(getStatsOn());
125         out.writeObject(getPermissions());
126         out.writeBoolean(isClassLoaderJava2Compliant());
127         
128         out.writeObject(_deploymentDescriptor);
129         out.writeObject(_defaultsDescriptor);
130         out.writeObject(_war);
131         out.writeBoolean(_extract);
132         out.writeBoolean(_ignorewebjetty);
133     }
134     
135     /* ------------------------------------------------------------ */
136     public void readExternal(java.io.ObjectInput in)
137         throws java.io.IOException, ClassNotFoundException
138     {
139         setContextPath((String)in.readObject());
140         setVirtualHosts((String[])in.readObject());
141         Object o = in.readObject();
142         
143         while(o instanceof HttpHandler)
144         {
145             addHandler((HttpHandler)o);
146             o = in.readObject();
147         }
148         setAttributes((Map)o);
149         setRedirectNullPath(in.readBoolean());
150         setMaxCachedFileSize(in.readInt());
151         setMaxCacheSize(in.readInt());
152         setStatsOn(in.readBoolean());
153         setPermissions((PermissionCollection)in.readObject());
154         setClassLoaderJava2Compliant(in.readBoolean());
155         
156         _deploymentDescriptor=(String)in.readObject();
157         _defaultsDescriptor=(String)in.readObject();
158         _war=(String)in.readObject();
159         _extract=in.readBoolean();
160         _ignorewebjetty=in.readBoolean();
161     }
162     
163     /* ------------------------------------------------------------ */
164     /** 
165      * @param war Filename or URL of the web application directory or WAR file. 
166      */
167     public void setWAR(String war)
168     {
169         _war=war;
170     }
171     
172     /* ------------------------------------------------------------ */
173     public String getWAR()
174     {
175         return _war;
176     }
177     
178     /* ------------------------------------------------------------ */
179     public WebApplicationHandler getWebApplicationHandler()
180     {
181         if (_webAppHandler==null)
182             getServletHandler();
183         return _webAppHandler;
184     }
185     
186     /* ------------------------------------------------------------ */
187     private void resolveWebApp()
188         throws IOException
189     {
190         if (_webApp==null && _war!=null && _war.length()>0)
191         {
192             // Set dir or WAR
193             _webApp = Resource.newResource(_war);
194 
195 
196             // Accept aliases for WAR files
197             if (_webApp.getAlias()!=null)
198             {
199                 log.info(_webApp+" anti-aliased to "+_webApp.getAlias());
200                 _webApp= Resource.newResource(_webApp.getAlias());
201             }
202 
203             if(log.isDebugEnabled())log.debug("Try webapp="+_webApp+
204                                               ", exists="+_webApp.exists()+
205                                               ", directory="+_webApp.isDirectory());
206             
207             // Is the WAR usable directly?
208             if (_webApp.exists() &&
209                 !_webApp.isDirectory() &&
210                 !_webApp.toString().startsWith("jar:"))
211             {
212                 // No - then lets see if it can be turned into a jar URL.
213                 Resource jarWebApp = Resource.newResource("jar:"+_webApp+"!/");
214                 if (jarWebApp.exists() && jarWebApp.isDirectory())
215                 {
216                     _webApp=jarWebApp;
217                     _war=_webApp.toString();
218                     if(log.isDebugEnabled())log.debug("Try webapp="+_webApp+
219                                                       ", exists="+_webApp.exists()+
220                                                       ", directory="+_webApp.isDirectory());
221                 }
222             }
223             
224             // If we should extract or the URL is still not usable
225             if (_webApp.exists() &&
226                 (!_webApp.isDirectory() || 
227                  ( _extract && _webApp.getFile()==null) ||
228                  ( _extract && _webApp.getFile()!=null && !_webApp.getFile().isDirectory())))
229             {
230                 // Then extract it.
231                 File tempDir=new File(getTempDirectory(),"webapp");
232                 if (tempDir.exists())
233                     tempDir.delete();
234                 tempDir.mkdir();
235                 tempDir.deleteOnExit();
236                 log.info("Extract "+_war+" to "+tempDir);
237                 JarResource.extract(_webApp,tempDir,true);
238                 _webApp=Resource.newResource(tempDir.getCanonicalPath());
239                 
240                 if(log.isDebugEnabled())log.debug("Try webapp="+_webApp+
241                                                   ", exists="+_webApp.exists()+
242                                                   ", directory="+_webApp.isDirectory());
243             }
244             
245             // Now do we have something usable?
246             if (!_webApp.exists() || !_webApp.isDirectory())
247             {
248                 log.warn("Web application not found "+_war);
249                 throw new java.io.FileNotFoundException(_war);
250             }
251 
252             if(log.isDebugEnabled())log.debug("webapp="+_webApp);
253 
254             // Iw there a WEB-INF directory?
255             _webInf = _webApp.addPath("WEB-INF/");
256             if (!_webInf.exists() || !_webInf.isDirectory())
257                 _webInf=null;
258       else
259       {
260     // Is there a WEB-INF work directory
261     Resource work=_webInf.addPath("work");
262     if (work.exists() && work.isDirectory() && 
263         work.getFile()!=null && work.getFile().canWrite() &&
264         getAttribute("javax.servlet.context.tempdir")==null)
265         setAttribute("javax.servlet.context.tempdir",work.getFile());
266       }
267             
268             
269             // ResourcePath
270             super.setBaseResource(_webApp);
271         }
272     }
273 
274     /* ------------------------------------------------------------ */
275     /** Get the context ServletHandler.
276      * Conveniance method. If no ServletHandler exists, a new one is added to
277      * the context.  This derivation of the method creates a
278      * WebApplicationHandler extension of ServletHandler.
279      * @return WebApplicationHandler
280      */
281     public synchronized ServletHandler getServletHandler()
282     {
283         if (_webAppHandler==null)
284         {
285             _webAppHandler=(WebApplicationHandler)getHandler(WebApplicationHandler.class);
286             if (_webAppHandler==null)
287             {
288                 if (getHandler(ServletHandler.class)!=null)
289                     throw new IllegalStateException("Cannot have ServletHandler in WebApplicationContext");
290                 _webAppHandler=new WebApplicationHandler();
291                 addHandler(_webAppHandler);
292             }
293         }
294         return _webAppHandler;
295     }
296     
297     /* ------------------------------------------------------------ */
298     public void setPermissions(PermissionCollection permissions)
299     {
300         if (!_ignorewebjetty)
301             log.warn("Permissions set with web-jetty.xml enabled");
302         super.setPermissions(permissions);
303     }
304     
305     /* ------------------------------------------------------------ */
306     public boolean isIgnoreWebJetty()
307     {
308         return _ignorewebjetty;
309     }
310 
311     /* ------------------------------------------------------------ */
312     /** 
313      * @param b If TRUE, web-jetty.xml and jetty-web.xml configuration
314      * files are ignored. 
315      */
316     public void setIgnoreWebJetty(boolean b)
317     {
318         _ignorewebjetty=b;
319         if (b && getPermissions()!=null)
320             log.warn("Permissions set with web-jetty.xml enabled");
321     }
322     
323     /* ------------------------------------------------------------ */
324     /** Start the Web Application.
325      * @exception IOException 
326      */
327     public void start()
328         throws Exception
329     {
330         if (isStarted())
331             return;
332         
333         setWelcomeFiles(null);
334         _tagLibMap=new HashMap(3);
335         
336         // save context classloader
337         Thread thread = Thread.currentThread();
338         ClassLoader lastContextLoader=thread.getContextClassLoader();
339 
340         MultiException mex=null;
341         try
342         {            
343             // Get parser
344             XmlParser xmlParser=new XmlParser();
345             
346             //set up cache of DTDs and schemas locally
347             URL dtd22=WebApplicationContext.class
348                 .getResource("/javax/servlet/resources/web-app_2_2.dtd");
349             URL dtd23=WebApplicationContext.class
350                 .getResource("/javax/servlet/resources/web-app_2_3.dtd");
351             URL jsp20xsd = WebApplicationContext.class
352                 .getResource("/javax/servlet/resources/jsp_2_0.xsd");
353             URL j2ee14xsd = WebApplicationContext.class
354                 .getResource("/javax/servlet/resources/j2ee_1_4.xsd");
355             URL webapp24xsd = WebApplicationContext.class
356                 .getResource ("/javax/servlet/resources/web-app_2_4.xsd");
357             URL schemadtd = WebApplicationContext.class
358                 .getResource ("/javax/servlet/resources/XMLSchema.dtd");
359             URL xmlxsd = WebApplicationContext.class
360                 .getResource ("/javax/servlet/resources/xml.xsd");
361             URL webservice11xsd = WebApplicationContext.class
362                 .getResource ("/javax/servlet/resources/j2ee_web_services_client_1_1.xsd");
363             URL datatypesdtd = WebApplicationContext.class
364                 .getResource ("/javax/servlet/resources/datatypes.dtd");
365 
366             xmlParser.redirectEntity("web-app_2_2.dtd",dtd22);
367             xmlParser.redirectEntity("-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN",dtd22);
368             
369             xmlParser.redirectEntity("web.dtd",dtd23);
370             xmlParser.redirectEntity("web-app_2_3.dtd",dtd23);
371             xmlParser.redirectEntity("-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN",dtd23);
372             
373             xmlParser.redirectEntity("XMLSchema.dtd", schemadtd);
374             xmlParser.redirectEntity("http://www.w3.org/2001/XMLSchema.dtd", schemadtd);
375             xmlParser.redirectEntity("-//W3C//DTD XMLSCHEMA 200102//EN", schemadtd);
376             
377             xmlParser.redirectEntity("jsp_2_0.xsd", jsp20xsd);
378             xmlParser.redirectEntity("http://java.sun.com/xml/ns/j2ee/jsp_2_0.xsd", jsp20xsd);
379             xmlParser.redirectEntity("j2ee_1_4.xsd", j2ee14xsd);
380             xmlParser.redirectEntity("http://java.sun.com/xml/ns/j2ee/j2ee_1_4.xsd", j2ee14xsd);
381             xmlParser.redirectEntity("web-app_2_4.xsd",webapp24xsd);
382             xmlParser.redirectEntity("http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd", webapp24xsd);
383             xmlParser.redirectEntity("xml.xsd", xmlxsd);
384             xmlParser.redirectEntity("http://www.w3.org/2001/xml.xsd", xmlxsd);
385             xmlParser.redirectEntity("datatypes.dtd", datatypesdtd);
386             xmlParser.redirectEntity("http://www.w3.org/2001/datatypes.dtd", datatypesdtd);
387             xmlParser.redirectEntity("j2ee_web_services_client_1_1.xsd", webservice11xsd);
388             xmlParser.redirectEntity("http://www.ibm.com/webservices/xsd/j2ee_web_services_client_1_1.xsd", webservice11xsd);
389 
390             // Find the webapp
391             resolveWebApp();
392             
393             // Get the handler
394             getServletHandler();
395             
396             // Add WEB-INF classes and lib classpaths
397             if (_webInf!=null && _webInf.isDirectory())
398             {
399                 // Look for classes directory
400                 Resource classes = _webInf.addPath("classes/");
401                 if (classes.exists())
402                     super.setClassPath(classes.toString());
403                 else
404                     super.setClassPath(null);
405                     
406                 // Look for jars
407                 Resource lib = _webInf.addPath("lib/");
408                 super.setClassPaths(lib,true);
409             }
410           
411             // initialize the classloader
412             initClassLoader(true);
413             thread.setContextClassLoader(getClassLoader());
414             initialize();
415 
416             // Do the default configuration
417             if (_defaultsDescriptor!=null && _defaultsDescriptor.length()>0)
418             {
419                 Resource dftResource= Resource.newSystemResource(_defaultsDescriptor);
420                 if (dftResource==null)
421                     dftResource= Resource.newResource(_defaultsDescriptor);
422                 
423                 XmlParser.Node defaultConfig =
424                     xmlParser.parse(dftResource.getURL().toString());
425                 initialize(defaultConfig);
426             }
427 
428             // handle any WEB-INF descriptors
429             if (_webInf!=null && _webInf.isDirectory())
430             {
431                 // do web.xml file
432                 Resource web = _webInf.addPath("web.xml");
433                 if (!web.exists())
434                 {
435                     log.info("No WEB-INF/web.xml in "+_war+". Serving files and default/dynamic servlets only");
436                 }
437                 else
438                 {
439                     XmlParser.Node config=null;
440                     _deploymentDescriptor=web.toString();
441                     config = xmlParser.parse(web.getURL().toString());
442                     initialize(config);
443                 }
444                 
445                 // do jetty.xml file
446                 Resource jetty = _webInf.addPath("web-jetty.xml");
447                 if (!jetty.exists())
448                     jetty = _webInf.addPath("jetty-web.xml");
449                 if (!_ignorewebjetty && jetty.exists())
450                 {
451                     if(log.isDebugEnabled())log.debug("Configure: "+jetty);
452                     XmlConfiguration jetty_config=new
453                         XmlConfiguration(jetty.getURL());
454                     jetty_config.configure(this);
455                 }
456             }
457             
458             // Set classpath for Jasper.
459             Map.Entry entry = _webAppHandler.getHolderEntry("test.jsp");
460             if (entry!=null)
461             {
462                 ServletHolder jspHolder = (ServletHolder)entry.getValue();
463                 if (jspHolder!=null && jspHolder.getInitParameter("classpath")==null)
464                 {
465                     String fileClassPath=getFileClassPath();
466                     jspHolder.setInitParameter("classpath",fileClassPath);
467                     if(log.isDebugEnabled())log.debug("Set classpath="+fileClassPath+" for "+jspHolder);
468                 }
469             }
470             
471             // If we have servlets, don't init them yet
472             _webAppHandler.setAutoInitializeServlets(false);
473             
474             // Start handlers
475             super.start();
476 
477             mex = new MultiException();
478             // If it actually started
479             if (super.isStarted())
480             {            
481                 // Context listeners
482                 if (_contextListeners!=null && _webAppHandler!=null)
483                 {
484                     ServletContextEvent event = new ServletContextEvent(getServletContext());
485                     for (int i=0;i<LazyList.size(_contextListeners);i++)
486                         try{((ServletContextListener)LazyList.get(_contextListeners,i))
487                                 .contextInitialized(event);}
488                         catch(Exception ex) { mex.add(ex); }
489                 }
490             }
491             
492             // OK to Initialize servlets now
493             if (_webAppHandler!=null && _webAppHandler.isStarted())
494             {
495                 try{
496                     _webAppHandler.initializeServlets();
497                 }
498                 catch(Exception ex) { mex.add(ex); }
499             }
500         }  
501         catch(Exception e)
502         {
503             log.warn("Configuration error on "+_war,e);
504             throw e;
505         }
506         finally
507         {
508             thread.setContextClassLoader(lastContextLoader);
509         }
510         
511         if (mex!=null)
512             mex.ifExceptionThrow();
513     }
514 
515     
516     /* ------------------------------------------------------------ */
517     /** Stop the web application.
518      * Handlers for resource, servlet, filter and security are removed
519      * as they are recreated and configured by any subsequent call to start().
520      * @exception InterruptedException 
521      */
522     public void stop()
523         throws  InterruptedException
524     {
525         // Context listeners
526         if (_contextListeners!=null)
527         {
528             if (_webAppHandler!=null)
529             {
530                 ServletContextEvent event = new ServletContextEvent(getServletContext());
531                 for (int i=LazyList.size(_contextListeners);i-->0;)
532                     ((ServletContextListener)LazyList.get(_contextListeners,i))
533                         .contextDestroyed(event);
534             }
535         }
536 
537         _contextListeners=null;
538         _contextAttributeListeners=null;
539         
540         // Stop the context
541         super.stop();
542 
543         // clean up
544         if (_webAppHandler!=null)
545             removeHandler(_webAppHandler);
546         _webAppHandler=null;
547 
548         if (_errorPages!=null)
549             _errorPages.clear();
550         _errorPages=null;
551 
552     }
553     
554     /* ------------------------------------------------------------ */
555     public void handle(String pathInContext,
556                        String pathParams,
557                        HttpRequest httpRequest,
558                        HttpResponse httpResponse)
559         throws HttpException, IOException
560     {
561         if (!isStarted())
562             return;
563         try
564         {
565             super.handle(pathInContext,pathParams,httpRequest,httpResponse);
566         }
567         finally
568         {
569             if (!httpRequest.isHandled())
570                 httpResponse.sendError(HttpResponse.__404_Not_Found);            
571             httpRequest.setHandled(true);
572             if (!httpResponse.isCommitted())
573                 httpResponse.commit();
574         }
575     }
576     
577     
578     /* ------------------------------------------------------------ */
579     public synchronized void addEventListener(EventListener listener)
580         throws IllegalArgumentException
581     {
582         boolean known=false;
583         if (listener instanceof ServletContextListener)
584         {
585             known=true;
586             _contextListeners=LazyList.add(_contextListeners,listener);
587         }
588         
589         if (listener instanceof ServletContextAttributeListener)
590         {
591             known=true;
592             _contextAttributeListeners=LazyList.add(_contextAttributeListeners,listener);
593         }
594         
595 
596         if (!known)
597             throw new IllegalArgumentException("Unknown "+listener);
598     }
599 
600     /* ------------------------------------------------------------ */
601     public synchronized void removeEventListener(EventListener listener)
602     {
603         _contextListeners=LazyList.remove(_contextListeners,listener);
604         _contextAttributeListeners=LazyList.remove(_contextAttributeListeners,listener);
605     }
606 
607     /* ------------------------------------------------------------ */
608     public synchronized void setAttribute(String name, Object value)
609     {
610         Object old = super.getAttribute(name);
611         super.setAttribute(name,value);
612 
613         if (_contextAttributeListeners!=null && _webAppHandler!=null)
614         {
615             ServletContextAttributeEvent event =
616                 new ServletContextAttributeEvent(getServletContext(),
617                                                  name,
618                                                  old!=null?old:value);
619             for (int i=0;i<LazyList.size(_contextAttributeListeners);i++)
620             {
621                 ServletContextAttributeListener l =
622                     (ServletContextAttributeListener)
623                     LazyList.get(_contextAttributeListeners,i);
624                 if (old==null)
625                     l.attributeAdded(event);
626                 else if (value==null)
627                     l.attributeRemoved(event);
628                 else
629                     l.attributeReplaced(event);    
630             }
631         }
632     }
633     
634 
635     /* ------------------------------------------------------------ */
636     public synchronized void removeAttribute(String name)
637     {
638         Object old = super.getAttribute(name);
639         super.removeAttribute(name);
640         
641         if (old !=null &&
642             _contextAttributeListeners!=null &&
643             _webAppHandler!=null)
644         {
645             ServletContextAttributeEvent event =
646                 new ServletContextAttributeEvent(getServletContext(),
647                                                  name,old);
648             for (int i=0;i<LazyList.size(_contextAttributeListeners);i++)
649             {
650                 ServletContextAttributeListener l =
651                     (ServletContextAttributeListener)
652                     LazyList.get(_contextAttributeListeners,i);
653                 l.attributeRemoved(event);    
654             }
655         }
656     }
657     
658     /* ------------------------------------------------------------ */
659     public String getDisplayName()
660     {
661         return _name;
662     }
663     
664     /* ------------------------------------------------------------ */
665     public String getDeploymentDescriptor()
666     {
667         return _deploymentDescriptor;
668     }
669     
670     
671     /* ------------------------------------------------------------ */
672     /** Set the defaults web.xml file.
673      * The default web.xml is used to configure all webapplications
674      * before the WEB-INF/web.xml file is applied.  By default the
675      * org/mortbay/jetty/servlet/webdefault.xml resource from the
676      * org.mortbay.jetty.jar is used.
677      * @param defaults File, Resource, URL or null.
678      */
679     public void setDefaultsDescriptor(String defaults)
680     {
681         _defaultsDescriptor=defaults;
682     }
683     
684     /* ------------------------------------------------------------ */
685     public String getDefaultsDescriptor()
686     {
687         return _defaultsDescriptor;
688     }
689     
690     /* ------------------------------------------------------------ */
691     /** 
692      * @param extract If true, a WAR is extracted to a temporary
693      * directory before being deployed. 
694      */
695     public void setExtractWAR(boolean extract)
696     {
697         _extract=extract;
698     }
699     
700     /* ------------------------------------------------------------ */
701     public boolean getExtractWAR()
702     {
703         return _extract;
704     }
705 
706     /* ------------------------------------------------------------ */
707     /**
708      * Initialize is called by the start method after the contexts classloader
709      * has been initialied, but before the defaults descriptor has been applied.
710      * The default implementation does nothing.
711      *
712      * @exception Exception if an error occurs
713      */
714     protected void initialize()
715         throws Exception
716     {
717     }
718 
719     /* ------------------------------------------------------------ */
720     protected void initialize(XmlParser.Node config)
721         throws ClassNotFoundException,UnavailableException
722     {
723         Iterator iter=config.iterator();
724         XmlParser.Node node=null;
725         while (iter.hasNext())
726         {
727             try
728             {
729                 Object o = iter.next();
730                 if (!(o instanceof XmlParser.Node))
731                     continue;
732                 
733                 node=(XmlParser.Node)o;
734                 String name=node.getTag();
735 
736                 initWebXmlElement(name,node);
737             }
738             catch(ClassNotFoundException e)
739             {
740                 throw e;
741             }
742             catch(Exception e)
743             {
744                 log.warn("Configuration problem at "+node,e);
745                 throw new UnavailableException("Configuration problem");
746             }
747         }
748         
749     }
750 
751     /* ------------------------------------------------------------ */
752     /** Handle web.xml element.
753      * This method is called for each top level element within the
754      * web.xml file.  It may be specialized by derived
755      * WebApplicationContexts to provide additional configuration and handling.
756      * @param element The element name
757      * @param node The node containing the element.
758      */
759     protected void initWebXmlElement(String element, XmlParser.Node node)
760         throws Exception
761     {
762         if ("display-name".equals(element))
763             initDisplayName(node);
764         else if ("description".equals(element))
765         {}
766         else if ("context-param".equals(element))
767             initContextParam(node);
768         else if ("servlet".equals(element))
769             initServlet(node);
770         else if ("servlet-mapping".equals(element))
771             initServletMapping(node);
772         else if ("session-config".equals(element))
773             initSessionConfig(node);
774         else if ("mime-mapping".equals(element))
775             initMimeConfig(node);
776         else if ("welcome-file-list".equals(element))
777             initWelcomeFileList(node);
778         else if ("locale-encoding-mapping-list".equals(element))
779             initLocaleEncodingList(node);
780         else if ("error-page".equals(element))
781             initErrorPage(node);
782         else if ("taglib".equals(element))
783             initTagLib(node);
784         else if ("resource-ref".equals(element))
785         {
786             if(log.isDebugEnabled())log.debug("No implementation: "+node);
787         }
788         else if ("security-constraint".equals(element))
789             initSecurityConstraint(node);
790         else if ("login-config".equals(element))
791             initLoginConfig(node);
792         else if ("security-role".equals(element))
793             initSecurityRole(node);
794         else if ("filter".equals(element))
795             initFilter(node);
796         else if ("filter-mapping".equals(element))
797             initFilterMapping(node);
798         else if ("listener".equals(element))
799             initListener(node);
800         else
801         {                
802             if (_warnings==null)
803                 _warnings=new HashSet(3);
804             
805             if (_warnings.contains(element))
806             {
807                 if(log.isDebugEnabled())log.debug("Not Implemented: "+node);
808             }
809             else
810             {
811                 _warnings.add(element);
812                 if(log.isDebugEnabled())
813                 {
814                     log.debug("Element "+element+" not handled in "+this);
815                     log.debug(node);
816                 }
817             }
818         }
819     }
820     
821     /* ------------------------------------------------------------ */
822     protected void initDisplayName(XmlParser.Node node)
823     {
824         _name=node.toString(false,true);
825     }
826     
827     /* ------------------------------------------------------------ */
828     protected void initContextParam(XmlParser.Node node)
829     {
830         String name=node.getString("param-name",false,true);
831         String value=node.getString("param-value",false,true);
832         if(log.isDebugEnabled())log.debug("ContextParam: "+name+"="+value);
833 
834         setInitParameter(name,value); 
835     }
836 
837     /* ------------------------------------------------------------ */
838     protected void initFilter(XmlParser.Node node)
839         throws ClassNotFoundException, UnavailableException
840     {
841         String name=node.getString("filter-name",false,true);
842         String className=node.getString("filter-class",false,true);
843         
844         if (className==null)
845         {
846             log.warn("Missing filter-class in "+node);
847             return;
848         }
849         if (name==null)
850             name=className;
851         
852         FilterHolder holder = _webAppHandler.defineFilter(name,className);
853         holder.addAppliesTo("REQUEST");
854         Iterator iter= node.iterator("init-param");
855         while(iter.hasNext())
856         {
857             XmlParser.Node paramNode=(XmlParser.Node)iter.next();
858             String pname=paramNode.getString("param-name",false,true);
859             String pvalue=paramNode.getString("param-value",false,true);
860             holder.put(pname,pvalue);
861         }
862     }
863     
864     /* ------------------------------------------------------------ */
865     protected void initFilterMapping(XmlParser.Node node)
866     {
867         String filterName=node.getString("filter-name",false,true);
868         String pathSpec=node.getString("url-pattern",false,true);
869         String servletName=node.getString("servlet-name",false,true);
870 
871 
872         FilterHolder holder = (servletName!=null)
873             ?_webAppHandler.mapServletToFilter(servletName,filterName)
874             :_webAppHandler.mapPathToFilter(pathSpec,filterName);
875         
876         Iterator iter= node.iterator("dispatcher");
877         while(iter.hasNext())
878         {
879             String dispatcher=((XmlParser.Node)iter.next())
880                 .toString(false,true);
881             holder.addAppliesTo(dispatcher);
882         }
883     }
884     
885     /* ------------------------------------------------------------ */
886     protected void initServlet(XmlParser.Node node)
887         throws ClassNotFoundException,
888                UnavailableException,
889                IOException,
890                MalformedURLException
891     {
892         String name=node.getString("servlet-name",false,true);
893         String className=node.getString("servlet-class",false,true);
894         String jspFile=null;
895         
896         if (className==null)
897         {
898             // There is no class, so look for a jsp file
899             jspFile=node.getString("jsp-file",false,true);
900             if (jspFile!=null)
901             {
902                 Map.Entry entry = _webAppHandler.getHolderEntry(jspFile);
903                 if (entry!=null)
904                     className=((ServletHolder)entry.getValue()).getClassName();
905             }
906 
907             if (className==null)
908             {
909                 log.warn("Missing servlet-class|jsp-file in "+node);
910                 return;
911             }
912         }
913         if (name==null)
914             name=className;
915         
916         ServletHolder holder = _webAppHandler.newServletHolder(name,className,jspFile);
917 
918         // handle JSP classpath
919         if (jspFile!=null)
920         {
921             initClassLoader(true);
922             holder.setInitParameter("classpath",getFileClassPath());
923         }
924         
925         Iterator iParamsIter= node.iterator("init-param");
926         while(iParamsIter.hasNext())
927         {
928             XmlParser.Node paramNode=(XmlParser.Node)iParamsIter.next();
929             String pname=paramNode.getString("param-name",false,true);
930             String pvalue=paramNode.getString("param-value",false,true);
931             holder.put(pname,pvalue);
932         }
933 
934         XmlParser.Node startup = node.get("load-on-startup");
935         if (startup!=null)
936         {
937             String s=startup.toString(false,true).toLowerCase();
938             if (s.startsWith("t"))
939             {
940                 log.warn("Deprecated boolean load-on-startup.  Please use integer");
941                 holder.setInitOrder(1);
942             }
943             else
944             {
945                 int order=0;
946                 try
947                 {
948                     if (s!=null && s.trim().length()>0)
949                         order=Integer.parseInt(s);
950                 }
951                 catch(Exception e)
952                 {
953                     log.warn("Cannot parse load-on-startup "+s+". Please use integer");
954                     LogSupport.ignore(log,e);
955                 }
956                 holder.setInitOrder(order);
957             }
958         }
959 
960         Iterator sRefsIter= node.iterator("security-role-ref");
961         while(sRefsIter.hasNext())
962         {
963             XmlParser.Node securityRef=(XmlParser.Node)sRefsIter.next();
964             String roleName=securityRef.getString("role-name",false,true);
965             String roleLink=securityRef.getString("role-link",false,true);
966             if (roleName!=null && roleName.length()>0
967                     && roleLink!=null && roleLink.length()>0)
968             {
969                 if(log.isDebugEnabled())log.debug("link role "+roleName+" to "+roleLink+" for "+this);
970                 holder.setUserRoleLink(roleName,roleLink);
971             }
972             else
973             {
974                 log.warn("Ignored invalid security-role-ref element: "
975                         +"servlet-name="+name+", "+securityRef);
976             }
977         }
978 
979         XmlParser.Node run_as = node.get("run-as");
980         if (run_as!=null)
981         {
982             String roleName=run_as.getString("role-name",false,true);
983             if (roleName!=null)
984                 holder.setRunAs(roleName);
985         }   
986     }
987     
988     /* ------------------------------------------------------------ */
989     protected void initServletMapping(XmlParser.Node node)
990     {
991         String name=node.getString("servlet-name",false,true);
992         String pathSpec=node.getString("url-pattern",false,true);
993 
994         _webAppHandler.mapPathToServlet(pathSpec,name);
995     }
996 
997     /* ------------------------------------------------------------ */
998     protected void initListener(XmlParser.Node node)
999     {
1000        String className=node.getString("listener-class",false,true);
1001        Object listener =null;
1002        try
1003        {
1004            Class listenerClass=loadClass(className);
1005            listener=listenerClass.newInstance();
1006        }
1007        catch(Exception e)
1008        {
1009            log.warn("Could not instantiate listener "+className,e);
1010            return;
1011        }
1012
1013        if (!(listener instanceof EventListener))
1014        {
1015            log.warn("Not an EventListener: "+listener);
1016            return;
1017        }
1018
1019        boolean known=false;
1020        try
1021        {
1022            addEventListener((EventListener)listener);
1023            known=true;
1024        }
1025        catch(Exception e)
1026        {
1027            LogSupport.ignore(log,e);
1028        }
1029
1030        try
1031        {
1032            _webAppHandler.addEventListener((EventListener)listener);
1033            known=true;
1034        }
1035        catch(Exception e)
1036        {
1037            LogSupport.ignore(log,e);
1038        }
1039        
1040        if (!known)
1041            log.warn("Unknown: "+listener);
1042    }
1043    
1044    
1045    /* ------------------------------------------------------------ */
1046    protected void initSessionConfig(XmlParser.Node node)
1047    {
1048        XmlParser.Node tNode=node.get("session-timeout");
1049        if(tNode!=null)
1050        {
1051            int timeout = Integer.parseInt(tNode.toString(false,true));
1052            _webAppHandler.setSessionInactiveInterval(timeout*60);
1053        }
1054    }
1055    
1056    /* ------------------------------------------------------------ */
1057    protected void initMimeConfig(XmlParser.Node node)
1058    {
1059        String extension= node.getString("extension",false,true);
1060        if (extension!=null && extension.startsWith("."))
1061            extension=extension.substring(1);
1062        
1063        String mimeType= node.getString("mime-type",false,true);
1064        setMimeMapping(extension,mimeType);
1065    }
1066    
1067    /* ------------------------------------------------------------ */
1068    protected void initWelcomeFileList(XmlParser.Node node)
1069    {
1070        Iterator iter= node.iterator("welcome-file");
1071        while(iter.hasNext())
1072        {
1073            XmlParser.Node indexNode=(XmlParser.Node)iter.next();
1074            String index=indexNode.toString(false,true);
1075            if(log.isDebugEnabled())log.debug("Index: "+index);
1076            addWelcomeFile(index);
1077        }
1078    }
1079    
1080    /* ------------------------------------------------------------ */
1081    protected void initLocaleEncodingList(XmlParser.Node node)
1082    {
1083        Iterator iter= node.iterator("locale-encoding-mapping");
1084        while(iter.hasNext())
1085        {
1086            XmlParser.Node mapping=(XmlParser.Node)iter.next();
1087            String locale= mapping.getString("locale",false,true);
1088            String encoding= mapping.getString("encoding",false,true);
1089            addLocaleEncoding(locale,encoding);
1090        }
1091    }
1092
1093    /* ------------------------------------------------------------ */
1094    protected void initErrorPage(XmlParser.Node node)
1095    {
1096        String error= node.getString("error-code",false,true);
1097        if (error==null || error.length()==0)
1098            error= node.getString("exception-type",false,true);
1099        
1100        String location= node.getString("location",false,true);
1101        setErrorPage(error,location);
1102    }
1103    
1104    /* ------------------------------------------------------------ */
1105    protected void initTagLib(XmlParser.Node node)
1106    {
1107        String uri= node.getString("taglib-uri",false,true);
1108        String location= node.getString("taglib-location",false,true);
1109        _tagLibMap.put(uri,location);
1110        setResourceAlias(uri,location);
1111    }
1112    
1113    /* ------------------------------------------------------------ */
1114    protected void initSecurityConstraint(XmlParser.Node node)
1115    {
1116        SecurityConstraint scBase = new SecurityConstraint();
1117        
1118        XmlParser.Node auths=node.get("auth-constraint");
1119        if (auths!=null)
1120        {
1121            scBase.setAuthenticate(true);
1122            // auth-constraint
1123            Iterator iter= auths.iterator("role-name");
1124            while(iter.hasNext())
1125            {
1126                String role=((XmlParser.Node)iter.next()).toString(false,true);
1127                scBase.addRole(role);
1128            }
1129        }
1130        
1131        XmlParser.Node data=node.get("user-data-constraint");
1132        if (data!=null)
1133        {
1134            data=data.get("transport-guarantee");
1135            String guarantee = data.toString(false,true).toUpperCase();
1136            if (guarantee==null || guarantee.length()==0 ||
1137                "NONE".equals(guarantee))
1138                scBase.setDataConstraint(SecurityConstraint.DC_NONE);
1139            else if ("INTEGRAL".equals(guarantee))
1140                scBase.setDataConstraint(SecurityConstraint.DC_INTEGRAL);
1141            else if ("CONFIDENTIAL".equals(guarantee))
1142                scBase.setDataConstraint(SecurityConstraint.DC_CONFIDENTIAL);
1143            else
1144            {
1145                log.warn("Unknown user-data-constraint:"+guarantee);
1146                scBase.setDataConstraint(SecurityConstraint.DC_CONFIDENTIAL);
1147            }
1148        }
1149
1150        Iterator iter= node.iterator("web-resource-collection");
1151        while(iter.hasNext())
1152        {
1153            XmlParser.Node collection=(XmlParser.Node)iter.next();
1154            String name=collection.getString("web-resource-name",false,true);
1155            SecurityConstraint sc = (SecurityConstraint)scBase.clone();
1156            sc.setName(name);
1157            
1158            Iterator iter2= collection.iterator("http-method");
1159            while(iter2.hasNext())
1160                sc.addMethod(((XmlParser.Node)iter2.next())
1161                             .toString(false,true));
1162
1163            iter2= collection.iterator("url-pattern");
1164            while(iter2.hasNext())
1165            {
1166                String url=
1167                    ((XmlParser.Node)iter2.next()).toString(false,true);
1168                addSecurityConstraint(url,sc);
1169            }
1170        }
1171    }
1172                                      
1173    /* ------------------------------------------------------------ */
1174    protected void initLoginConfig(XmlParser.Node node)
1175    {
1176        XmlParser.Node method=node.get("auth-method");
1177        if (method!=null)
1178        {
1179            Authenticator authenticator=null;
1180            String m=method.toString(false,true);
1181            
1182            if (SecurityConstraint.__FORM_AUTH.equals(m))
1183                authenticator=_formAuthenticator=new FormAuthenticator();
1184            else if (SecurityConstraint.__BASIC_AUTH.equals(m))
1185                authenticator=new BasicAuthenticator();
1186            else if (SecurityConstraint.__DIGEST_AUTH.equals(m))
1187                authenticator=new DigestAuthenticator();
1188            else if (SecurityConstraint.__CERT_AUTH.equals(m))
1189                authenticator=new ClientCertAuthenticator();
1190            else if (SecurityConstraint.__CERT_AUTH2.equals(m))
1191                authenticator=new ClientCertAuthenticator();
1192            else
1193                log.warn("UNKNOWN AUTH METHOD: "+m);
1194
1195            setAuthenticator(authenticator);
1196        }
1197        
1198        XmlParser.Node name=node.get("realm-name");
1199        if (name!=null)
1200            setRealmName(name.toString(false,true));
1201
1202        XmlParser.Node formConfig = node.get("form-login-config");
1203        if(formConfig != null)
1204        {
1205            if (_formAuthenticator==null)
1206                log.warn("FORM Authentication miss-configured");
1207            else
1208            {
1209                XmlParser.Node loginPage = formConfig.get("form-login-page");
1210                if (loginPage != null)
1211                    _formAuthenticator.setLoginPage(loginPage.toString(false,true));
1212                XmlParser.Node errorPage = formConfig.get("form-error-page");
1213                if (errorPage != null)
1214                {
1215                    String ep=errorPage.toString(false,true);
1216                    _formAuthenticator.setErrorPage(ep);
1217                }
1218            }
1219        }
1220    }
1221    
1222    /* ------------------------------------------------------------ */
1223    protected void initSecurityRole(XmlParser.Node node)
1224    {
1225    }
1226
1227    /* ------------------------------------------------------------ */
1228    protected UserRealm getUserRealm(String name)
1229    {
1230        return getHttpServer().getRealm(name);
1231    }
1232    
1233    /* ------------------------------------------------------------ */
1234    public String toString()
1235    {
1236        return "WebApplicationContext["+getHttpContextName()+","+
1237            (_name==null?_war:_name)+"]";
1238    }
1239    
1240    /* ------------------------------------------------------------ */
1241    public void setClassPath(String classPath)
1242    {
1243        log.warn("ClassPath should not be set for WebApplication");
1244        super.setClassPath(classPath);
1245    }
1246    
1247    /* ------------------------------------------------------------ */
1248    public void setResourceBase(String resourceBase)
1249    {
1250        log.warn("ResourceBase should not be set for WebApplication");
1251        super.setResourceBase(resourceBase);
1252    }
1253    
1254    /* ------------------------------------------------------------ */
1255    public void setBaseResource(Resource baseResource)
1256    {
1257        log.warn("BaseResource should not be set for WebApplication");
1258        super.setBaseResource(baseResource);
1259    }
1260
1261    /* ------------------------------------------------------------ */
1262    /** Get the taglib map. 
1263     * @return A map of uri to location for tag libraries.
1264     */
1265    public Map getTagLibMap()
1266    {
1267        return _tagLibMap;
1268    }
1269    
1270    
1271    /* ------------------------------------------------------------ */
1272    /** Set Resource Alias.
1273     * Resource aliases map resource uri's within a context.
1274     * They may optionally be used by a handler when looking for
1275     * a resource.  
1276     * @param alias 
1277     * @param uri 
1278     */
1279    public void setResourceAlias(String alias,String uri)
1280    {
1281        if (_resourceAliases==null)
1282            _resourceAliases=new HashMap(5);
1283        _resourceAliases.put(alias,uri);
1284    }
1285    
1286    /* ------------------------------------------------------------ */
1287    public String getResourceAlias(String alias)
1288    {
1289        if (_resourceAliases==null)
1290            return null;
1291       return (String) _resourceAliases.get(alias);
1292    }
1293    
1294    /* ------------------------------------------------------------ */
1295    public String removeResourceAlias(String alias)
1296    {
1297        if (_resourceAliases==null)
1298            return null;
1299       return (String) _resourceAliases.remove(alias);
1300    }
1301
1302    
1303    /* ------------------------------------------------------------ */
1304    public Resource getResource(String uriInContext)
1305        throws IOException
1306    {
1307        IOException ioe=null;
1308        Resource resource=null;
1309        try
1310        {
1311            resource=super.getResource(uriInContext);
1312            if (resource!=null && resource.exists())
1313                return resource;
1314        }
1315        catch (IOException e)
1316        {
1317            ioe=e;
1318        }
1319
1320        String aliasedUri=getResourceAlias(uriInContext);
1321        if (aliasedUri!=null)
1322            return super.getResource(aliasedUri);
1323
1324        if (ioe!=null)
1325            throw ioe;
1326
1327        return resource;
1328    }
1329
1330
1331    /* ------------------------------------------------------------ */
1332    /** set error page URI.
1333     * @param error A string representing an error code or a
1334     * exception classname
1335     * @param uriInContext
1336     */
1337    void setErrorPage(String error,String uriInContext)
1338    {
1339        if (_errorPages==null)
1340            _errorPages=new HashMap();
1341        _errorPages.put(error,uriInContext);
1342    }
1343
1344    /* ------------------------------------------------------------ */
1345    /** get error page URI.
1346     * @param error A string representing an error code or a
1347     * exception classname
1348     * @return URI within context
1349     */
1350    String getErrorPage(String error)
1351    {
1352        if (_errorPages==null)
1353            return null;
1354       return (String) _errorPages.get(error);
1355    }
1356
1357
1358    /* ------------------------------------------------------------ */
1359    String removeErrorPage(String error)
1360    {
1361        if (_errorPages==null)
1362            return null;
1363       return (String) _errorPages.remove(error);
1364    }
1365    
1366}