KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mortbay > http > HttpContext


1 // ========================================================================
2
// $Id: HttpContext.java,v 1.136 2006/02/21 09:47:43 gregwilkins Exp $
3
// Copyright 2000-2004 Mort Bay Consulting Pty. Ltd.
4
// ------------------------------------------------------------------------
5
// Licensed under the Apache License, Version 2.0 (the "License");
6
// you may not use this file except in compliance with the License.
7
// You may obtain a copy of the License at
8
// http://www.apache.org/licenses/LICENSE-2.0
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
// ========================================================================
15

16 package org.mortbay.http;
17
18 import java.io.File JavaDoc;
19 import java.io.IOException JavaDoc;
20 import java.io.Serializable JavaDoc;
21 import java.net.InetAddress JavaDoc;
22 import java.net.MalformedURLException JavaDoc;
23 import java.net.Socket JavaDoc;
24 import java.net.URL JavaDoc;
25 import java.net.URLClassLoader JavaDoc;
26 import java.net.UnknownHostException JavaDoc;
27 import java.security.Permission JavaDoc;
28 import java.security.PermissionCollection JavaDoc;
29 import java.security.Permissions JavaDoc;
30 import java.util.ArrayList JavaDoc;
31 import java.util.Arrays JavaDoc;
32 import java.util.Collections JavaDoc;
33 import java.util.Enumeration JavaDoc;
34 import java.util.HashMap JavaDoc;
35 import java.util.Iterator JavaDoc;
36 import java.util.LinkedList JavaDoc;
37 import java.util.List JavaDoc;
38 import java.util.Map JavaDoc;
39 import java.util.StringTokenizer JavaDoc;
40
41 import org.apache.commons.logging.Log;
42 import org.mortbay.log.LogFactory;
43 import org.mortbay.http.ResourceCache.ResourceMetaData;
44 import org.mortbay.http.handler.ErrorPageHandler;
45 import org.mortbay.util.Container;
46 import org.mortbay.util.EventProvider;
47 import org.mortbay.util.IO;
48 import org.mortbay.util.LazyList;
49 import org.mortbay.util.LifeCycle;
50 import org.mortbay.util.LogSupport;
51 import org.mortbay.util.MultiException;
52 import org.mortbay.util.Resource;
53 import org.mortbay.util.URI;
54
55
56 /* ------------------------------------------------------------ */
57 /** Context for a collection of HttpHandlers.
58  * HTTP Context provides an ordered container for HttpHandlers
59  * that share the same path prefix, filebase, resourcebase and/or
60  * classpath.
61  * <p>
62  * A HttpContext is analagous to a ServletContext in the
63  * Servlet API, except that it may contain other types of handler
64  * other than servlets.
65  * <p>
66  * A ClassLoader is created for the context and it uses
67  * Thread.currentThread().getContextClassLoader(); as it's parent loader.
68  * The class loader is initialized during start(), when a derived
69  * context calls initClassLoader() or on the first call to loadClass()
70  * <p>
71  *
72  * <B>Note. that order is important when configuring a HttpContext.
73  * For example, if resource serving is enabled before servlets, then resources
74  * take priority.</B>
75  *
76  * @see HttpServer
77  * @see HttpHandler
78  * @see org.mortbay.jetty.servlet.ServletHttpContext
79  * @version $Id: HttpContext.java,v 1.136 2006/02/21 09:47:43 gregwilkins Exp $
80  * @author Greg Wilkins (gregw)
81  */

82 public class HttpContext extends Container
83                          implements LifeCycle,
84                                     HttpHandler,
85                                     EventProvider,
86                                     Serializable JavaDoc
87 {
88     private static Log log = LogFactory.getLog(HttpContext.class);
89
90     /* ------------------------------------------------------------ */
91     /** File class path attribute.
92      * If this name is set as a context init parameter, then the attribute
93      * name given will be used to set the file classpath for the context as a
94      * context attribute.
95      */

96     public final static String JavaDoc __fileClassPathAttr=
97         "org.mortbay.http.HttpContext.FileClassPathAttribute";
98
99     public final static String JavaDoc __ErrorHandler=
100         "org.mortbay.http.ErrorHandler";
101
102
103     /* ------------------------------------------------------------ */
104     /* ------------------------------------------------------------ */
105     // These attributes are serialized by WebApplicationContext, which needs
106
// to be updated if you add to these
107
private String JavaDoc _contextPath;
108     private List JavaDoc _vhosts=new ArrayList JavaDoc(2);
109     private List JavaDoc _hosts=new ArrayList JavaDoc(2);
110     private List JavaDoc _handlers=new ArrayList JavaDoc(3);
111     private Map JavaDoc _attributes = new HashMap JavaDoc(3);
112     private boolean _redirectNullPath=true;
113     private boolean _statsOn=false;
114     private PermissionCollection JavaDoc _permissions;
115     private boolean _classLoaderJava2Compliant=true;
116     private ResourceCache _resources;
117     private String JavaDoc[] _systemClasses=new String JavaDoc [] {"java.","javax.servlet.","javax.xml.","org.mortbay.","org.xml.","org.w3c.","org.apache.commons.logging."};
118     private String JavaDoc[] _serverClasses = new String JavaDoc[] {"-org.mortbay.http.PathMap","-org.mortbay.jetty.servlet.Invoker","-org.mortbay.jetty.servlet.JSR154Filter","-org.mortbay.jetty.servlet.Default","org.mortbay.jetty.Server","org.mortbay.http.","org.mortbay.start.","org.mortbay.stop."};
119   
120     /* ------------------------------------------------------------ */
121     private String JavaDoc _contextName;
122     private String JavaDoc _classPath;
123     private Map JavaDoc _initParams = new HashMap JavaDoc(11);
124     private UserRealm _userRealm;
125     private String JavaDoc _realmName;
126     private PathMap _constraintMap=new PathMap();
127     private Authenticator _authenticator;
128     private RequestLog _requestLog;
129
130
131     private String JavaDoc[] _welcomes=
132     {
133         "welcome.html",
134         "index.html",
135         "index.htm",
136         "index.jsp"
137     };
138
139
140     /* ------------------------------------------------------------ */
141     private transient boolean _gracefulStop;
142     private transient ClassLoader JavaDoc _parent;
143     private transient ClassLoader JavaDoc _loader;
144     private transient HttpServer _httpServer;
145     private transient File JavaDoc _tmpDir;
146     private transient HttpHandler[] _handlersArray;
147     private transient String JavaDoc[] _vhostsArray;
148
149
150     /* ------------------------------------------------------------ */
151     transient Object JavaDoc _statsLock=new Object JavaDoc[0];
152     transient long _statsStartedAt;
153     transient int _requests;
154     transient int _requestsActive;
155     transient int _requestsActiveMax;
156     transient int _responses1xx; // Informal
157
transient int _responses2xx; // Success
158
transient int _responses3xx; // Redirection
159
transient int _responses4xx; // Client Error
160
transient int _responses5xx; // Server Error
161

162
163     /* ------------------------------------------------------------ */
164     /** Constructor.
165      */

166     public HttpContext()
167     {
168         setAttribute(__ErrorHandler, new ErrorPageHandler());
169         _resources=new ResourceCache();
170         addComponent(_resources);
171     }
172
173     /* ------------------------------------------------------------ */
174     /** Constructor.
175      * @param httpServer
176      * @param contextPathSpec
177      */

178     public HttpContext(HttpServer httpServer,String JavaDoc contextPathSpec)
179     {
180         this();
181         setHttpServer(httpServer);
182         setContextPath(contextPathSpec);
183     }
184
185     /* ------------------------------------------------------------ */
186     private void readObject(java.io.ObjectInputStream JavaDoc in)
187         throws IOException JavaDoc, ClassNotFoundException JavaDoc
188     {
189         in.defaultReadObject();
190         _statsLock=new Object JavaDoc[0];
191         getHandlers();
192         for (int i=0;i<_handlersArray.length;i++)
193             _handlersArray[i].initialize(this);
194     }
195
196     /* ------------------------------------------------------------ */
197     /** Get the ThreadLocal HttpConnection.
198      * Get the HttpConnection for current thread, if any. This method is
199      * not static in order to control access.
200      * @return HttpConnection for this thread.
201      */

202     public HttpConnection getHttpConnection()
203     {
204         return HttpConnection.getHttpConnection();
205     }
206
207     /* ------------------------------------------------------------ */
208     void setHttpServer(HttpServer httpServer)
209     {
210         _httpServer=httpServer;
211         _contextName=null;
212       
213     }
214
215     /* ------------------------------------------------------------ */
216     public HttpServer getHttpServer()
217     {
218         return _httpServer;
219     }
220
221     /* ------------------------------------------------------------ */
222     public void setStopGracefully(boolean graceful)
223     {
224     _gracefulStop=graceful;
225     }
226
227     /* ------------------------------------------------------------ */
228     public boolean getStopGracefully()
229     {
230     return _gracefulStop;
231     }
232
233
234     /* ------------------------------------------------------------ */
235     public static String JavaDoc canonicalContextPathSpec(String JavaDoc contextPathSpec)
236     {
237         // check context path
238
if (contextPathSpec==null ||
239             contextPathSpec.indexOf(',')>=0 ||
240             contextPathSpec.startsWith("*"))
241             throw new IllegalArgumentException JavaDoc ("Illegal context spec:"+contextPathSpec);
242
243         if(!contextPathSpec.startsWith("/"))
244         contextPathSpec='/'+contextPathSpec;
245
246         if (contextPathSpec.length()>1)
247         {
248             if (contextPathSpec.endsWith("/"))
249                 contextPathSpec+="*";
250             else if (!contextPathSpec.endsWith("/*"))
251                 contextPathSpec+="/*";
252         }
253
254         return contextPathSpec;
255     }
256
257     /* ------------------------------------------------------------ */
258     public void setContextPath(String JavaDoc contextPathSpec)
259     {
260         if (_httpServer!=null)
261             _httpServer.removeMappings(this);
262
263         contextPathSpec=canonicalContextPathSpec(contextPathSpec);
264
265         if (contextPathSpec.length()>1)
266             _contextPath=contextPathSpec.substring(0,contextPathSpec.length()-2);
267         else
268             _contextPath="/";
269
270         _contextName=null;
271
272         if (_httpServer!=null)
273             _httpServer.addMappings(this);
274     }
275
276
277     /* ------------------------------------------------------------ */
278     /**
279      * @return The context prefix
280      */

281     public String JavaDoc getContextPath()
282     {
283         return _contextPath;
284     }
285
286
287     /* ------------------------------------------------------------ */
288     /** Add a virtual host alias to this context.
289      * @see #setVirtualHosts
290      * @param hostname A hostname. A null host name means any hostname is
291      * acceptable. Host names may String representation of IP addresses.
292      */

293     public void addVirtualHost(String JavaDoc hostname)
294     {
295         // Note that null hosts are also added.
296
if (!_vhosts.contains(hostname))
297         {
298             _vhosts.add(hostname);
299             _contextName=null;
300
301             if (_httpServer!=null)
302             {
303                 if (_vhosts.size()==1)
304                     _httpServer.removeMapping(null,this);
305                 _httpServer.addMapping(hostname,this);
306             }
307             _vhostsArray=null;
308         }
309     }
310
311     /* ------------------------------------------------------------ */
312     /** remove a virtual host alias to this context.
313      * @see #setVirtualHosts
314      * @param hostname A hostname. A null host name means any hostname is
315      * acceptable. Host names may String representation of IP addresses.
316      */

317     public void removeVirtualHost(String JavaDoc hostname)
318     {
319         // Note that null hosts are also added.
320
if (_vhosts.remove(hostname))
321         {
322             _contextName=null;
323             if (_httpServer!=null)
324             {
325                 _httpServer.removeMapping(hostname,this);
326                 if (_vhosts.size()==0)
327                     _httpServer.addMapping(null,this);
328             }
329             _vhostsArray=null;
330         }
331     }
332
333     /* ------------------------------------------------------------ */
334     /** Set the virtual hosts for the context.
335      * Only requests that have a matching host header or fully qualified
336      * URL will be passed to that context with a virtual host name.
337      * A context with no virtual host names or a null virtual host name is
338      * available to all requests that are not served by a context with a
339      * matching virtual host name.
340      * @param hosts Array of virtual hosts that this context responds to. A
341      * null host name or null/empty array means any hostname is acceptable.
342      * Host names may String representation of IP addresses.
343      */

344     public void setVirtualHosts(String JavaDoc[] hosts)
345     {
346         List JavaDoc old = new ArrayList JavaDoc(_vhosts);
347
348         if (hosts!=null)
349     {
350         for (int i=0;i<hosts.length;i++)
351         {
352         boolean existing=old.remove(hosts[i]);
353         if (!existing)
354             addVirtualHost(hosts[i]);
355         }
356     }
357
358         for (int i=0;i<old.size();i++)
359             removeVirtualHost((String JavaDoc)old.get(i));
360     }
361
362     /* ------------------------------------------------------------ */
363     /** Get the virtual hosts for the context.
364      * Only requests that have a matching host header or fully qualified
365      * URL will be passed to that context with a virtual host name.
366      * A context with no virtual host names or a null virtual host name is
367      * available to all requests that are not served by a context with a
368      * matching virtual host name.
369      * @return Array of virtual hosts that this context responds to. A
370      * null host name or empty array means any hostname is acceptable.
371      * Host names may be String representation of IP addresses.
372      */

373     public String JavaDoc[] getVirtualHosts()
374     {
375         if (_vhostsArray!=null)
376             return _vhostsArray;
377         if (_vhosts==null)
378             _vhostsArray=new String JavaDoc[0];
379         else
380         {
381             _vhostsArray=new String JavaDoc[_vhosts.size()];
382             _vhostsArray=(String JavaDoc[])_vhosts.toArray(_vhostsArray);
383         }
384         return _vhostsArray;
385     }
386
387
388     /* ------------------------------------------------------------ */
389     /** Set the hosts for the context.
390      * Set the real hosts that this context will accept requests for.
391      * If not null or empty, then only requests from HttpListeners for hosts
392      * in this array are accepted by this context.
393      * Unlike virutal hosts, this value is not used by HttpServer for
394      * matching a request to a context.
395      */

396     public void setHosts(String JavaDoc[] hosts)
397         throws UnknownHostException JavaDoc
398     {
399         if (hosts==null || hosts.length==0)
400             _hosts=null;
401         else
402         {
403             _hosts=new ArrayList JavaDoc();
404             for (int i=0;i<hosts.length;i++)
405                 if (hosts[i]!=null)
406                     _hosts.add(InetAddress.getByName(hosts[i]));
407         }
408         
409     }
410
411     /* ------------------------------------------------------------ */
412     /** Get the hosts for the context.
413      */

414     public String JavaDoc[] getHosts()
415     {
416         if (_hosts==null || _hosts.size()==0)
417             return null;
418         String JavaDoc[] hosts=new String JavaDoc[_hosts.size()];
419         for (int i=0;i<hosts.length;i++)
420         {
421             InetAddress JavaDoc a = (InetAddress JavaDoc)_hosts.get(i);
422             if (a!=null)
423                 hosts[i]=a.getHostName();
424         }
425         return hosts;
426     }
427
428
429     /* ------------------------------------------------------------ */
430     /** Set system classes.
431      * System classes cannot be overriden by context classloaders.
432      * @param classes array of classname Strings. Names ending with '.' are treated as package names. Names starting with '-' are treated as
433      * negative matches and must be listed before any enclosing packages.
434      */

435     public void setSystemClasses(String JavaDoc[] classes)
436     {
437         _systemClasses=classes;
438     }
439
440     /* ------------------------------------------------------------ */
441     /** Get system classes.
442      * System classes cannot be overriden by context classloaders.
443      * @return array of classname Strings. Names ending with '.' are treated as package names. Names starting with '-' are treated as
444      * negative matches and must be listed before any enclosing packages. Null if not set.
445      */

446     public String JavaDoc[] getSystemClasses()
447     {
448         return _systemClasses;
449     }
450     
451
452     /* ------------------------------------------------------------ */
453     /** Set system classes.
454      * Servers classes cannot be seen by context classloaders.
455      * @param classes array of classname Strings. Names ending with '.' are treated as package names. Names starting with '-' are treated as
456      * negative matches and must be listed before any enclosing packages.
457      */

458     public void setServerClasses(String JavaDoc[] classes)
459     {
460         _serverClasses=classes;
461     }
462
463     /* ------------------------------------------------------------ */
464     /** Get system classes.
465      * System classes cannot be seen by context classloaders.
466      * @return array of classname Strings. Names ending with '.' are treated as package names. Names starting with '-' are treated as
467      * negative matches and must be listed before any enclosing packages. Null if not set.
468      */

469     public String JavaDoc[] getServerClasses()
470     {
471         return _serverClasses;
472     }
473
474
475     /* ------------------------------------------------------------ */
476     public void setHandlers(HttpHandler[] handlers)
477     {
478         List JavaDoc old = new ArrayList JavaDoc(_handlers);
479
480     if (handlers!=null)
481     {
482         for (int i=0;i<handlers.length;i++)
483         {
484         boolean existing=old.remove(handlers[i]);
485         if (!existing)
486             addHandler(handlers[i]);
487         }
488     }
489
490         for (int i=0;i<old.size();i++)
491             removeHandler((HttpHandler)old.get(i));
492     }
493
494     /* ------------------------------------------------------------ */
495     /** Get all handlers.
496      * @return List of all HttpHandlers
497      */

498     public HttpHandler[] getHandlers()
499     {
500         if (_handlersArray!=null)
501             return _handlersArray;
502         if (_handlers==null)
503             _handlersArray=new HttpHandler[0];
504         else
505         {
506             _handlersArray=new HttpHandler[_handlers.size()];
507             _handlersArray=(HttpHandler[])_handlers.toArray(_handlersArray);
508         }
509         return _handlersArray;
510     }
511
512
513     /* ------------------------------------------------------------ */
514     /** Add a handler.
515      * @param i The position in the handler list
516      * @param handler The handler.
517      */

518     public synchronized void addHandler(int i,HttpHandler handler)
519     {
520         _handlers.add(i,handler);
521         _handlersArray=null;
522
523         HttpContext context = handler.getHttpContext();
524         if (context==null)
525             handler.initialize(this);
526         else if (context!=this)
527             throw new IllegalArgumentException JavaDoc("Handler in another HttpContext");
528         addComponent(handler);
529     }
530
531     /* ------------------------------------------------------------ */
532     /** Add a HttpHandler to the context.
533      * @param handler
534      */

535     public synchronized void addHandler(HttpHandler handler)
536     {
537         addHandler(_handlers.size(),handler);
538     }
539
540     /* ------------------------------------------------------------ */
541     /** Get handler index.
542      * @param handler instance
543      * @return Index of handler in context or -1 if not found.
544      */

545     public int getHandlerIndex(HttpHandler handler)
546     {
547         for (int h=0;h<_handlers.size();h++)
548         {
549             if ( handler == _handlers.get(h))
550                 return h;
551         }
552         return -1;
553     }
554
555     /* ------------------------------------------------------------ */
556     /** Get a handler by class.
557      * @param handlerClass
558      * @return The first handler that is an instance of the handlerClass
559      */

560     public synchronized HttpHandler getHandler(Class JavaDoc handlerClass)
561     {
562         for (int h=0;h<_handlers.size();h++)
563         {
564             HttpHandler handler = (HttpHandler)_handlers.get(h);
565             if (handlerClass.isInstance(handler))
566                 return handler;
567         }
568         return null;
569     }
570
571     /* ------------------------------------------------------------ */
572     /** Remove a handler.
573      * The handler must be stopped before being removed.
574      * @param i index of handler
575      */

576     public synchronized HttpHandler removeHandler(int i)
577     {
578         HttpHandler handler = _handlersArray[i];
579         if (handler.isStarted())
580             try{handler.stop();} catch (InterruptedException JavaDoc e){log.warn(LogSupport.EXCEPTION,e);}
581         _handlers.remove(i);
582         _handlersArray=null;
583         removeComponent(handler);
584         return handler;
585     }
586
587     /* ------------------------------------------------------------ */
588     /** Remove a handler.
589      * The handler must be stopped before being removed.
590      */

591     public synchronized void removeHandler(HttpHandler handler)
592     {
593         if (handler.isStarted())
594             try{handler.stop();} catch (InterruptedException JavaDoc e){log.warn(LogSupport.EXCEPTION,e);}
595         _handlers.remove(handler);
596         removeComponent(handler);
597         _handlersArray=null;
598     }
599
600
601     /* ------------------------------------------------------------ */
602     /** Set context init parameter.
603      * Init Parameters differ from attributes as they can only
604      * have string values, servlets cannot set them and they do
605      * not have a package scoped name space.
606      * @param param param name
607      * @param value param value or null
608      */

609     public void setInitParameter(String JavaDoc param, String JavaDoc value)
610     {
611         _initParams.put(param,value);
612     }
613
614     /* ------------------------------------------------------------ */
615     /** Get context init parameter.
616      * @param param param name
617      * @return param value or null
618      */

619     public String JavaDoc getInitParameter(String JavaDoc param)
620     {
621         return (String JavaDoc)_initParams.get(param);
622     }
623
624     /* ------------------------------------------------------------ */
625     /** Get context init parameter.
626      * @return Enumeration of names
627      */

628     public Enumeration JavaDoc getInitParameterNames()
629     {
630         return Collections.enumeration(_initParams.keySet());
631     }
632
633     /* ------------------------------------------------------------ */
634     /** Set a context attribute.
635      * @param name attribute name
636      * @param value attribute value
637      */

638     public synchronized void setAttribute(String JavaDoc name, Object JavaDoc value)
639     {
640         _attributes.put(name,value);
641     }
642
643     /* ------------------------------------------------------------ */
644     /**
645      * @param name attribute name
646      * @return attribute value or null
647      */

648     public Object JavaDoc getAttribute(String JavaDoc name)
649     {
650         return _attributes.get(name);
651     }
652
653     /* ------------------------------------------------------------ */
654     /**
655      */

656     public Map JavaDoc getAttributes()
657     {
658         return _attributes;
659     }
660
661     /* ------------------------------------------------------------ */
662     /**
663      */

664     public void setAttributes(Map JavaDoc attributes)
665     {
666         _attributes=attributes;
667     }
668
669     /* ------------------------------------------------------------ */
670     /**
671      * @return enumaration of names.
672      */

673     public Enumeration JavaDoc getAttributeNames()
674     {
675         return Collections.enumeration(_attributes.keySet());
676     }
677
678     /* ------------------------------------------------------------ */
679     /**
680      * @param name attribute name
681      */

682     public synchronized void removeAttribute(String JavaDoc name)
683     {
684         _attributes.remove(name);
685     }
686
687
688     /* ------------------------------------------------------------ */
689     public void flushCache()
690     {
691         _resources.flushCache();
692     }
693
694     /* ------------------------------------------------------------ */
695     public String JavaDoc[] getWelcomeFiles()
696     {
697         return _welcomes;
698     }
699
700     /* ------------------------------------------------------------ */
701     public void setWelcomeFiles(String JavaDoc[] welcomes)
702     {
703         if (welcomes==null)
704             _welcomes=new String JavaDoc[0];
705         else
706             _welcomes=welcomes;
707     }
708
709     /* ------------------------------------------------------------ */
710     public void addWelcomeFile(String JavaDoc welcomeFile)
711     {
712         if (welcomeFile.startsWith("/") ||
713             welcomeFile.startsWith(java.io.File.separator) ||
714             welcomeFile.endsWith("/") ||
715             welcomeFile.endsWith(java.io.File.separator))
716             log.warn("Invalid welcome file: "+welcomeFile);
717         List JavaDoc list = new ArrayList JavaDoc(Arrays.asList(_welcomes));
718         list.add(welcomeFile);
719         _welcomes=(String JavaDoc[])list.toArray(_welcomes);
720     }
721
722     /* ------------------------------------------------------------ */
723     public void removeWelcomeFile(String JavaDoc welcomeFile)
724     {
725         List JavaDoc list = new ArrayList JavaDoc(Arrays.asList(_welcomes));
726         list.remove(welcomeFile);
727         _welcomes=(String JavaDoc[])list.toArray(_welcomes);
728     }
729
730     /* ------------------------------------------------------------ */
731     public String JavaDoc getWelcomeFile(Resource resource)
732         throws IOException JavaDoc
733     {
734         if (!resource.isDirectory())
735             return null;
736
737         for (int i=0;i<_welcomes.length;i++)
738         {
739             Resource welcome=resource.addPath(_welcomes[i]);
740             if (welcome.exists())
741                 return _welcomes[i];
742         }
743
744         return null;
745     }
746
747
748     /* ------------------------------------------------------------ */
749     /** Get the context classpath.
750      * This method only returns the paths that have been set for this
751      * context and does not include any paths from a parent or the
752      * system classloader.
753      * Note that this may not be a legal javac classpath.
754      * @return a comma or ';' separated list of class
755      * resources. These may be jar files, directories or URLs to jars
756      * or directories.
757      * @see #getFileClassPath()
758      */

759     public String JavaDoc getClassPath()
760     {
761         return _classPath;
762     }
763
764     /* ------------------------------------------------------------ */
765     /** Get the file classpath of the context.
766      * This method makes a best effort to return a complete file
767      * classpath for the context.
768      * It is obtained by walking the classloader hierarchy and looking for
769      * URLClassLoaders. The system property java.class.path is also checked for
770      * file elements not already found in the loader hierarchy.
771      * @return Path of files and directories for loading classes.
772      * @exception IllegalStateException HttpContext.initClassLoader
773      * has not been called.
774      */

775     public String JavaDoc getFileClassPath()
776         throws IllegalStateException JavaDoc
777     {
778     
779         ClassLoader JavaDoc loader = getClassLoader();
780         if (loader==null)
781             throw new IllegalStateException JavaDoc("Context classloader not initialized");
782             
783         LinkedList JavaDoc paths =new LinkedList JavaDoc();
784         LinkedList JavaDoc loaders=new LinkedList JavaDoc();
785         
786         // Walk the loader hierarchy
787
while (loader !=null)
788         {
789             loaders.add(0,loader);
790             loader = loader.getParent();
791         }
792         
793         // Try to handle java2compliant modes
794
loader=getClassLoader();
795         if (loader instanceof ContextLoader && !((ContextLoader)loader).isJava2Compliant())
796         {
797             loaders.remove(loader);
798             loaders.add(0,loader);
799         }
800         
801         for (int i=0;i<loaders.size();i++)
802         {
803             loader=(ClassLoader JavaDoc)loaders.get(i);
804             
805             if (log.isDebugEnabled()) log.debug("extract paths from "+loader);
806             if (loader instanceof URLClassLoader JavaDoc)
807             {
808                 URL JavaDoc[] urls = ((URLClassLoader JavaDoc)loader).getURLs();
809                 for (int j=0;urls!=null && j<urls.length;j++)
810                 {
811                     try
812                     {
813                         Resource path = Resource.newResource(urls[j]);
814                         if (log.isTraceEnabled()) log.trace("path "+path);
815                         File JavaDoc file = path.getFile();
816                         if (file!=null)
817                             paths.add(file.getAbsolutePath());
818                     }
819                     catch(Exception JavaDoc e)
820                     {
821                         LogSupport.ignore(log,e);
822                     }
823                 }
824             }
825         }
826         
827         // Add the system classpath elements from property.
828
String JavaDoc jcp=System.getProperty("java.class.path");
829         if (jcp!=null)
830         {
831             StringTokenizer JavaDoc tok=new StringTokenizer JavaDoc(jcp,File.pathSeparator);
832             while (tok.hasMoreTokens())
833             {
834                 String JavaDoc path=tok.nextToken();
835                 if (!paths.contains(path))
836                 {
837                     if(log.isTraceEnabled())log.trace("PATH="+path);
838                     paths.add(path);
839                 }
840                 else
841                     if(log.isTraceEnabled())log.trace("done="+path);
842             }
843         }
844         
845         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
846         Iterator JavaDoc iter = paths.iterator();
847         while(iter.hasNext())
848         {
849             if (buf.length()>0)
850                 buf.append(File.pathSeparator);
851             buf.append(iter.next().toString());
852         }
853         
854         if (log.isDebugEnabled()) log.debug("fileClassPath="+buf);
855         return buf.toString();
856     }
857
858     /* ------------------------------------------------------------ */
859     /** Sets the class path for the context.
860      * A class path is only required for a context if it uses classes
861      * that are not in the system class path.
862      * @param classPath a comma or ';' separated list of class
863      * resources. These may be jar files, directories or URLs to jars
864      * or directories.
865      */

866     public void setClassPath(String JavaDoc classPath)
867     {
868         _classPath=classPath;
869         if (isStarted())
870             log.warn("classpath set while started");
871     }
872
873     /* ------------------------------------------------------------ */
874     /** Add the class path element to the context.
875      * A class path is only required for a context if it uses classes
876      * that are not in the system class path.
877      * @param classPath a comma or ';' separated list of class
878      * resources. These may be jar files, directories or URLs to jars
879      * or directories.
880      */

881     public void addClassPath(String JavaDoc classPath)
882     {
883         if (_classPath==null || _classPath.length()==0)
884             _classPath=classPath;
885         else
886             _classPath+=","+classPath;
887
888         if (isStarted())
889             log.warn("classpath set while started");
890     }
891
892     /* ------------------------------------------------------------ */
893     /** Add elements to the class path for the context from the jar and zip files found
894      * in the specified resource.
895      * @param lib the resource that contains the jar and/or zip files.
896      * @param append true if the classpath entries are to be appended to any
897      * existing classpath, or false if they replace the existing classpath.
898      * @see #setClassPath(String)
899      */

900     public void addClassPaths(Resource lib)
901     {
902         if (isStarted())
903             log.warn("classpaths set while started");
904
905         if (lib.exists() && lib.isDirectory())
906         {
907             String JavaDoc[] files=lib.list();
908             for (int f=0;files!=null && f<files.length;f++)
909             {
910                 try {
911                     Resource fn=lib.addPath(files[f]);
912                     String JavaDoc fnlc=fn.getName().toLowerCase();
913                     if (fnlc.endsWith(".jar") || fnlc.endsWith(".zip"))
914                     {
915                         addClassPath(fn.toString());
916                     }
917                 }
918                 catch (Exception JavaDoc ex)
919                 {
920                     log.warn(LogSupport.EXCEPTION,ex);
921                 }
922             }
923         }
924     }
925
926     /* ------------------------------------------------------------ */
927     /** Get Java2 compliant classloading.
928      * @return If true, the class loader will conform to the java 2
929      * specification and delegate all loads to the parent classloader. If
930      * false, the context classloader only delegate loads for system classes
931      * or classes that it can't find itself.
932      */

933     public boolean isClassLoaderJava2Compliant()
934     {
935         return _classLoaderJava2Compliant;
936     }
937
938     /* ------------------------------------------------------------ */
939     /** Set Java2 compliant classloading.
940      * @param compliant If true, the class loader will conform to the java 2
941      * specification and delegate all loads to the parent classloader. If
942      * false, the context classloader only delegate loads for system classes
943      * or classes that it can't find itself.
944      */

945     public void setClassLoaderJava2Compliant(boolean compliant)
946     {
947         _classLoaderJava2Compliant = compliant;
948         if (_loader!=null && (_loader instanceof ContextLoader))
949             ((ContextLoader)_loader).setJava2Compliant(compliant);
950     }
951
952     /* ------------------------------------------------------------ */
953     /** Set temporary directory for context.
954      * The javax.servlet.context.tempdir attribute is also set.
955      * @param dir Writable temporary directory.
956      */

957     public void setTempDirectory(File JavaDoc dir)
958     {
959         if (isStarted())
960             throw new IllegalStateException JavaDoc("Started");
961
962         if (dir!=null)
963         {
964             try{dir=new File JavaDoc(dir.getCanonicalPath());}
965             catch (IOException JavaDoc e){log.warn(LogSupport.EXCEPTION,e);}
966         }
967
968         if (dir!=null && !dir.exists())
969         {
970             dir.mkdir();
971             dir.deleteOnExit();
972         }
973
974         if (dir!=null && ( !dir.exists() || !dir.isDirectory() || !dir.canWrite()))
975             throw new IllegalArgumentException JavaDoc("Bad temp directory: "+dir);
976
977         _tmpDir=dir;
978         setAttribute("javax.servlet.context.tempdir",_tmpDir);
979     }
980
981     /* ------------------------------------------------------------ */
982     /** Get Context temporary directory.
983      * A tempory directory is generated if it has not been set. The
984      * "javax.servlet.context.tempdir" attribute is consulted and if
985      * not set, the host, port and context are used to generate a
986      * directory within the JVMs temporary directory.
987      * @return Temporary directory as a File.
988      */

989     public File JavaDoc getTempDirectory()
990     {
991         if (_tmpDir!=null)
992             return _tmpDir;
993
994         // Initialize temporary directory
995
//
996
// I'm afraid that this is very much black magic.
997
// but if you can think of better....
998
Object JavaDoc t = getAttribute("javax.servlet.context.tempdir");
999
1000        if (t!=null && (t instanceof File JavaDoc))
1001        {
1002            _tmpDir=(File JavaDoc)t;
1003            if (_tmpDir.isDirectory() && _tmpDir.canWrite())
1004                return _tmpDir;
1005        }
1006
1007        if (t!=null && (t instanceof String JavaDoc))
1008        {
1009            try
1010            {
1011                _tmpDir=new File JavaDoc((String JavaDoc)t);
1012
1013                if (_tmpDir.isDirectory() && _tmpDir.canWrite())
1014                {
1015                    if(log.isDebugEnabled())log.debug("Converted to File "+_tmpDir+" for "+this);
1016                    setAttribute("javax.servlet.context.tempdir",_tmpDir);
1017                    return _tmpDir;
1018                }
1019            }
1020            catch(Exception JavaDoc e)
1021            {
1022                log.warn(LogSupport.EXCEPTION,e);
1023            }
1024        }
1025
1026        // No tempdir so look for a WEB-INF/work directory to use as tempDir base
1027
File JavaDoc work=null;
1028        try
1029        {
1030            work=new File JavaDoc(System.getProperty("jetty.home"),"work");
1031            if (!work.exists() || !work.canWrite() || !work.isDirectory())
1032                work=null;
1033        }
1034        catch(Exception JavaDoc e)
1035        {
1036            LogSupport.ignore(log,e);
1037        }
1038
1039        // No tempdir set so make one!
1040
try
1041        {
1042            HttpListener httpListener=_httpServer.getListeners()[0];
1043
1044            String JavaDoc vhost = null;
1045            for (int h=0;vhost==null && _vhosts!=null && h<_vhosts.size();h++)
1046                vhost=(String JavaDoc)_vhosts.get(h);
1047            String JavaDoc host=httpListener.getHost();
1048            String JavaDoc temp="Jetty_"+
1049                (host==null?"":host)+
1050                "_"+
1051                httpListener.getPort()+
1052                "_"+
1053                (vhost==null?"":vhost)+
1054                getContextPath();
1055
1056            temp=temp.replace('/','_');
1057            temp=temp.replace('.','_');
1058            temp=temp.replace('\\','_');
1059
1060            
1061            if (work!=null)
1062                _tmpDir=new File JavaDoc(work,temp);
1063            else
1064            {
1065                _tmpDir=new File JavaDoc(System.getProperty("java.io.tmpdir"),temp);
1066                
1067                if (_tmpDir.exists())
1068                {
1069                    if(log.isDebugEnabled())log.debug("Delete existing temp dir "+_tmpDir+" for "+this);
1070                    if (!IO.delete(_tmpDir))
1071                    {
1072                        if(log.isDebugEnabled())log.debug("Failed to delete temp dir "+_tmpDir);
1073                    }
1074                
1075                    if (_tmpDir.exists())
1076                    {
1077                        String JavaDoc old=_tmpDir.toString();
1078                        _tmpDir=File.createTempFile(temp+"_","");
1079                        if (_tmpDir.exists())
1080                            _tmpDir.delete();
1081                        log.warn("Can't reuse "+old+", using "+_tmpDir);
1082                    }
1083                }
1084            }
1085
1086            if (!_tmpDir.exists())
1087                _tmpDir.mkdir();
1088            if (work==null)
1089                _tmpDir.deleteOnExit();
1090            if(log.isDebugEnabled())log.debug("Created temp dir "+_tmpDir+" for "+this);
1091        }
1092        catch(Exception JavaDoc e)
1093        {
1094            _tmpDir=null;
1095            LogSupport.ignore(log,e);
1096        }
1097
1098        if (_tmpDir==null)
1099        {
1100            try{
1101                // that didn't work, so try something simpler (ish)
1102
_tmpDir=File.createTempFile("JettyContext","");
1103                if (_tmpDir.exists())
1104                    _tmpDir.delete();
1105                _tmpDir.mkdir();
1106                _tmpDir.deleteOnExit();
1107                if(log.isDebugEnabled())log.debug("Created temp dir "+_tmpDir+" for "+this);
1108            }
1109            catch(IOException JavaDoc e)
1110            {
1111                log.fatal(e); System.exit(1);
1112            }
1113        }
1114
1115        setAttribute("javax.servlet.context.tempdir",_tmpDir);
1116        return _tmpDir;
1117    }
1118
1119
1120
1121    /* ------------------------------------------------------------ */
1122    /** Set ClassLoader.
1123     * @param loader The loader to be used by this context.
1124     */

1125    public synchronized void setClassLoader(ClassLoader JavaDoc loader)
1126    {
1127        if (isStarted())
1128            throw new IllegalStateException JavaDoc("Started");
1129        _loader=loader;
1130    }
1131
1132
1133    /* ------------------------------------------------------------ */
1134    /** Get the classloader.
1135     * If no classloader has been set and the context has been loaded
1136     * normally, then null is returned.
1137     * If no classloader has been set and the context was loaded from
1138     * a classloader, that loader is returned.
1139     * If a classloader has been set and no classpath has been set then
1140     * the set classloader is returned.
1141     * If a classloader and a classpath has been set, then a new
1142     * URLClassloader initialized on the classpath with the set loader as a
1143     * partent is return.
1144     * @return Classloader or null.
1145     */

1146    public synchronized ClassLoader JavaDoc getClassLoader()
1147    {
1148        return _loader;
1149    }
1150
1151    /* ------------------------------------------------------------ */
1152    /** Set Parent ClassLoader.
1153     * By default the parent loader is the thread context classloader
1154     * of the thread that calls initClassLoader. If setClassLoader is
1155     * called, then the parent is ignored.
1156     * @param loader The class loader to use for the parent loader of
1157     * the context classloader.
1158     */

1159    public synchronized void setParentClassLoader(ClassLoader JavaDoc loader)
1160    {
1161        if (isStarted())
1162            throw new IllegalStateException JavaDoc("Started");
1163        _parent=loader;
1164    }
1165
1166    /* ------------------------------------------------------------ */
1167    public ClassLoader JavaDoc getParentClassLoader()
1168    {
1169        return _parent;
1170    }
1171
1172    /* ------------------------------------------------------------ */
1173    /** Initialize the context classloader.
1174     * Initialize the context classloader with the current parameters.
1175     * Any attempts to change the classpath after this call will
1176     * result in a IllegalStateException
1177     * @param forceContextLoader If true, a ContextLoader is always if
1178     * no loader has been set.
1179     */

1180    protected void initClassLoader(boolean forceContextLoader)
1181        throws MalformedURLException JavaDoc, IOException JavaDoc
1182    {
1183        ClassLoader JavaDoc parent=_parent;
1184        if (_loader==null)
1185        {
1186            // If no parent, then try this threads classes loader as parent
1187
if (parent==null)
1188                parent=Thread.currentThread().getContextClassLoader();
1189
1190            // If no parent, then try this classes loader as parent
1191
if (parent==null)
1192                parent=this.getClass().getClassLoader();
1193
1194            if(log.isDebugEnabled())log.debug("Init classloader from "+_classPath+
1195                       ", "+parent+" for "+this);
1196
1197            if (forceContextLoader || _classPath!=null || _permissions!=null)
1198            {
1199                ContextLoader loader=new ContextLoader(this,_classPath,parent,_permissions);
1200                loader.setJava2Compliant(_classLoaderJava2Compliant);
1201                _loader=loader;
1202            }
1203            else
1204                _loader=parent;
1205        }
1206    }
1207
1208    /* ------------------------------------------------------------ */
1209    public synchronized Class JavaDoc loadClass(String JavaDoc className)
1210        throws ClassNotFoundException JavaDoc
1211    {
1212        if (_loader==null)
1213        {
1214            try{initClassLoader(false);}
1215            catch(Exception JavaDoc e)
1216            {
1217                log.warn(LogSupport.EXCEPTION,e);
1218                return null;
1219            }
1220        }
1221
1222        if (className==null)
1223            return null;
1224
1225        if (_loader == null)
1226            return Class.forName(className);
1227        return _loader.loadClass(className);
1228    }
1229
1230    /* ------------------------------------------------------------ */
1231    /** Set the realm name.
1232     * @param realmName The name to use to retrieve the actual realm
1233     * from the HttpServer
1234     */

1235    public void setRealmName(String JavaDoc realmName)
1236    {
1237        _realmName=realmName;
1238    }
1239
1240    /* ------------------------------------------------------------ */
1241    public String JavaDoc getRealmName()
1242    {
1243        return _realmName;
1244    }
1245
1246    /* ------------------------------------------------------------ */
1247    /** Set the realm.
1248     */

1249    public void setRealm(UserRealm realm)
1250    {
1251        _userRealm=realm;
1252    }
1253
1254    /* ------------------------------------------------------------ */
1255    public UserRealm getRealm()
1256    {
1257        return _userRealm;
1258    }
1259
1260    /* ------------------------------------------------------------ */
1261    public Authenticator getAuthenticator()
1262    {
1263        return _authenticator;
1264    }
1265
1266    /* ------------------------------------------------------------ */
1267    public void setAuthenticator(Authenticator authenticator)
1268    {
1269        _authenticator=authenticator;
1270    }
1271
1272    /* ------------------------------------------------------------ */
1273    public void addSecurityConstraint(String JavaDoc pathSpec, SecurityConstraint sc)
1274    {
1275        Object JavaDoc scs = _constraintMap.get(pathSpec);
1276        scs = LazyList.add(scs,sc);
1277        _constraintMap.put(pathSpec,scs);
1278        
1279        if(log.isDebugEnabled())log.debug("added "+sc+" at "+pathSpec);
1280    }
1281
1282    /* ------------------------------------------------------------ */
1283    public void clearSecurityConstraints()
1284    {
1285        _constraintMap.clear();
1286    }
1287
1288    /* ------------------------------------------------------------ */
1289    public boolean checkSecurityConstraints(
1290        String JavaDoc pathInContext,
1291        HttpRequest request,
1292        HttpResponse response)
1293        throws HttpException, IOException JavaDoc
1294    {
1295        UserRealm realm= getRealm();
1296
1297        List JavaDoc scss= _constraintMap.getMatches(pathInContext);
1298        String JavaDoc pattern=null;
1299        if (scss != null && scss.size() > 0)
1300        {
1301            Object JavaDoc constraints= null;
1302
1303            // for each path match
1304
// Add only constraints that have the correct method
1305
// break if the matching pattern changes. This allows only
1306
// constraints with matching pattern and method to be combined.
1307
loop:
1308            for (int m= 0; m < scss.size(); m++)
1309            {
1310                Map.Entry JavaDoc entry= (Map.Entry JavaDoc)scss.get(m);
1311                Object JavaDoc scs= entry.getValue();
1312                String JavaDoc p=(String JavaDoc)entry.getKey();
1313                for (int c=0;c<LazyList.size(scs);c++)
1314                {
1315                    SecurityConstraint sc=(SecurityConstraint)LazyList.get(scs,c);
1316                    if (!sc.forMethod(request.getMethod()))
1317                        continue;
1318                        
1319                    if (pattern!=null && !pattern.equals(p))
1320                        break loop;
1321                    pattern=p;
1322                    constraints= LazyList.add(constraints, sc);
1323                }
1324            }
1325            
1326            return SecurityConstraint.check(
1327                LazyList.getList(constraints),
1328                _authenticator,
1329                realm,
1330                pathInContext,
1331                request,
1332                response);
1333        }
1334        request.setUserPrincipal(HttpRequest.__NOT_CHECKED);
1335        return true;
1336    }
1337
1338    /* ------------------------------------------------------------ */
1339    /** Set null path redirection.
1340     * @param b if true a /context request will be redirected to
1341     * /context/ if there is not path in the context.
1342     */

1343    public void setRedirectNullPath(boolean b)
1344    {
1345        _redirectNullPath=b;
1346    }
1347
1348    /* ------------------------------------------------------------ */
1349    /**
1350     * @return True if a /context request is redirected to /context/ if
1351     * there is not path in the context.
1352     */

1353    public boolean isRedirectNullPath()
1354    {
1355        return _redirectNullPath;
1356    }
1357
1358
1359
1360    /* ------------------------------------------------------------ */
1361    /** Set the permissions to be used for this context.
1362     * The collection of permissions set here are used for all classes
1363     * loaded by this context. This is simpler that creating a
1364     * security policy file, as not all code sources may be statically
1365     * known.
1366     * @param permissions
1367     */

1368    public void setPermissions(PermissionCollection JavaDoc permissions)
1369    {
1370        _permissions=permissions;
1371    }
1372
1373    /* ------------------------------------------------------------ */
1374    /** Get the permissions to be used for this context.
1375     */

1376    public PermissionCollection JavaDoc getPermissions()
1377    {
1378        return _permissions;
1379    }
1380
1381    /* ------------------------------------------------------------ */
1382    /** Add a permission to this context.
1383     * The collection of permissions set here are used for all classes
1384     * loaded by this context. This is simpler that creating a
1385     * security policy file, as not all code sources may be statically
1386     * known.
1387     * @param permission
1388     */

1389    public void addPermission(Permission JavaDoc permission)
1390    {
1391        if (_permissions==null)
1392            _permissions=new Permissions JavaDoc();
1393        _permissions.add(permission);
1394    }
1395
1396    /* ------------------------------------------------------------ */
1397    /** Handler request.
1398     * Determine the path within the context and then call
1399     * handle(pathInContext,request,response).
1400     * @param request
1401     * @param response
1402     * @return True if the request has been handled.
1403     * @exception HttpException
1404     * @exception IOException
1405     */

1406    public void handle(HttpRequest request,
1407                       HttpResponse response)
1408        throws HttpException, IOException JavaDoc
1409    {
1410        if (!isStarted() || _gracefulStop)
1411            return;
1412
1413        // reject requests by real host
1414
if (_hosts!=null && _hosts.size()>0)
1415        {
1416            Object JavaDoc o = request.getHttpConnection().getConnection();
1417            if (o instanceof Socket JavaDoc)
1418            {
1419                Socket JavaDoc s=(Socket JavaDoc)o;
1420                if (!_hosts.contains(s.getLocalAddress()))
1421                {
1422                    if(log.isDebugEnabled())log.debug(s.getLocalAddress()+" not in "+_hosts);
1423                    return;
1424                }
1425            }
1426        }
1427        
1428        // handle stats
1429
if (_statsOn)
1430        {
1431            synchronized(_statsLock)
1432            {
1433                _requests++;
1434                _requestsActive++;
1435                if (_requestsActive>_requestsActiveMax)
1436                    _requestsActiveMax=_requestsActive;
1437            }
1438        }
1439
1440        String JavaDoc pathInContext = URI.canonicalPath(request.getPath());
1441        if (pathInContext==null)
1442        {
1443            // Must be a bad request.
1444
throw new HttpException(HttpResponse.__400_Bad_Request);
1445        }
1446
1447        if (_contextPath.length()>1)
1448            pathInContext=pathInContext.substring(_contextPath.length());
1449
1450        if (_redirectNullPath && (pathInContext==null ||
1451                                  pathInContext.length()==0))
1452        {
1453            StringBuffer JavaDoc buf=request.getRequestURL();
1454            buf.append("/");
1455            String JavaDoc q=request.getQuery();
1456            if (q!=null&&q.length()!=0)
1457                buf.append("?"+q);
1458                
1459            response.sendRedirect(buf.toString());
1460            if (log.isDebugEnabled())
1461                log.debug(this+" consumed all of path "+
1462                             request.getPath()+
1463                             ", redirect to "+buf.toString());
1464            return;
1465        }
1466
1467        String JavaDoc pathParams=null;
1468        int semi = pathInContext.lastIndexOf(';');
1469        if (semi>=0)
1470        {
1471            int pl = pathInContext.length()-semi;
1472            String JavaDoc ep=request.getEncodedPath();
1473            if(';'==ep.charAt(ep.length()-pl))
1474            {
1475                pathParams=pathInContext.substring(semi+1);
1476                pathInContext=pathInContext.substring(0,semi);
1477            }
1478        }
1479
1480        try
1481        {
1482            handle(pathInContext,pathParams,request,response);
1483        }
1484        finally
1485        {
1486            if (_userRealm!=null && request.hasUserPrincipal())
1487                _userRealm.disassociate(request.getUserPrincipal());
1488        }
1489    }
1490
1491    /* ------------------------------------------------------------ */
1492    /** Handler request.
1493     * Call each HttpHandler until request is handled.
1494     * @param pathInContext Path in context
1495     * @param pathParams Path parameters such as encoded Session ID
1496     * @param request
1497     * @param response
1498     * @return True if the request has been handled.
1499     * @exception HttpException
1500     * @exception IOException
1501     */

1502    public void handle(String JavaDoc pathInContext,
1503                       String JavaDoc pathParams,
1504                       HttpRequest request,
1505                       HttpResponse response)
1506        throws HttpException, IOException JavaDoc
1507    {
1508        Object JavaDoc old_scope= null;
1509        try
1510        {
1511            old_scope= enterContextScope(request,response);
1512            HttpHandler[] handlers= getHandlers();
1513            for (int k= 0; k < handlers.length; k++)
1514            {
1515                HttpHandler handler= handlers[k];
1516                if (handler == null)
1517                {
1518                    handlers= getHandlers();
1519                    k= -1;
1520                    continue;
1521                }
1522                if (!handler.isStarted())
1523                {
1524                    if (log.isDebugEnabled())
1525                        log.debug(handler + " not started in " + this);
1526                    continue;
1527                }
1528                if (log.isDebugEnabled())
1529                    log.debug("Handler " + handler);
1530                handler.handle(pathInContext, pathParams, request, response);
1531                if (request.isHandled())
1532                {
1533                    if (log.isDebugEnabled())
1534                        log.debug("Handled by " + handler);
1535                    return;
1536                }
1537            }
1538            return;
1539        }
1540        finally
1541        {
1542            leaveContextScope(request, response, old_scope);
1543        }
1544    }
1545
1546    /* ------------------------------------------------------------ */
1547    /** Enter the context scope.
1548     * This method is called (by handle or servlet dispatchers) to indicate that
1549     * request handling is entering the scope of this context. The opaque scope object
1550     * returned, should be passed to the leaveContextScope method.
1551     */

1552    public Object JavaDoc enterContextScope(HttpRequest request, HttpResponse response)
1553    {
1554        // Save the thread context loader
1555
Thread JavaDoc thread = Thread.currentThread();
1556        ClassLoader JavaDoc cl=thread.getContextClassLoader();
1557        HttpContext c=response.getHttpContext();
1558
1559        Scope scope=null;
1560        if (cl!=HttpContext.class.getClassLoader() || c!=null)
1561        {
1562            scope=new Scope();
1563            scope._classLoader=cl;
1564            scope._httpContext=c;
1565        }
1566        
1567        if (_loader!=null)
1568            thread.setContextClassLoader(_loader);
1569        response.setHttpContext(this);
1570            
1571        return scope;
1572    }
1573    
1574    /* ------------------------------------------------------------ */
1575    /** Leave the context scope.
1576     * This method is called (by handle or servlet dispatchers) to indicate that
1577     * request handling is leaveing the scope of this context. The opaque scope object
1578     * returned by enterContextScope should be passed in.
1579     */

1580    public void leaveContextScope(HttpRequest request, HttpResponse response,Object JavaDoc oldScope)
1581    {
1582        if (oldScope==null)
1583        {
1584            Thread.currentThread()
1585                .setContextClassLoader(HttpContext.class.getClassLoader());
1586            response.setHttpContext(null);
1587        }
1588        else
1589        {
1590            Scope old = (Scope)oldScope;
1591            Thread.currentThread().setContextClassLoader(old._classLoader);
1592            response.setHttpContext(old._httpContext);
1593        }
1594    }
1595    
1596
1597    /* ------------------------------------------------------------ */
1598    public String JavaDoc getHttpContextName()
1599    {
1600        if (_contextName==null)
1601            _contextName = (_vhosts.size()>1?(_vhosts.toString()+":"):"")+_contextPath;
1602        return _contextName;
1603    }
1604
1605    /* ------------------------------------------------------------ */
1606    public void setHttpContextName(String JavaDoc s)
1607    {
1608        _contextName=s;
1609    }
1610    
1611    /* ------------------------------------------------------------ */
1612    public String JavaDoc toString()
1613    {
1614        return "HttpContext["+getContextPath()+","+getHttpContextName()+"]";
1615    }
1616
1617    /* ------------------------------------------------------------ */
1618    public String JavaDoc toString(boolean detail)
1619    {
1620        return "HttpContext["+getContextPath()+","+getHttpContextName()+"]" +
1621            (detail?("="+_handlers):"");
1622    }
1623
1624    
1625    /* ------------------------------------------------------------ */
1626    protected synchronized void doStart()
1627        throws Exception JavaDoc
1628    {
1629        if (isStarted())
1630            return;
1631
1632        if (_httpServer.getServerClasses()!=null)
1633            _serverClasses=_httpServer.getServerClasses();
1634        if (_httpServer.getSystemClasses()!=null)
1635            _systemClasses=_httpServer.getSystemClasses();
1636        
1637        _resources.start();
1638        
1639        statsReset();
1640
1641        if (_httpServer==null)
1642            throw new IllegalStateException JavaDoc("No server for "+this);
1643
1644        // start the context itself
1645
_resources.getMimeMap();
1646        _resources.getEncodingMap();
1647
1648        // Setup realm
1649
if (_userRealm==null && _authenticator!=null)
1650        {
1651            _userRealm=_httpServer.getRealm(_realmName);
1652            if (_userRealm==null)
1653                log.warn("No Realm: "+_realmName);
1654        }
1655
1656        // setup the context loader
1657
initClassLoader(false);
1658
1659        // Set attribute if needed
1660
String JavaDoc attr = getInitParameter(__fileClassPathAttr);
1661        if (attr!=null && attr.length()>0)
1662            setAttribute(attr,getFileClassPath());
1663
1664        // Start the handlers
1665
Thread JavaDoc thread = Thread.currentThread();
1666        ClassLoader JavaDoc lastContextLoader=thread.getContextClassLoader();
1667        try
1668        {
1669            if (_loader!=null)
1670                thread.setContextClassLoader(_loader);
1671
1672            if (_requestLog!=null)
1673                _requestLog.start();
1674            
1675            startHandlers();
1676        }
1677        finally
1678        {
1679            thread.setContextClassLoader(lastContextLoader);
1680            getHandlers();
1681        }
1682
1683    }
1684
1685    /* ------------------------------------------------------------ */
1686    /** Start the handlers.
1687     * This is called by start after the classloader has been
1688     * initialized and set as the thread context loader.
1689     * It may be specialized to provide custom handling
1690     * before any handlers are started.
1691     * @exception Exception
1692     */

1693    protected void startHandlers()
1694        throws Exception JavaDoc
1695    {
1696        // Prepare a multi exception
1697
MultiException mx = new MultiException();
1698
1699        Iterator JavaDoc handlers = _handlers.iterator();
1700        while(handlers.hasNext())
1701        {
1702            HttpHandler handler=(HttpHandler)handlers.next();
1703            if (!handler.isStarted())
1704                try{handler.start();}catch(Exception JavaDoc e){mx.add(e);}
1705        }
1706        mx.ifExceptionThrow();
1707    }
1708
1709    /* ------------------------------------------------------------ */
1710    /** Stop the context.
1711     * @param graceful If true and statistics are on, then this method will wait
1712     * for requestsActive to go to zero before calling stop()
1713     */

1714    public void stop(boolean graceful)
1715        throws InterruptedException JavaDoc
1716    {
1717        boolean gs=_gracefulStop;
1718        try
1719        {
1720            _gracefulStop=true;
1721            
1722            // wait for all requests to complete.
1723
while (graceful && _statsOn && _requestsActive>0 && _httpServer!=null)
1724                try {Thread.sleep(100);}
1725            catch (InterruptedException JavaDoc e){throw e;}
1726            catch (Exception JavaDoc e){LogSupport.ignore(log,e);}
1727            
1728            stop();
1729        }
1730        finally
1731        {
1732            _gracefulStop=gs;
1733        }
1734    }
1735
1736    /* ------------------------------------------------------------ */
1737    /** Stop the context.
1738     */

1739    protected void doStop()
1740        throws Exception JavaDoc
1741    {
1742        if (_httpServer==null)
1743            throw new InterruptedException JavaDoc("Destroy called");
1744
1745        synchronized(this)
1746        {
1747            // Notify the container for the stop
1748
Thread JavaDoc thread = Thread.currentThread();
1749            ClassLoader JavaDoc lastContextLoader=thread.getContextClassLoader();
1750            try
1751            {
1752                if (_loader!=null)
1753                    thread.setContextClassLoader(_loader);
1754                Iterator JavaDoc handlers = _handlers.iterator();
1755                while(handlers.hasNext())
1756                {
1757                    HttpHandler handler=(HttpHandler)handlers.next();
1758                    if (handler.isStarted())
1759                    {
1760                        try{handler.stop();}
1761                        catch(Exception JavaDoc e){log.warn(LogSupport.EXCEPTION,e);}
1762                    }
1763                }
1764                
1765                if (_requestLog!=null)
1766                    _requestLog.stop();
1767            }
1768            finally
1769            {
1770                thread.setContextClassLoader(lastContextLoader);
1771            }
1772            
1773            // TODO this is a poor test
1774
if (_loader instanceof ContextLoader)
1775            {
1776                ((ContextLoader)_loader).destroy();
1777                LogFactory.release(_loader);
1778            }
1779            
1780            _loader=null;
1781        }
1782        _resources.flushCache();
1783        _resources.stop();
1784    }
1785
1786
1787    /* ------------------------------------------------------------ */
1788    /** Destroy a context.
1789     * Destroy a context and remove it from the HttpServer. The
1790     * HttpContext must be stopped before it can be destroyed.
1791     */

1792    public void destroy()
1793    {
1794        if (isStarted())
1795            throw new IllegalStateException JavaDoc("Started");
1796
1797        if (_httpServer!=null)
1798            _httpServer.removeContext(this);
1799
1800        _httpServer=null;
1801        
1802        if (_handlers!=null)
1803            _handlers.clear();
1804        
1805        _handlers=null;
1806        _parent=null;
1807        _loader=null;
1808        if (_attributes!=null)
1809            _attributes.clear();
1810        _attributes=null;
1811        if (_initParams!=null)
1812            _initParams.clear();
1813        _initParams=null;
1814        if (_vhosts!=null)
1815            _vhosts.clear();
1816        _vhosts=null;
1817        _hosts=null;
1818        _tmpDir=null;
1819
1820        _permissions=null;
1821        
1822        removeComponent(_resources);
1823        if (_resources!=null)
1824        {
1825            _resources.flushCache();
1826            if (_resources.isStarted())
1827                try{_resources.stop();}catch(Exception JavaDoc e){LogSupport.ignore(log,e);}
1828                _resources.destroy();
1829        }
1830        _resources=null;
1831        
1832        super.destroy();
1833        
1834    }
1835
1836
1837    /* ------------------------------------------------------------ */
1838    /** Set the request log.
1839     * @param log RequestLog to use.
1840     */

1841    public void setRequestLog(RequestLog log)
1842    {
1843        _requestLog=log;
1844    }
1845
1846    /* ------------------------------------------------------------ */
1847    public RequestLog getRequestLog()
1848    {
1849        return _requestLog;
1850    }
1851
1852
1853    /* ------------------------------------------------------------ */
1854    /** Send an error response.
1855     * This method may be specialized to provide alternative error handling for
1856     * errors generated by the container. The default implemenation calls HttpResponse.sendError
1857     * @param response the response to send
1858     * @param code The error code
1859     * @param msg The message for the error or null for the default
1860     * @throws IOException Problem sending response.
1861     */

1862    public void sendError(HttpResponse response,int code,String JavaDoc msg)
1863        throws IOException JavaDoc
1864    {
1865        response.sendError(code,msg);
1866    }
1867    
1868    /* ------------------------------------------------------------ */
1869    /** Send an error response.
1870     * This method obtains the responses context and call sendError for context specific
1871     * error handling.
1872     * @param response the response to send
1873     * @param code The error code
1874     * @param msg The message for the error or null for the default
1875     * @throws IOException Problem sending response.
1876     */

1877    public static void sendContextError(HttpResponse response,int code,String JavaDoc msg)
1878        throws IOException JavaDoc
1879    {
1880        HttpContext context = response.getHttpContext();
1881        if (context!=null)
1882            context.sendError(response,code,msg);
1883        else
1884            response.sendError(code,msg);
1885    }
1886    
1887    /* ------------------------------------------------------------ */
1888    /** True set statistics recording on for this context.
1889     * @param on If true, statistics will be recorded for this context.
1890     */

1891    public void setStatsOn(boolean on)
1892    {
1893        log.info("setStatsOn "+on+" for "+this);
1894        _statsOn=on;
1895        statsReset();
1896    }
1897
1898    /* ------------------------------------------------------------ */
1899    public boolean getStatsOn() {return _statsOn;}
1900
1901    /* ------------------------------------------------------------ */
1902    public long getStatsOnMs()
1903    {return _statsOn?(System.currentTimeMillis()-_statsStartedAt):0;}
1904
1905    /* ------------------------------------------------------------ */
1906    public void statsReset()
1907    {
1908        synchronized(_statsLock)
1909        {
1910            if (_statsOn)
1911                _statsStartedAt=System.currentTimeMillis();
1912            _requests=0;
1913            _requestsActiveMax=_requestsActive;
1914            _responses1xx=0;
1915            _responses2xx=0;
1916            _responses3xx=0;
1917            _responses4xx=0;
1918            _responses5xx=0;
1919        }
1920    }
1921
1922    /* ------------------------------------------------------------ */
1923    /**
1924     * @return Get the number of requests handled by this context
1925     * since last call of statsReset(). If setStatsOn(false) then this
1926     * is undefined.
1927     */

1928    public int getRequests() {return _requests;}
1929
1930    /* ------------------------------------------------------------ */
1931    /**
1932     * @return Number of requests currently active.
1933     * Undefined if setStatsOn(false).
1934     */

1935    public int getRequestsActive() {return _requestsActive;}
1936
1937    /* ------------------------------------------------------------ */
1938    /**
1939     * @return Maximum number of active requests
1940     * since statsReset() called. Undefined if setStatsOn(false).
1941     */

1942    public int getRequestsActiveMax() {return _requestsActiveMax;}
1943
1944    /* ------------------------------------------------------------ */
1945    /**
1946     * @return Get the number of responses with a 2xx status returned
1947     * by this context since last call of statsReset(). Undefined if
1948     * if setStatsOn(false).
1949     */

1950    public int getResponses1xx() {return _responses1xx;}
1951
1952    /* ------------------------------------------------------------ */
1953    /**
1954     * @return Get the number of responses with a 100 status returned
1955     * by this context since last call of statsReset(). Undefined if
1956     * if setStatsOn(false).
1957     */

1958    public int getResponses2xx() {return _responses2xx;}
1959
1960    /* ------------------------------------------------------------ */
1961    /**
1962     * @return Get the number of responses with a 3xx status returned
1963     * by this context since last call of statsReset(). Undefined if
1964     * if setStatsOn(false).
1965     */

1966    public int getResponses3xx() {return _responses3xx;}
1967
1968    /* ------------------------------------------------------------ */
1969    /**
1970     * @return Get the number of responses with a 4xx status returned
1971     * by this context since last call of statsReset(). Undefined if
1972     * if setStatsOn(false).
1973     */

1974    public int getResponses4xx() {return _responses4xx;}
1975
1976    /* ------------------------------------------------------------ */
1977    /**
1978     * @return Get the number of responses with a 5xx status returned
1979     * by this context since last call of statsReset(). Undefined if
1980     * if setStatsOn(false).
1981     */

1982    public int getResponses5xx() {return _responses5xx;}
1983
1984
1985    /* ------------------------------------------------------------ */
1986    /** Log a request and response.
1987     * Statistics are also collected by this method.
1988     * @param request
1989     * @param response
1990     */

1991    public void log(HttpRequest request,
1992                    HttpResponse response,
1993                    int length)
1994    {
1995        if (_statsOn)
1996        {
1997            synchronized(_statsLock)
1998            {
1999                if (--_requestsActive<0)
2000                    _requestsActive=0;
2001
2002                if (response!=null)
2003                {
2004                    switch(response.getStatus()/100)
2005                    {
2006                      case 1: _responses1xx++;break;
2007                      case 2: _responses2xx++;break;
2008                      case 3: _responses3xx++;break;
2009                      case 4: _responses4xx++;break;
2010                      case 5: _responses5xx++;break;
2011                    }
2012                }
2013            }
2014        }
2015
2016        if (_requestLog!=null &&
2017            request!=null &&
2018            response!=null)
2019            _requestLog.log(request,response,length);
2020        else if (_httpServer!=null)
2021            _httpServer.log(request,response,length);
2022    }
2023
2024    
2025
2026    /* ------------------------------------------------------------ */
2027    /* Class to save scope of nested context calls
2028     */

2029    private static class Scope
2030    {
2031        ClassLoader JavaDoc _classLoader;
2032        HttpContext _httpContext;
2033    }
2034
2035    /*
2036     * @see org.mortbay.http.HttpHandler#getName()
2037     */

2038    public String JavaDoc getName()
2039    {
2040        return this.getContextPath();
2041    }
2042
2043    /*
2044     * @see org.mortbay.http.HttpHandler#getHttpContext()
2045     */

2046    public HttpContext getHttpContext()
2047    {
2048        return this;
2049    }
2050
2051    /*
2052     * @see org.mortbay.http.HttpHandler#initialize(org.mortbay.http.HttpContext)
2053     */

2054    public void initialize(HttpContext context)
2055    {
2056        throw new UnsupportedOperationException JavaDoc();
2057    }
2058    
2059    
2060    /**
2061     * @return
2062     */

2063    public Resource getBaseResource()
2064    {
2065        return _resources.getBaseResource();
2066    }
2067    /**
2068     * @param type
2069     * @return
2070     */

2071    public String JavaDoc getEncodingByMimeType(String JavaDoc type)
2072    {
2073        return _resources.getEncodingByMimeType(type);
2074    }
2075    /**
2076     * @return
2077     */

2078    public Map JavaDoc getEncodingMap()
2079    {
2080        return _resources.getEncodingMap();
2081    }
2082    /**
2083     * @return
2084     */

2085    public int getMaxCachedFileSize()
2086    {
2087        return _resources.getMaxCachedFileSize();
2088    }
2089    /**
2090     * @return
2091     */

2092    public int getMaxCacheSize()
2093    {
2094        return _resources.getMaxCacheSize();
2095    }
2096    /**
2097     * @param filename
2098     * @return
2099     */

2100    public String JavaDoc getMimeByExtension(String JavaDoc filename)
2101    {
2102        return _resources.getMimeByExtension(filename);
2103    }
2104    /**
2105     * @return
2106     */

2107    public Map JavaDoc getMimeMap()
2108    {
2109        return _resources.getMimeMap();
2110    }
2111    /**
2112     * @param pathInContext
2113     * @return
2114     * @throws IOException
2115     */

2116    public Resource getResource(String JavaDoc pathInContext) throws IOException JavaDoc
2117    {
2118        return _resources.getResource(pathInContext);
2119    }
2120    /**
2121     * @return
2122     */

2123    public String JavaDoc getResourceBase()
2124    {
2125        return _resources.getResourceBase();
2126    }
2127    /**
2128     * @param resource
2129     * @return
2130     */

2131    public ResourceMetaData getResourceMetaData(Resource resource)
2132    {
2133        return _resources.getResourceMetaData(resource);
2134    }
2135    /**
2136     * @param base
2137     */

2138    public void setBaseResource(Resource base)
2139    {
2140        _resources.setBaseResource(base);
2141    }
2142    /**
2143     * @param encodingMap
2144     */

2145    public void setEncodingMap(Map JavaDoc encodingMap)
2146    {
2147        _resources.setEncodingMap(encodingMap);
2148    }
2149    /**
2150     * @param maxCachedFileSize
2151     */

2152    public void setMaxCachedFileSize(int maxCachedFileSize)
2153    {
2154        _resources.setMaxCachedFileSize(maxCachedFileSize);
2155    }
2156    /**
2157     * @param maxCacheSize
2158     */

2159    public void setMaxCacheSize(int maxCacheSize)
2160    {
2161        _resources.setMaxCacheSize(maxCacheSize);
2162    }
2163    /**
2164     * @param mimeMap
2165     */

2166    public void setMimeMap(Map JavaDoc mimeMap)
2167    {
2168        _resources.setMimeMap(mimeMap);
2169    }
2170    /**
2171     * @param extension
2172     * @param type
2173     */

2174    public void setMimeMapping(String JavaDoc extension, String JavaDoc type)
2175    {
2176        _resources.setMimeMapping(extension, type);
2177    }
2178    /**
2179     * @param resourceBase
2180     */

2181    public void setResourceBase(String JavaDoc resourceBase)
2182    {
2183        _resources.setResourceBase(resourceBase);
2184    }
2185    /**
2186     * @param mimeType
2187     * @param encoding
2188     */

2189    public void setTypeEncoding(String JavaDoc mimeType, String JavaDoc encoding)
2190    {
2191        _resources.setTypeEncoding(mimeType, encoding);
2192    }
2193}
2194
Popular Tags