View Javadoc

1   // ========================================================================
2   // Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at 
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses. 
12  // ========================================================================
13  
14  package org.eclipse.jetty.server.handler;
15  
16  import java.io.File;
17  import java.io.IOException;
18  import java.io.InputStream;
19  import java.net.MalformedURLException;
20  import java.net.URL;
21  import java.net.URLClassLoader;
22  import java.util.Arrays;
23  import java.util.Collections;
24  import java.util.EnumSet;
25  import java.util.Enumeration;
26  import java.util.EventListener;
27  import java.util.HashMap;
28  import java.util.HashSet;
29  import java.util.Locale;
30  import java.util.Map;
31  import java.util.Set;
32  
33  import javax.servlet.Filter;
34  import javax.servlet.RequestDispatcher;
35  import javax.servlet.Servlet;
36  import javax.servlet.ServletContext;
37  import javax.servlet.ServletContextAttributeEvent;
38  import javax.servlet.ServletContextAttributeListener;
39  import javax.servlet.ServletContextEvent;
40  import javax.servlet.ServletContextListener;
41  import javax.servlet.ServletException;
42  import javax.servlet.ServletRequestAttributeListener;
43  import javax.servlet.ServletRequestEvent;
44  import javax.servlet.ServletRequestListener;
45  import javax.servlet.http.HttpServletRequest;
46  import javax.servlet.http.HttpServletResponse;
47  
48  import org.eclipse.jetty.http.HttpException;
49  import org.eclipse.jetty.http.MimeTypes;
50  import org.eclipse.jetty.io.Buffer;
51  import org.eclipse.jetty.server.Dispatcher;
52  import org.eclipse.jetty.server.DispatcherType;
53  import org.eclipse.jetty.server.Handler;
54  import org.eclipse.jetty.server.HandlerContainer;
55  import org.eclipse.jetty.server.HttpConnection;
56  import org.eclipse.jetty.server.Request;
57  import org.eclipse.jetty.server.Server;
58  import org.eclipse.jetty.util.Attributes;
59  import org.eclipse.jetty.util.AttributesMap;
60  import org.eclipse.jetty.util.LazyList;
61  import org.eclipse.jetty.util.Loader;
62  import org.eclipse.jetty.util.URIUtil;
63  import org.eclipse.jetty.util.log.Log;
64  import org.eclipse.jetty.util.log.Logger;
65  import org.eclipse.jetty.util.resource.Resource;
66  
67  /* ------------------------------------------------------------ */
68  /** ContextHandler.
69   * 
70   * This handler wraps a call to handle by setting the context and
71   * servlet path, plus setting the context classloader.
72   * 
73   * <p>
74   * If the context init parameter "org.eclipse.jetty.servlet.ManagedAttributes"
75   * is set to a coma separated list of names, then they are treated as context
76   * attribute names, which if set as attributes are passed to the servers Container
77   * so that they may be managed with JMX.
78   * 
79   * @org.apache.xbean.XBean description="Creates a basic HTTP context"
80   *
81   * 
82   *
83   */
84  public class ContextHandler extends ScopedHandler implements Attributes, Server.Graceful, CompleteHandler
85  {
86      private static final ThreadLocal<Context> __context=new ThreadLocal<Context>();
87      public static final String MANAGED_ATTRIBUTES = "org.eclipse.jetty.server.servlet.ManagedAttributes";
88      
89      /* ------------------------------------------------------------ */
90      /** Get the current ServletContext implementation.
91       * This call is only valid during a call to doStart and is available to
92       * nested handlers to access the context.
93       * 
94       * @return ServletContext implementation
95       */
96      public static Context getCurrentContext()
97      {
98          return __context.get();
99      }
100 
101     protected Context _scontext;
102     
103     private AttributesMap _attributes;
104     private AttributesMap _contextAttributes;
105     private ClassLoader _classLoader;
106     private String _contextPath="/";
107     private Map<String,String> _initParams;
108     private String _displayName;
109     private Resource _baseResource;  
110     private MimeTypes _mimeTypes;
111     private Map<String,String> _localeEncodingMap;
112     private String[] _welcomeFiles;
113     private ErrorHandler _errorHandler;
114     private String[] _vhosts;
115     private Set<String> _connectors;
116     private EventListener[] _eventListeners;
117     private Logger _logger;
118     private boolean _allowNullPathInfo;
119     private int _maxFormContentSize=Integer.getInteger("org.eclipse.jetty.server.Request.maxFormContentSize",200000).intValue();
120     private boolean _compactPath=false;
121     private boolean _aliases=false;
122 
123     private Object _contextListeners;
124     private Object _contextAttributeListeners;
125     private Object _requestListeners;
126     private Object _requestAttributeListeners;
127     private Set<String> _managedAttributes;
128 
129     private boolean _shutdown=false;
130     private boolean _available=true;  
131     private volatile int _availability;  // 0=STOPPED, 1=AVAILABLE, 2=SHUTDOWN, 3=UNAVAILABLE
132     
133     private final static int __STOPPED=0,__AVAILABLE=1,__SHUTDOWN=2,__UNAVAILABLE=3;
134     
135     
136     /* ------------------------------------------------------------ */
137     /**
138      * 
139      */
140     public ContextHandler()
141     {
142         super();
143         _scontext=new Context();
144         _attributes=new AttributesMap();
145         _initParams=new HashMap<String,String>();
146     }
147     
148     /* ------------------------------------------------------------ */
149     /**
150      * 
151      */
152     protected ContextHandler(Context context)
153     {
154         super();
155         _scontext=context;
156         _attributes=new AttributesMap();
157         _initParams=new HashMap<String,String>();
158     }
159     
160     /* ------------------------------------------------------------ */
161     /**
162      * 
163      */
164     public ContextHandler(String contextPath)
165     {
166         this();
167         setContextPath(contextPath);
168     }
169     
170     /* ------------------------------------------------------------ */
171     /**
172      * 
173      */
174     public ContextHandler(HandlerContainer parent, String contextPath)
175     {
176         this();
177         setContextPath(contextPath);
178         if (parent instanceof HandlerWrapper)
179             ((HandlerWrapper)parent).setHandler(this);
180         else if (parent instanceof HandlerCollection)
181             ((HandlerCollection)parent).addHandler(this);
182     }
183 
184     /* ------------------------------------------------------------ */
185     public Context getServletContext()
186     {
187         return _scontext;
188     }
189     
190     /* ------------------------------------------------------------ */
191     /**
192      * @return the allowNullPathInfo true if /context is not redirected to /context/
193      */
194     public boolean getAllowNullPathInfo()
195     {
196         return _allowNullPathInfo;
197     }
198 
199     /* ------------------------------------------------------------ */
200     /**
201      * @param allowNullPathInfo  true if /context is not redirected to /context/
202      */
203     public void setAllowNullPathInfo(boolean allowNullPathInfo)
204     {
205         _allowNullPathInfo=allowNullPathInfo;
206     }
207 
208     /* ------------------------------------------------------------ */
209     public void setServer(Server server)
210     {
211         if (_errorHandler!=null)
212         {
213             Server old_server=getServer();
214             if (old_server!=null && old_server!=server)
215                 old_server.getContainer().update(this, _errorHandler, null, "error",true);
216             super.setServer(server); 
217             if (server!=null && server!=old_server)
218                 server.getContainer().update(this, null, _errorHandler, "error",true);
219             _errorHandler.setServer(server); 
220         }
221         else
222             super.setServer(server); 
223     }
224 
225     /* ------------------------------------------------------------ */
226     /** Set the virtual hosts for the context.
227      * Only requests that have a matching host header or fully qualified
228      * URL will be passed to that context with a virtual host name.
229      * A context with no virtual host names or a null virtual host name is
230      * available to all requests that are not served by a context with a
231      * matching virtual host name.
232      * @param vhosts Array of virtual hosts that this context responds to. A
233      * null host name or null/empty array means any hostname is acceptable.
234      * Host names may be String representation of IP addresses. Host names may
235      * start with '*.' to wildcard one level of names.
236      */
237     public void setVirtualHosts( String[] vhosts )
238     {
239         if ( vhosts == null )
240         {
241             _vhosts = vhosts;
242         } 
243         else 
244         {
245             _vhosts = new String[vhosts.length];
246             for ( int i = 0; i < vhosts.length; i++ )
247                 _vhosts[i] = normalizeHostname( vhosts[i]);
248         }
249     }
250 
251     /* ------------------------------------------------------------ */
252     /** Get the virtual hosts for the context.
253      * Only requests that have a matching host header or fully qualified
254      * URL will be passed to that context with a virtual host name.
255      * A context with no virtual host names or a null virtual host name is
256      * available to all requests that are not served by a context with a
257      * matching virtual host name.
258      * @return Array of virtual hosts that this context responds to. A
259      * null host name or empty array means any hostname is acceptable.
260      * Host names may be String representation of IP addresses.
261      * Host names may start with '*.' to wildcard one level of names.
262      */
263     public String[] getVirtualHosts()
264     {
265         return _vhosts;
266     }
267 
268     /* ------------------------------------------------------------ */
269     /** 
270      * @deprecated use {@link #setConnectorNames(String[])} 
271      */
272     public void setHosts(String[] hosts)
273     {
274         setConnectorNames(hosts);
275     }
276 
277     /* ------------------------------------------------------------ */
278     /** Get the hosts for the context.
279      * @deprecated
280      */
281     public String[] getHosts()
282     {
283         return getConnectorNames();
284     }
285 
286     /* ------------------------------------------------------------ */
287     /**
288      * @return an array of connector names that this context
289      * will accept a request from.
290      */
291     public String[] getConnectorNames()
292     {
293         if (_connectors==null || _connectors.size()==0)
294             return null;
295             
296         return _connectors.toArray(new String[_connectors.size()]);
297     }
298 
299     /* ------------------------------------------------------------ */
300     /** Set the names of accepted connectors.
301      * 
302      * Names are either "host:port" or a specific configured name for a connector.
303      * 
304      * @param connectors If non null, an array of connector names that this context
305      * will accept a request from.
306      */
307     public void setConnectorNames(String[] connectors)
308     {
309         if (connectors==null || connectors.length==0)
310             _connectors=null;
311         else
312             _connectors= new HashSet<String>(Arrays.asList(connectors));
313     }
314     
315     /* ------------------------------------------------------------ */
316     /* 
317      * @see javax.servlet.ServletContext#getAttribute(java.lang.String)
318      */
319     public Object getAttribute(String name)
320     {
321         return _attributes.getAttribute(name);
322     }
323 
324     /* ------------------------------------------------------------ */
325     /* 
326      * @see javax.servlet.ServletContext#getAttributeNames()
327      */
328     @SuppressWarnings("unchecked")
329     public Enumeration getAttributeNames()
330     {
331         return AttributesMap.getAttributeNamesCopy(_attributes);
332     }
333     
334     /* ------------------------------------------------------------ */
335     /**
336      * @return Returns the attributes.
337      */
338     public Attributes getAttributes()
339     {
340         return _attributes;
341     }
342     
343     /* ------------------------------------------------------------ */
344     /**
345      * @return Returns the classLoader.
346      */
347     public ClassLoader getClassLoader()
348     {
349         return _classLoader;
350     }
351 
352     /* ------------------------------------------------------------ */
353     /**
354      * Make best effort to extract a file classpath from the context classloader
355      * @return Returns the classLoader.
356      */
357     public String getClassPath()
358     {
359         if ( _classLoader==null || !(_classLoader instanceof URLClassLoader))
360             return null;
361         URLClassLoader loader = (URLClassLoader)_classLoader;
362         URL[] urls =loader.getURLs();
363         StringBuilder classpath=new StringBuilder();
364         for (int i=0;i<urls.length;i++)
365         {
366             try
367             {
368                 Resource resource = newResource(urls[i]);
369                 File file=resource.getFile();
370                 if (file!=null && file.exists())
371                 {
372                     if (classpath.length()>0)
373                         classpath.append(File.pathSeparatorChar);
374                     classpath.append(file.getAbsolutePath());
375                 }
376             }
377             catch (IOException e)
378             {
379                 Log.debug(e);
380             }
381         }
382         if (classpath.length()==0)
383             return null;
384         return classpath.toString();
385     }
386 
387     /* ------------------------------------------------------------ */
388     /**
389      * @return Returns the _contextPath.
390      */
391     public String getContextPath()
392     {
393         return _contextPath;
394     }
395    
396     /* ------------------------------------------------------------ */
397     /* 
398      * @see javax.servlet.ServletContext#getInitParameter(java.lang.String)
399      */
400     public String getInitParameter(String name)
401     {
402         return _initParams.get(name);
403     }
404 
405     /* ------------------------------------------------------------ */
406     /* 
407      * @see javax.servlet.ServletContext#getInitParameterNames()
408      */
409     @SuppressWarnings("unchecked")
410     public Enumeration getInitParameterNames()
411     {
412         return Collections.enumeration(_initParams.keySet());
413     }
414     
415     /* ------------------------------------------------------------ */
416     /**
417      * @return Returns the initParams.
418      */
419     public Map<String,String> getInitParams()
420     {
421         return _initParams;
422     }
423 
424     /* ------------------------------------------------------------ */
425     /* 
426      * @see javax.servlet.ServletContext#getServletContextName()
427      */
428     public String getDisplayName()
429     {
430         return _displayName;
431     }
432 
433     /* ------------------------------------------------------------ */
434     public EventListener[] getEventListeners()
435     {
436         return _eventListeners;
437     }
438     
439     /* ------------------------------------------------------------ */
440     /**
441      * Set the context event listeners.
442      * @see ServletContextListener
443      * @see ServletContextAttributeListener
444      * @see ServletRequestListener
445      * @see ServletRequestAttributeListener
446      */
447     public void setEventListeners(EventListener[] eventListeners)
448     {
449         _contextListeners=null;
450         _contextAttributeListeners=null;
451         _requestListeners=null;
452         _requestAttributeListeners=null;
453         
454         _eventListeners=eventListeners;
455         
456         for (int i=0; eventListeners!=null && i<eventListeners.length;i ++)
457         {
458             EventListener listener = _eventListeners[i];
459             
460             if (listener instanceof ServletContextListener)
461                 _contextListeners= LazyList.add(_contextListeners, listener);
462             
463             if (listener instanceof ServletContextAttributeListener)
464                 _contextAttributeListeners= LazyList.add(_contextAttributeListeners, listener);
465             
466             if (listener instanceof ServletRequestListener)
467                 _requestListeners= LazyList.add(_requestListeners, listener);
468             
469             if (listener instanceof ServletRequestAttributeListener)
470                 _requestAttributeListeners= LazyList.add(_requestAttributeListeners, listener);
471         }
472     }     
473 
474     /* ------------------------------------------------------------ */
475     /**
476     * Add a context event listeners.
477     * @see ServletContextListener
478     * @see ServletContextAttributeListener
479     * @see ServletRequestListener
480     * @see ServletRequestAttributeListener
481     */
482     public void addEventListener(EventListener listener) 
483     {
484         setEventListeners((EventListener[])LazyList.addToArray(getEventListeners(), listener, EventListener.class));
485     }
486 
487     /* ------------------------------------------------------------ */
488     /**
489      * @return true if this context is accepting new requests
490      */
491     public boolean isShutdown()
492     {
493         return !_shutdown;
494     }
495 
496     /* ------------------------------------------------------------ */
497     /** Set shutdown status.
498      * This field allows for graceful shutdown of a context. A started context may be put into non accepting state so
499      * that existing requests can complete, but no new requests are accepted.
500      * @param shutdown true if this context is (not?) accepting new requests
501      */
502     public void setShutdown(boolean shutdown)
503     {
504         synchronized(this)
505         {
506             _shutdown = shutdown;
507             _availability=isRunning()?(_shutdown?__SHUTDOWN:_available?__AVAILABLE:__UNAVAILABLE):__STOPPED;
508         }
509     }
510 
511     /* ------------------------------------------------------------ */
512     /**
513      * @return false if this context is unavailable (sends 503)
514      */
515     public boolean isAvailable()
516     {
517         return _available;
518     }
519 
520     /* ------------------------------------------------------------ */
521     /** Set Available status.
522      */
523     public void setAvailable(boolean available)
524     {
525         synchronized(this)
526         {
527             _available = available;
528             _availability=isRunning()?(_shutdown?__SHUTDOWN:_available?__AVAILABLE:__UNAVAILABLE):__STOPPED;
529         }
530     }
531 
532     /* ------------------------------------------------------------ */
533     public Logger getLogger()
534     {
535         return _logger;
536     }
537     
538     /* ------------------------------------------------------------ */
539     public void setLogger(Logger logger)
540     {
541         _logger=logger;
542     }
543     
544     /* ------------------------------------------------------------ */
545     /* 
546      * @see org.eclipse.thread.AbstractLifeCycle#doStart()
547      */
548     protected void doStart() throws Exception
549     {
550         _availability=__STOPPED;
551         
552         if (_contextPath==null)
553             throw new IllegalStateException("Null contextPath");
554         
555         _logger=Log.getLogger(getDisplayName()==null?getContextPath():getDisplayName());
556         ClassLoader old_classloader=null;
557         Thread current_thread=null;
558         Context old_context=null;
559 
560         _contextAttributes=new AttributesMap();
561         try
562         {
563             
564             // Set the classloader
565             if (_classLoader!=null)
566             {
567                 current_thread=Thread.currentThread();
568                 old_classloader=current_thread.getContextClassLoader();
569                 current_thread.setContextClassLoader(_classLoader);
570             }
571             
572 
573             if (_mimeTypes==null)
574                 _mimeTypes=new MimeTypes();
575             
576             old_context=__context.get();
577             __context.set(_scontext);
578             
579             if (_errorHandler==null)
580                 setErrorHandler(new ErrorHandler());
581             
582             
583             // defers the calling of super.doStart()
584             startContext();
585             
586 
587             _availability=_shutdown?__SHUTDOWN:_available?__AVAILABLE:__UNAVAILABLE;
588         }
589         finally
590         {
591             __context.set(old_context);
592             
593             // reset the classloader
594             if (_classLoader!=null)
595             {
596                 current_thread.setContextClassLoader(old_classloader);
597             }
598             
599         }
600     }
601 
602     /* ------------------------------------------------------------ */
603     /**
604      * Extensible startContext.
605      * this method is called from {@link ContextHandler#doStart()} instead of a 
606      * call to super.doStart().   This allows derived classes to insert additional
607      * handling (Eg configuration) before the call to super.doStart by this method
608      * will start contained handlers.
609      * @see org.eclipse.jetty.Scope.Context
610      * @see org.eclipse.jetty.webapp.WebAppContext
611      */
612     protected void startContext()
613     	throws Exception
614     {
615         super.doStart();
616 
617         if (_errorHandler!=null)
618             _errorHandler.start();
619         
620         // Context listeners
621         if (_contextListeners != null )
622         {
623             ServletContextEvent event= new ServletContextEvent(_scontext);
624             for (int i= 0; i < LazyList.size(_contextListeners); i++)
625             {
626                 ((ServletContextListener)LazyList.get(_contextListeners, i)).contextInitialized(event);
627             }
628         }
629 
630         String managedAttributes = _initParams.get(MANAGED_ATTRIBUTES);
631         if (managedAttributes!=null)
632         {
633             _managedAttributes=new HashSet<String>();
634             String[] attributes = managedAttributes.split(",");
635             _managedAttributes.addAll(Arrays.asList(attributes));
636 
637             Enumeration e = _scontext.getAttributeNames();
638             while(e.hasMoreElements())
639             {
640                 String name = (String)e.nextElement();
641                 Object value = _scontext.getAttribute(name);
642                 setManagedAttribute(name,value);
643             }
644         }       
645     }
646     
647     /* ------------------------------------------------------------ */
648     /* 
649      * @see org.eclipse.thread.AbstractLifeCycle#doStop()
650      */
651     protected void doStop() throws Exception
652     {
653         _availability=__STOPPED;
654         
655         ClassLoader old_classloader=null;
656         Thread current_thread=null;
657 
658         Context old_context=__context.get();
659         __context.set(_scontext);
660         try
661         {
662             // Set the classloader
663             if (_classLoader!=null)
664             {
665                 current_thread=Thread.currentThread();
666                 old_classloader=current_thread.getContextClassLoader();
667                 current_thread.setContextClassLoader(_classLoader);
668             }
669             
670             super.doStop();
671             
672             // Context listeners
673             if (_contextListeners != null )
674             {
675                 ServletContextEvent event= new ServletContextEvent(_scontext);
676                 for (int i=LazyList.size(_contextListeners); i-->0;)
677                 {
678                     ((ServletContextListener)LazyList.get(_contextListeners, i)).contextDestroyed(event);
679                 }
680             }
681 
682             if (_errorHandler!=null)
683                 _errorHandler.stop();
684             
685             Enumeration e = _scontext.getAttributeNames();
686             while(e.hasMoreElements())
687             {
688                 String name = (String)e.nextElement();
689                 setManagedAttribute(name,null);
690             }
691         }
692         finally
693         {
694             __context.set(old_context);
695             // reset the classloader
696             if (_classLoader!=null)
697                 current_thread.setContextClassLoader(old_classloader);
698         }
699 
700         if (_contextAttributes!=null)
701             _contextAttributes.clearAttributes();
702         _contextAttributes=null;
703     }
704 
705     /* ------------------------------------------------------------ */
706     /* 
707      * @see org.eclipse.jetty.server.Handler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
708      */
709     public boolean checkContext(final String target, final Request baseRequest, final HttpServletResponse response)
710             throws IOException, ServletException
711     {   
712         DispatcherType dispatch=baseRequest.getDispatcherType();
713         
714         switch(_availability)
715         {
716             case __STOPPED:
717             case __SHUTDOWN:
718                 return false;
719             case __UNAVAILABLE:
720                 response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
721                 return false;
722             default:
723                 if((DispatcherType.REQUEST.equals(dispatch) && baseRequest.isHandled()))
724                     return false;
725         }
726         
727         // Check the vhosts
728         if (_vhosts!=null && _vhosts.length>0)
729         {
730             String vhost = normalizeHostname( baseRequest.getServerName());
731 
732             boolean match=false;
733             
734             // TODO non-linear lookup
735             for (int i=0;!match && i<_vhosts.length;i++)
736             {
737                 String contextVhost = _vhosts[i];
738                 if(contextVhost==null) continue;
739                 if(contextVhost.startsWith("*.")) {
740                     // wildcard only at the beginning, and only for one additional subdomain level
741                     match=contextVhost.regionMatches(true,2,vhost,vhost.indexOf(".")+1,contextVhost.length()-2);
742                 } else
743                     match=contextVhost.equalsIgnoreCase(vhost);
744             }
745             if (!match)
746                 return false;
747         }
748         
749         // Check the connector
750         if (_connectors!=null && _connectors.size()>0)
751         {
752             String connector=HttpConnection.getCurrentConnection().getConnector().getName();
753             if (connector==null || !_connectors.contains(connector))
754                 return false;
755         }
756                 
757             
758         if (target.startsWith(_contextPath))
759         {
760             if (_contextPath.length()==target.length() && _contextPath.length()>1 &&!_allowNullPathInfo)
761             {
762                 // context request must end with /
763                 baseRequest.setHandled(true);
764                 if (baseRequest.getQueryString()!=null)
765                     response.sendRedirect(URIUtil.addPaths(baseRequest.getRequestURI(),URIUtil.SLASH)+"?"+baseRequest.getQueryString());
766                 else 
767                     response.sendRedirect(URIUtil.addPaths(baseRequest.getRequestURI(),URIUtil.SLASH));
768                 return false;
769             }
770         }
771         else
772         {
773             // Not for this context!
774             return false;
775         }
776         
777         return true;
778     }        
779         
780 
781 
782     /* ------------------------------------------------------------ */
783     /**
784      * @see org.eclipse.jetty.server.handler.ScopedHandler#doScope(java.lang.String, org.eclipse.jetty.server.Request, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
785      */
786     @Override
787     public void doScope(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
788     { 
789         Context old_context=null;
790         String old_context_path=null;
791         String old_servlet_path=null;
792         String old_path_info=null;
793         ClassLoader old_classloader=null;
794         Thread current_thread=null;
795         String pathInfo=null;
796 
797         DispatcherType dispatch=baseRequest.getDispatcherType();
798         
799         old_context=baseRequest.getContext();
800   
801         // Are we already in this context?
802         if (old_context!=_scontext)
803         {
804             // check the target.
805             if (DispatcherType.REQUEST.equals(dispatch) || DispatcherType.ASYNC.equals(dispatch))
806             {
807                 if (_compactPath)
808                     target=URIUtil.compactPath(target);
809                 if (!checkContext(target,baseRequest,response))
810                     return;
811                 
812                 if (target.length()>_contextPath.length())
813                 {
814                     if (_contextPath.length()>1)
815                         target=target.substring(_contextPath.length());
816                     pathInfo=target;
817                 }
818                 else if (_contextPath.length()==1)
819                 {
820                     target=URIUtil.SLASH;
821                     pathInfo=URIUtil.SLASH;
822                 }
823                 else
824                 {
825                     target=URIUtil.SLASH;
826                     pathInfo=null;
827                 }
828             }
829 
830             // Set the classloader
831             if (_classLoader!=null)
832             {
833                 current_thread=Thread.currentThread();
834                 old_classloader=current_thread.getContextClassLoader();
835                 current_thread.setContextClassLoader(_classLoader);
836             }
837         }
838         
839         try
840         {
841             old_context_path=baseRequest.getContextPath();
842             old_servlet_path=baseRequest.getServletPath();
843             old_path_info=baseRequest.getPathInfo();
844             
845             // Update the paths
846             baseRequest.setContext(_scontext);
847             if (!DispatcherType.INCLUDE.equals(dispatch) && target.startsWith("/"))
848             {
849                 if (_contextPath.length()==1)
850                     baseRequest.setContextPath("");
851                 else
852                     baseRequest.setContextPath(_contextPath);
853                 baseRequest.setServletPath(null);
854                 baseRequest.setPathInfo(pathInfo);
855             }
856             
857             // start manual inline of nextScope(target,baseRequest,request,response);
858             //noinspection ConstantIfStatement
859             if (false)
860                 nextScope(target,baseRequest,request,response);
861             else if (_nextScope!=null)
862                 _nextScope.doScope(target,baseRequest,request, response);
863             else if (_outerScope!=null)
864                 _outerScope.doHandle(target,baseRequest,request, response);
865             else 
866                 doHandle(target,baseRequest,request, response);
867             // end manual inline (pathentic attempt to reduce stack depth)
868         }
869         finally
870         {
871             if (old_context!=_scontext)
872             {
873                 // reset the classloader
874                 if (_classLoader!=null)
875                 {
876                     current_thread.setContextClassLoader(old_classloader);
877                 }
878                 
879                 // reset the context and servlet path.
880                 baseRequest.setContext(old_context);
881                 baseRequest.setContextPath(old_context_path);
882                 baseRequest.setServletPath(old_servlet_path);
883                 baseRequest.setPathInfo(old_path_info); 
884             }
885         }
886     }
887     
888     /* ------------------------------------------------------------ */
889     /**
890      * @see org.eclipse.jetty.server.handler.ScopedHandler#doHandle(java.lang.String, org.eclipse.jetty.server.Request, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
891      */
892     @Override
893     public void doHandle(String target,Request baseRequest,HttpServletRequest request,HttpServletResponse response) throws IOException, ServletException
894     {
895         final DispatcherType dispatch=baseRequest.getDispatcherType();
896         final boolean new_context=baseRequest.takeNewContext();
897         try
898         {
899             if (new_context)
900             {
901                 // Handle the REALLY SILLY request events!
902                 if (_requestAttributeListeners!=null)
903                 {
904                     final int s=LazyList.size(_requestAttributeListeners);
905                     for(int i=0;i<s;i++)
906                         baseRequest.addEventListener(((EventListener)LazyList.get(_requestAttributeListeners,i)));
907                 }
908 
909                 if (_requestListeners!=null)
910                 {
911                     final int s=LazyList.size(_requestListeners);
912                     final ServletRequestEvent sre = new ServletRequestEvent(_scontext,request);
913                     for(int i=0;i<s;i++)
914                         ((ServletRequestListener)LazyList.get(_requestListeners,i)).requestInitialized(sre);
915                 }
916             }
917             
918             if (DispatcherType.REQUEST.equals(dispatch) && isProtectedTarget(target))
919                 throw new HttpException(HttpServletResponse.SC_NOT_FOUND);
920             
921             // start manual inline of nextHandle(target,baseRequest,request,response);
922             //noinspection ConstantIfStatement
923             if (false)
924                 nextHandle(target,baseRequest,request,response);
925             else if (_nextScope!=null && _nextScope==_handler)
926                 _nextScope.doHandle(target,baseRequest,request, response);
927             else if (_handler!=null)
928                 _handler.handle(target,baseRequest, request, response);
929             // end manual inline
930         }
931         catch(HttpException e)
932         {
933             Log.debug(e);
934             response.sendError(e.getStatus(), e.getReason());
935         }
936         finally
937         {
938             // Handle more REALLY SILLY request events!
939             if (new_context)
940             {
941                 if (_requestListeners!=null)
942                 {
943                     final int s=LazyList.size(_requestListeners);
944                     final ServletRequestEvent sre = new ServletRequestEvent(_scontext,request);
945                     for(int i=0;i<s;i++)
946                         ((ServletRequestListener)LazyList.get(_requestListeners,i)).requestInitialized(sre);
947                 }
948                 
949                 if (_requestAttributeListeners!=null)
950                 {
951                     for(int i=LazyList.size(_requestAttributeListeners);i-->0;)
952                         baseRequest.removeEventListener(((EventListener)LazyList.get(_requestAttributeListeners,i)));
953                 }
954             }
955         }
956     }
957     
958     /* ------------------------------------------------------------ */
959     /* Handle a runnable in this context
960      */
961     public void handle(Runnable runnable)
962     {   
963         ClassLoader old_classloader=null;
964         Thread current_thread=null;
965         try
966         {
967             // Set the classloader
968             if (_classLoader!=null)
969             {
970                 current_thread=Thread.currentThread();
971                 old_classloader=current_thread.getContextClassLoader();
972                 current_thread.setContextClassLoader(_classLoader);
973             }
974             
975             runnable.run();
976         }
977         finally
978         {
979             if (old_classloader!=null)
980             {
981                 current_thread.setContextClassLoader(old_classloader);
982             }
983         }
984     }
985 
986     /* ------------------------------------------------------------ */
987     /** Check the target.
988      * Called by {@link #handle(String, Request, HttpServletRequest, HttpServletResponse)} when a
989      * target within a context is determined.  If the target is protected, 404 is returned.
990      * The default implementation always returns false.
991      * @see org.eclipse.jetty.webapp.WebAppContext#isProtectedTarget(String)
992      */
993     /* ------------------------------------------------------------ */
994     protected boolean isProtectedTarget(String target)
995     { 
996         return false;
997     }
998 
999     /* ------------------------------------------------------------ */
1000     /* 
1001      * @see javax.servlet.ServletContext#removeAttribute(java.lang.String)
1002      */
1003     public void removeAttribute(String name)
1004     {
1005         setManagedAttribute(name,null);
1006         _attributes.removeAttribute(name);
1007     }
1008 
1009     /* ------------------------------------------------------------ */
1010     /* Set a context attribute.
1011      * Attributes set via this API cannot be overriden by the ServletContext.setAttribute API.
1012      * Their lifecycle spans the stop/start of a context.  No attribute listener events are 
1013      * triggered by this API.
1014      * @see javax.servlet.ServletContext#setAttribute(java.lang.String, java.lang.Object)
1015      */
1016     public void setAttribute(String name, Object value)
1017     {
1018         setManagedAttribute(name,value);
1019         _attributes.setAttribute(name,value);
1020     }
1021     
1022     /* ------------------------------------------------------------ */
1023     /**
1024      * @param attributes The attributes to set.
1025      */
1026     public void setAttributes(Attributes attributes)
1027     {
1028         if (attributes instanceof AttributesMap)
1029         {
1030             _attributes = (AttributesMap)attributes;
1031             Enumeration e = _attributes.getAttributeNames();
1032             while (e.hasMoreElements())
1033             {
1034                 String name = (String)e.nextElement();
1035                 setManagedAttribute(name,attributes.getAttribute(name));
1036             }
1037         }
1038         else
1039         {
1040             _attributes=new AttributesMap();
1041             Enumeration e = attributes.getAttributeNames();
1042             while (e.hasMoreElements())
1043             {
1044                 String name = (String)e.nextElement();
1045                 Object value=attributes.getAttribute(name);
1046                 setManagedAttribute(name,value);
1047                 _attributes.setAttribute(name,value);
1048             }
1049         }
1050     }
1051 
1052     /* ------------------------------------------------------------ */
1053     public void clearAttributes()
1054     {
1055         Enumeration e = _attributes.getAttributeNames();
1056         while (e.hasMoreElements())
1057         {
1058             String name = (String)e.nextElement();
1059             setManagedAttribute(name,null);
1060         }
1061         _attributes.clearAttributes();
1062     }
1063 
1064     /* ------------------------------------------------------------ */
1065     private void setManagedAttribute(String name, Object value)
1066     {   
1067         if (_managedAttributes!=null && _managedAttributes.contains(name))
1068         {
1069             Object o =_scontext.getAttribute(name);
1070             if (o!=null)
1071                 getServer().getContainer().removeBean(o);
1072             if (value!=null)
1073                 getServer().getContainer().addBean(value);
1074         }
1075     }
1076     
1077     /* ------------------------------------------------------------ */
1078     /**
1079      * @param classLoader The classLoader to set.
1080      */
1081     public void setClassLoader(ClassLoader classLoader)
1082     {
1083         _classLoader = classLoader;
1084     }
1085     
1086     /* ------------------------------------------------------------ */
1087     /**
1088      * @param contextPath The _contextPath to set.
1089      */
1090     public void setContextPath(String contextPath)
1091     {
1092         if (contextPath!=null && contextPath.length()>1 && contextPath.endsWith("/"))
1093             throw new IllegalArgumentException("ends with /");
1094         _contextPath = contextPath;
1095         
1096         if (getServer()!=null && (getServer().isStarting() || getServer().isStarted()))
1097         {
1098             Handler[] contextCollections = getServer().getChildHandlersByClass(ContextHandlerCollection.class);
1099             for (int h=0;contextCollections!=null&& h<contextCollections.length;h++)
1100                 ((ContextHandlerCollection)contextCollections[h]).mapContexts();
1101         }
1102     }
1103     
1104     /* ------------------------------------------------------------ */
1105     /**
1106      * @param initParams The initParams to set.
1107      */
1108     public void setInitParams(Map<String,String> initParams)
1109     {
1110         if (initParams == null)
1111             return;
1112         _initParams = new HashMap<String,String>(initParams);
1113     }
1114     
1115     /* ------------------------------------------------------------ */
1116     /**
1117      * @param servletContextName The servletContextName to set.
1118      */
1119     public void setDisplayName(String servletContextName)
1120     {
1121         _displayName = servletContextName;
1122     }
1123     
1124     /* ------------------------------------------------------------ */
1125     /**
1126      * @return Returns the resourceBase.
1127      */
1128     public Resource getBaseResource()
1129     {
1130         if (_baseResource==null)
1131             return null;
1132         return _baseResource;
1133     }
1134 
1135     /* ------------------------------------------------------------ */
1136     /**
1137      * @return Returns the base resource as a string.
1138      */
1139     public String getResourceBase()
1140     {
1141         if (_baseResource==null)
1142             return null;
1143         return _baseResource.toString();
1144     }
1145     
1146     /* ------------------------------------------------------------ */
1147     /**
1148      * @param base The resourceBase to set.
1149      */
1150     public void setBaseResource(Resource base) 
1151     {
1152         _baseResource=base;
1153     }
1154 
1155     /* ------------------------------------------------------------ */
1156     /**
1157      * @param resourceBase The base resource as a string.
1158      */
1159     public void setResourceBase(String resourceBase) 
1160     {
1161         try
1162         {
1163             setBaseResource(newResource(resourceBase));
1164         }
1165         catch (Exception e)
1166         {
1167             Log.warn(e);
1168             throw new IllegalArgumentException(resourceBase);
1169         }
1170     }
1171     /* ------------------------------------------------------------ */
1172     /**
1173      * @return True if aliases are allowed
1174      */
1175     public boolean isAliases()
1176     {
1177         return _aliases;
1178     }
1179 
1180     /* ------------------------------------------------------------ */
1181     /**
1182      * @param aliases  aliases are allowed
1183      */
1184     public void setAliases(boolean aliases)
1185     {
1186         _aliases = aliases;
1187     }
1188 
1189     /* ------------------------------------------------------------ */
1190     /**
1191      * @return Returns the mimeTypes.
1192      */
1193     public MimeTypes getMimeTypes()
1194     {
1195         return _mimeTypes;
1196     }
1197     
1198     /* ------------------------------------------------------------ */
1199     /**
1200      * @param mimeTypes The mimeTypes to set.
1201      */
1202     public void setMimeTypes(MimeTypes mimeTypes)
1203     {
1204         _mimeTypes = mimeTypes;
1205     }
1206 
1207     /* ------------------------------------------------------------ */
1208     /**
1209      */
1210     public void setWelcomeFiles(String[] files) 
1211     {
1212         _welcomeFiles=files;
1213     }
1214 
1215     /* ------------------------------------------------------------ */
1216     /**
1217      * @return The names of the files which the server should consider to be welcome files in this context.
1218      * @see <a href="http://jcp.org/aboutJava/communityprocess/final/jsr154/index.html">The Servlet Specification</a>
1219      * @see #setWelcomeFiles
1220      */
1221     public String[] getWelcomeFiles() 
1222     {
1223         return _welcomeFiles;
1224     }
1225 
1226     /* ------------------------------------------------------------ */
1227     /**
1228      * @return Returns the errorHandler.
1229      */
1230     public ErrorHandler getErrorHandler()
1231     {
1232         return _errorHandler;
1233     }
1234 
1235     /* ------------------------------------------------------------ */
1236     /**
1237      * @param errorHandler The errorHandler to set.
1238      */
1239     public void setErrorHandler(ErrorHandler errorHandler)
1240     {
1241         if (errorHandler!=null)
1242             errorHandler.setServer(getServer());
1243         if (getServer()!=null)
1244             getServer().getContainer().update(this, _errorHandler, errorHandler, "errorHandler",true);
1245         _errorHandler = errorHandler;
1246     }
1247     
1248     /* ------------------------------------------------------------ */
1249     public int getMaxFormContentSize()
1250     {
1251         return _maxFormContentSize;
1252     }
1253     
1254     /* ------------------------------------------------------------ */
1255     public void setMaxFormContentSize(int maxSize)
1256     {
1257         _maxFormContentSize=maxSize;
1258     }
1259 
1260 
1261     /* ------------------------------------------------------------ */
1262     /**
1263      * @return True if URLs are compacted to replace multiple '/'s with a single '/'
1264      */
1265     public boolean isCompactPath()
1266     {
1267         return _compactPath;
1268     }
1269 
1270     /* ------------------------------------------------------------ */
1271     /**
1272      * @param compactPath True if URLs are compacted to replace multiple '/'s with a single '/'
1273      */
1274     public void setCompactPath(boolean compactPath)
1275     {
1276         _compactPath=compactPath;
1277     }
1278 
1279     /* ------------------------------------------------------------ */
1280     public String toString()
1281     {
1282         
1283         return super.toString()+"@"+Integer.toHexString(hashCode())+getContextPath()+","+getBaseResource();
1284     }
1285 
1286     /* ------------------------------------------------------------ */
1287     public synchronized Class<?> loadClass(String className)
1288         throws ClassNotFoundException
1289     {
1290         if (className==null)
1291             return null;
1292         
1293         if (_classLoader==null)
1294             return Loader.loadClass(this.getClass(), className);
1295 
1296         return _classLoader.loadClass(className);
1297     }
1298     
1299 
1300     /* ------------------------------------------------------------ */
1301     public void addLocaleEncoding(String locale,String encoding)
1302     {
1303         if (_localeEncodingMap==null)
1304             _localeEncodingMap=new HashMap<String,String>();
1305         _localeEncodingMap.put(locale, encoding);
1306     }
1307     
1308     /* ------------------------------------------------------------ */
1309     /**
1310      * Get the character encoding for a locale. The full locale name is first
1311      * looked up in the map of encodings. If no encoding is found, then the
1312      * locale language is looked up. 
1313      *
1314      * @param locale a <code>Locale</code> value
1315      * @return a <code>String</code> representing the character encoding for
1316      * the locale or null if none found.
1317      */
1318     public String getLocaleEncoding(Locale locale)
1319     {
1320         if (_localeEncodingMap==null)
1321             return null;
1322         String encoding = _localeEncodingMap.get(locale.toString());
1323         if (encoding==null)
1324             encoding = _localeEncodingMap.get(locale.getLanguage());
1325         return encoding;
1326     }
1327     
1328     /* ------------------------------------------------------------ */
1329     /* 
1330      */
1331     public Resource getResource(String path) throws MalformedURLException
1332     {
1333         if (path==null || !path.startsWith(URIUtil.SLASH))
1334             throw new MalformedURLException(path);
1335         
1336         if (_baseResource==null)
1337             return null;
1338 
1339         try
1340         {
1341             path=URIUtil.canonicalPath(path);
1342             Resource resource=_baseResource.addPath(path);
1343             
1344             if (!_aliases && resource.getAlias()!=null)
1345             {
1346                 if (resource.exists())
1347                     Log.warn("Aliased resource: "+resource+"~="+resource.getAlias());
1348                 else if (Log.isDebugEnabled())
1349                     Log.debug("Aliased resource: "+resource+"~="+resource.getAlias());
1350                 return null;
1351             }
1352             
1353             return resource;
1354         }
1355         catch(Exception e)
1356         {
1357             Log.ignore(e);
1358         }
1359                     
1360         return null;
1361     }
1362 
1363     /* ------------------------------------------------------------ */
1364     /** Convert URL to Resource
1365      * wrapper for {@link Resource#newResource(URL)} enables extensions to 
1366      * provide alternate resource implementations.
1367      */
1368     public Resource newResource(URL url) throws IOException
1369     {
1370         return Resource.newResource(url);
1371     }
1372 
1373     /* ------------------------------------------------------------ */
1374     /** Convert URL to Resource
1375      * wrapper for {@link Resource#newResource(String)} enables extensions to 
1376      * provide alternate resource implementations.
1377      */
1378     public Resource newResource(String url) throws IOException
1379     {
1380         return Resource.newResource(url);
1381     }
1382 
1383     /* ------------------------------------------------------------ */
1384     /* 
1385      */
1386     public Set<String> getResourcePaths(String path)
1387     {           
1388         try
1389         {
1390             path=URIUtil.canonicalPath(path);
1391             Resource resource=getResource(path);
1392             
1393             if (resource!=null && resource.exists())
1394             {
1395                 if (!path.endsWith(URIUtil.SLASH))
1396                     path=path+URIUtil.SLASH;
1397                 
1398                 String[] l=resource.list();
1399                 if (l!=null)
1400                 {
1401                     HashSet<String> set = new HashSet<String>();
1402                     for(int i=0;i<l.length;i++)
1403                         set.add(path+l[i]);
1404                     return set;
1405                 }   
1406             }
1407         }
1408         catch(Exception e)
1409         {
1410             Log.ignore(e);
1411         }
1412         return Collections.emptySet();
1413     }
1414 
1415 
1416 
1417     /* ------------------------------------------------------------ */
1418     private String normalizeHostname( String host )
1419     {
1420         if ( host == null )
1421             return null;
1422         
1423         if ( host.endsWith( "." ) )
1424             return host.substring( 0, host.length() -1);
1425       
1426             return host;
1427     }
1428 
1429     public void complete(Request request)
1430     {
1431         // TODO Auto-generated method stub
1432         
1433     }
1434     
1435     /* ------------------------------------------------------------ */
1436     /** Context.
1437      * <p>
1438      * A partial implementation of  {@link javax.servlet.ServletContext}.
1439      * A complete implementation is provided by the derived {@link org.eclipse.jetty.servlet.ServletContextHandler.Context}.   
1440      * </p>
1441      * 
1442      *
1443      */
1444     public class Context implements ServletContext
1445     {
1446         /* ------------------------------------------------------------ */
1447         protected Context()
1448         {
1449         }
1450 
1451         /* ------------------------------------------------------------ */
1452         public ContextHandler getContextHandler()
1453         {
1454             // TODO reduce visibility of this method
1455             return ContextHandler.this;
1456         }
1457 
1458         /* ------------------------------------------------------------ */
1459         /* 
1460          * @see javax.servlet.ServletContext#getContext(java.lang.String)
1461          */
1462         public ServletContext getContext(String uripath)
1463         {
1464             // TODO this is a very poor implementation!
1465             // TODO move this to Server
1466             ContextHandler context=null;
1467             Handler[] handlers = getServer().getChildHandlersByClass(ContextHandler.class);
1468             for (int i=0;i<handlers.length;i++)
1469             {
1470                 if (handlers[i]==null || !handlers[i].isStarted())
1471                     continue;
1472                 ContextHandler ch = (ContextHandler)handlers[i];
1473                 String context_path=ch.getContextPath();
1474                 if (uripath.equals(context_path) || (uripath.startsWith(context_path)&&uripath.charAt(context_path.length())=='/'))
1475                 {
1476                     if (context==null || context_path.length()>context.getContextPath().length())
1477                         context=ch;
1478                 }
1479             }
1480             
1481             if (context!=null)
1482                 return context._scontext;
1483             return null;
1484         }
1485 
1486         /* ------------------------------------------------------------ */
1487         /* 
1488          * @see javax.servlet.ServletContext#getMajorVersion()
1489          */
1490         public int getMajorVersion()
1491         {
1492             return 2;
1493         }
1494 
1495         /* ------------------------------------------------------------ */
1496         /* 
1497          * @see javax.servlet.ServletContext#getMimeType(java.lang.String)
1498          */
1499         public String getMimeType(String file)
1500         {
1501             if (_mimeTypes==null)
1502                 return null;
1503             Buffer mime = _mimeTypes.getMimeByExtension(file);
1504             if (mime!=null)
1505                 return mime.toString();
1506             return null;
1507         }
1508 
1509         /* ------------------------------------------------------------ */
1510         /* 
1511          * @see javax.servlet.ServletContext#getMinorVersion()
1512          */
1513         public int getMinorVersion()
1514         {
1515             return 5;
1516         }
1517 
1518         /* ------------------------------------------------------------ */
1519         /* 
1520          * @see javax.servlet.ServletContext#getNamedDispatcher(java.lang.String)
1521          */
1522         public RequestDispatcher getNamedDispatcher(String name)
1523         {
1524             return null;
1525         }
1526         /* ------------------------------------------------------------ */
1527         /* 
1528          * @see javax.servlet.ServletContext#getRequestDispatcher(java.lang.String)
1529          */
1530         public RequestDispatcher getRequestDispatcher(String uriInContext)
1531         {
1532             if (uriInContext == null)
1533                 return null;
1534 
1535             if (!uriInContext.startsWith("/"))
1536                 return null;
1537             
1538             try
1539             {
1540                 String query=null;
1541                 int q=0;
1542                 if ((q=uriInContext.indexOf('?'))>0)
1543                 {
1544                     query=uriInContext.substring(q+1);
1545                     uriInContext=uriInContext.substring(0,q);
1546                 }
1547                 if ((q=uriInContext.indexOf(';'))>0)
1548                     uriInContext=uriInContext.substring(0,q);
1549 
1550                 String pathInContext=URIUtil.canonicalPath(URIUtil.decodePath(uriInContext));
1551                 String uri=URIUtil.addPaths(getContextPath(), uriInContext);
1552                 ContextHandler context=ContextHandler.this;
1553                 return new Dispatcher(context,uri, pathInContext, query);
1554             }
1555             catch(Exception e)
1556             {
1557                 Log.ignore(e);
1558             }
1559             return null;
1560         }
1561         /* ------------------------------------------------------------ */
1562         /* 
1563          * @see javax.servlet.ServletContext#getRealPath(java.lang.String)
1564          */
1565         public String getRealPath(String path)
1566         {
1567             if(path==null)
1568                 return null;
1569             if(path.length()==0)
1570                 path = URIUtil.SLASH;
1571             else if(path.charAt(0)!='/')
1572                 path = URIUtil.SLASH + path;
1573                 
1574             try
1575             {
1576                 Resource resource=ContextHandler.this.getResource(path);
1577                 if(resource!=null)
1578                 {
1579                     File file = resource.getFile();
1580                     if (file!=null)
1581                         return file.getCanonicalPath();
1582                 }
1583             }
1584             catch (Exception e)
1585             {
1586                 Log.ignore(e);
1587             }
1588             
1589             return null;
1590         }
1591 
1592         /* ------------------------------------------------------------ */
1593         public URL getResource(String path) throws MalformedURLException
1594         {
1595             Resource resource=ContextHandler.this.getResource(path);
1596             if (resource!=null && resource.exists())
1597                 return resource.getURL();
1598             return null;
1599         }
1600         
1601         /* ------------------------------------------------------------ */
1602         /* 
1603          * @see javax.servlet.ServletContext#getResourceAsStream(java.lang.String)
1604          */
1605         public InputStream getResourceAsStream(String path)
1606         {
1607             try
1608             {
1609                 URL url=getResource(path);
1610                 if (url==null)
1611                     return null;
1612                 return url.openStream();
1613             }
1614             catch(Exception e)
1615             {
1616                 Log.ignore(e);
1617                 return null;
1618             }
1619         }
1620 
1621         /* ------------------------------------------------------------ */
1622         /* 
1623          * @see javax.servlet.ServletContext#getResourcePaths(java.lang.String)
1624          */
1625         public Set getResourcePaths(String path)
1626         {            
1627             return ContextHandler.this.getResourcePaths(path);
1628         }
1629 
1630         /* ------------------------------------------------------------ */
1631         /* 
1632          * @see javax.servlet.ServletContext#getServerInfo()
1633          */
1634         public String getServerInfo()
1635         {
1636             return "jetty/"+Server.getVersion();
1637         }
1638 
1639         /* ------------------------------------------------------------ */
1640         /* 
1641          * @see javax.servlet.ServletContext#getServlet(java.lang.String)
1642          */
1643         public Servlet getServlet(String name) throws ServletException
1644         {
1645             return null;
1646         }
1647 
1648         /* ------------------------------------------------------------ */
1649         /* 
1650          * @see javax.servlet.ServletContext#getServletNames()
1651          */
1652         @SuppressWarnings("unchecked")
1653         public Enumeration getServletNames()
1654         {
1655             return Collections.enumeration(Collections.EMPTY_LIST);
1656         }
1657 
1658         /* ------------------------------------------------------------ */
1659         /* 
1660          * @see javax.servlet.ServletContext#getServlets()
1661          */
1662         @SuppressWarnings("unchecked")
1663         public Enumeration getServlets()
1664         {
1665             return Collections.enumeration(Collections.EMPTY_LIST);
1666         }
1667 
1668         /* ------------------------------------------------------------ */
1669         /* 
1670          * @see javax.servlet.ServletContext#log(java.lang.Exception, java.lang.String)
1671          */
1672         public void log(Exception exception, String msg)
1673         {
1674             _logger.warn(msg,exception);
1675         }
1676 
1677         /* ------------------------------------------------------------ */
1678         /* 
1679          * @see javax.servlet.ServletContext#log(java.lang.String)
1680          */
1681         public void log(String msg)
1682         {
1683             _logger.info(msg, null, null);
1684         }
1685 
1686         /* ------------------------------------------------------------ */
1687         /* 
1688          * @see javax.servlet.ServletContext#log(java.lang.String, java.lang.Throwable)
1689          */
1690         public void log(String message, Throwable throwable)
1691         {
1692             _logger.warn(message,throwable);
1693         }
1694 
1695         /* ------------------------------------------------------------ */
1696         /* 
1697          * @see javax.servlet.ServletContext#getInitParameter(java.lang.String)
1698          */
1699         public String getInitParameter(String name)
1700         {
1701             return ContextHandler.this.getInitParameter(name);
1702         }
1703 
1704         /* ------------------------------------------------------------ */
1705         /* 
1706          * @see javax.servlet.ServletContext#getInitParameterNames()
1707          */
1708         @SuppressWarnings("unchecked")
1709         public Enumeration getInitParameterNames()
1710         {
1711             return ContextHandler.this.getInitParameterNames();
1712         }
1713 
1714         /* ------------------------------------------------------------ */
1715         /* 
1716          * @see javax.servlet.ServletContext#getAttribute(java.lang.String)
1717          */
1718         public synchronized Object getAttribute(String name)
1719         {
1720             Object o = ContextHandler.this.getAttribute(name);
1721             if (o==null && _contextAttributes!=null)
1722                 o=_contextAttributes.getAttribute(name);
1723             return o;
1724         }
1725 
1726         /* ------------------------------------------------------------ */
1727         /* 
1728          * @see javax.servlet.ServletContext#getAttributeNames()
1729          */
1730         @SuppressWarnings("unchecked")
1731         public synchronized Enumeration getAttributeNames()
1732         {
1733             HashSet<String> set = new HashSet<String>();
1734             if (_contextAttributes!=null)
1735             {
1736             	Enumeration<String> e = _contextAttributes.getAttributeNames();
1737             	while(e.hasMoreElements())
1738             		set.add(e.nextElement());
1739             }
1740             Enumeration<String> e = _attributes.getAttributeNames();
1741             while(e.hasMoreElements())
1742                 set.add(e.nextElement());
1743             
1744             return Collections.enumeration(set);
1745         }
1746 
1747         /* ------------------------------------------------------------ */
1748         /* 
1749          * @see javax.servlet.ServletContext#setAttribute(java.lang.String, java.lang.Object)
1750          */
1751         public synchronized void setAttribute(String name, Object value)
1752         {
1753             
1754             if (_contextAttributes==null)
1755             {
1756             	// Set it on the handler
1757             	ContextHandler.this.setAttribute(name, value);
1758                 return;
1759             }
1760 
1761             setManagedAttribute(name,value);
1762             Object old_value=_contextAttributes.getAttribute(name);
1763             
1764             if (value==null)
1765                 _contextAttributes.removeAttribute(name);
1766             else
1767                 _contextAttributes.setAttribute(name,value);
1768             
1769             if (_contextAttributeListeners!=null)
1770             {
1771                 ServletContextAttributeEvent event =
1772                     new ServletContextAttributeEvent(_scontext,name, old_value==null?value:old_value);
1773 
1774                 for(int i=0;i<LazyList.size(_contextAttributeListeners);i++)
1775                 {
1776                     ServletContextAttributeListener l = (ServletContextAttributeListener)LazyList.get(_contextAttributeListeners,i);
1777                     
1778                     if (old_value==null)
1779                         l.attributeAdded(event);
1780                     else if (value==null)
1781                         l.attributeRemoved(event);
1782                     else
1783                         l.attributeReplaced(event);
1784                 }
1785             }
1786         }
1787 
1788         /* ------------------------------------------------------------ */
1789         /* 
1790          * @see javax.servlet.ServletContext#removeAttribute(java.lang.String)
1791          */
1792         public synchronized void removeAttribute(String name)
1793         {
1794             setManagedAttribute(name,null);
1795             
1796             if (_contextAttributes==null)
1797             {
1798             	// Set it on the handler
1799             	_attributes.removeAttribute(name);
1800                 return;
1801             }
1802             
1803             Object old_value=_contextAttributes.getAttribute(name);
1804             _contextAttributes.removeAttribute(name);
1805             if (old_value!=null)
1806             {
1807                 if (_contextAttributeListeners!=null)
1808                 {
1809                     ServletContextAttributeEvent event =
1810                         new ServletContextAttributeEvent(_scontext,name, old_value);
1811 
1812                     for(int i=0;i<LazyList.size(_contextAttributeListeners);i++)
1813                         ((ServletContextAttributeListener)LazyList.get(_contextAttributeListeners,i)).attributeRemoved(event);
1814                 }
1815             }
1816         }
1817 
1818         /* ------------------------------------------------------------ */
1819         /* 
1820          * @see javax.servlet.ServletContext#getServletContextName()
1821          */
1822         public String getServletContextName()
1823         {
1824             String name = ContextHandler.this.getDisplayName();
1825             if (name==null)
1826                 name=ContextHandler.this.getContextPath();
1827             return name;
1828         }
1829 
1830         /* ------------------------------------------------------------ */
1831         public String getContextPath()
1832         {
1833             if ((_contextPath != null) && _contextPath.equals(URIUtil.SLASH))
1834                 return "";
1835             
1836             return _contextPath;
1837         }
1838 
1839         /* ------------------------------------------------------------ */
1840         public String toString()
1841         {
1842             return "ServletContext@"+Integer.toHexString(hashCode())+"{"+(getContextPath().equals("")?URIUtil.SLASH:getContextPath())+","+getBaseResource()+"}";
1843         }
1844 
1845         /* ------------------------------------------------------------ */
1846         public boolean setInitParameter(String name, String value)
1847         {
1848             if (ContextHandler.this.getInitParameter(name)!=null)
1849                 return false;
1850             ContextHandler.this.getInitParams().put(name,value);
1851             return true;
1852         }
1853         
1854     }
1855 
1856 }