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.server.context.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
85  {
86      private static final ThreadLocal<Context> __context=new ThreadLocal<Context>();
87      public static final String MANAGED_ATTRIBUTES = "org.eclipse.jetty.server.context.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 Map<String,Object> _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         String managedAttributes = _initParams.get(MANAGED_ATTRIBUTES);
616         if (managedAttributes!=null)
617         {
618             _managedAttributes=new HashMap<String,Object>();
619             String[] attributes = managedAttributes.split(",");
620             for (String attribute : attributes)
621                 _managedAttributes.put(attribute,null);
622             
623             Enumeration e = _scontext.getAttributeNames();
624             while(e.hasMoreElements())
625             {
626                 String name = (String)e.nextElement();
627                 Object value = _scontext.getAttribute(name);
628                 setManagedAttribute(name,value);
629             }
630         }       
631         
632         super.doStart();
633 
634         if (_errorHandler!=null)
635             _errorHandler.start();
636         
637         // Context listeners
638         if (_contextListeners != null )
639         {
640             ServletContextEvent event= new ServletContextEvent(_scontext);
641             for (int i= 0; i < LazyList.size(_contextListeners); i++)
642             {
643                 ((ServletContextListener)LazyList.get(_contextListeners, i)).contextInitialized(event);
644             }
645         }
646 
647     }
648     
649     /* ------------------------------------------------------------ */
650     /* 
651      * @see org.eclipse.thread.AbstractLifeCycle#doStop()
652      */
653     protected void doStop() throws Exception
654     {
655         _availability=__STOPPED;
656         
657         ClassLoader old_classloader=null;
658         Thread current_thread=null;
659 
660         Context old_context=__context.get();
661         __context.set(_scontext);
662         try
663         {
664             // Set the classloader
665             if (_classLoader!=null)
666             {
667                 current_thread=Thread.currentThread();
668                 old_classloader=current_thread.getContextClassLoader();
669                 current_thread.setContextClassLoader(_classLoader);
670             }
671             
672             super.doStop();
673             
674             // Context listeners
675             if (_contextListeners != null )
676             {
677                 ServletContextEvent event= new ServletContextEvent(_scontext);
678                 for (int i=LazyList.size(_contextListeners); i-->0;)
679                 {
680                     ((ServletContextListener)LazyList.get(_contextListeners, i)).contextDestroyed(event);
681                 }
682             }
683 
684             if (_errorHandler!=null)
685                 _errorHandler.stop();
686             
687             Enumeration e = _scontext.getAttributeNames();
688             while(e.hasMoreElements())
689             {
690                 String name = (String)e.nextElement();
691                 setManagedAttribute(name,null);
692             }
693         }
694         finally
695         {
696             __context.set(old_context);
697             // reset the classloader
698             if (_classLoader!=null)
699                 current_thread.setContextClassLoader(old_classloader);
700         }
701 
702         if (_contextAttributes!=null)
703             _contextAttributes.clearAttributes();
704         _contextAttributes=null;
705     }
706 
707     /* ------------------------------------------------------------ */
708     /* 
709      * @see org.eclipse.jetty.server.Handler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
710      */
711     public boolean checkContext(final String target, final Request baseRequest, final HttpServletResponse response)
712             throws IOException, ServletException
713     {   
714         DispatcherType dispatch=baseRequest.getDispatcherType();
715         
716         switch(_availability)
717         {
718             case __STOPPED:
719             case __SHUTDOWN:
720                 return false;
721             case __UNAVAILABLE:
722                 response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
723                 return false;
724             default:
725                 if((DispatcherType.REQUEST.equals(dispatch) && baseRequest.isHandled()))
726                     return false;
727         }
728         
729         // Check the vhosts
730         if (_vhosts!=null && _vhosts.length>0)
731         {
732             String vhost = normalizeHostname( baseRequest.getServerName());
733 
734             boolean match=false;
735             
736             // TODO non-linear lookup
737             for (int i=0;!match && i<_vhosts.length;i++)
738             {
739                 String contextVhost = _vhosts[i];
740                 if(contextVhost==null) continue;
741                 if(contextVhost.startsWith("*.")) {
742                     // wildcard only at the beginning, and only for one additional subdomain level
743                     match=contextVhost.regionMatches(true,2,vhost,vhost.indexOf(".")+1,contextVhost.length()-2);
744                 } else
745                     match=contextVhost.equalsIgnoreCase(vhost);
746             }
747             if (!match)
748                 return false;
749         }
750         
751         // Check the connector
752         if (_connectors!=null && _connectors.size()>0)
753         {
754             String connector=HttpConnection.getCurrentConnection().getConnector().getName();
755             if (connector==null || !_connectors.contains(connector))
756                 return false;
757         }
758                 
759             
760         if (target.startsWith(_contextPath))
761         {
762             if (_contextPath.length()==target.length() && _contextPath.length()>1 &&!_allowNullPathInfo)
763             {
764                 // context request must end with /
765                 baseRequest.setHandled(true);
766                 if (baseRequest.getQueryString()!=null)
767                     response.sendRedirect(URIUtil.addPaths(baseRequest.getRequestURI(),URIUtil.SLASH)+"?"+baseRequest.getQueryString());
768                 else 
769                     response.sendRedirect(URIUtil.addPaths(baseRequest.getRequestURI(),URIUtil.SLASH));
770                 return false;
771             }
772         }
773         else
774         {
775             // Not for this context!
776             return false;
777         }
778         
779         return true;
780     }        
781         
782 
783 
784     /* ------------------------------------------------------------ */
785     /**
786      * @see org.eclipse.jetty.server.handler.ScopedHandler#doScope(java.lang.String, org.eclipse.jetty.server.Request, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
787      */
788     @Override
789     public void doScope(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
790     { 
791         Context old_context=null;
792         String old_context_path=null;
793         String old_servlet_path=null;
794         String old_path_info=null;
795         ClassLoader old_classloader=null;
796         Thread current_thread=null;
797         String pathInfo=null;
798 
799         DispatcherType dispatch=baseRequest.getDispatcherType();
800         
801         old_context=baseRequest.getContext();
802   
803         // Are we already in this context?
804         if (old_context!=_scontext)
805         {
806             // check the target.
807             if (DispatcherType.REQUEST.equals(dispatch) || DispatcherType.ASYNC.equals(dispatch))
808             {
809                 if (_compactPath)
810                     target=URIUtil.compactPath(target);
811                 if (!checkContext(target,baseRequest,response))
812                     return;
813                 
814                 if (target.length()>_contextPath.length())
815                 {
816                     if (_contextPath.length()>1)
817                         target=target.substring(_contextPath.length());
818                     pathInfo=target;
819                 }
820                 else if (_contextPath.length()==1)
821                 {
822                     target=URIUtil.SLASH;
823                     pathInfo=URIUtil.SLASH;
824                 }
825                 else
826                 {
827                     target=URIUtil.SLASH;
828                     pathInfo=null;
829                 }
830             }
831 
832             // Set the classloader
833             if (_classLoader!=null)
834             {
835                 current_thread=Thread.currentThread();
836                 old_classloader=current_thread.getContextClassLoader();
837                 current_thread.setContextClassLoader(_classLoader);
838             }
839         }
840         
841         try
842         {
843             old_context_path=baseRequest.getContextPath();
844             old_servlet_path=baseRequest.getServletPath();
845             old_path_info=baseRequest.getPathInfo();
846             
847             // Update the paths
848             baseRequest.setContext(_scontext);
849             if (!DispatcherType.INCLUDE.equals(dispatch) && target.startsWith("/"))
850             {
851                 if (_contextPath.length()==1)
852                     baseRequest.setContextPath("");
853                 else
854                     baseRequest.setContextPath(_contextPath);
855                 baseRequest.setServletPath(null);
856                 baseRequest.setPathInfo(pathInfo);
857             }
858             
859             // start manual inline of nextScope(target,baseRequest,request,response);
860             //noinspection ConstantIfStatement
861             if (false)
862                 nextScope(target,baseRequest,request,response);
863             else if (_nextScope!=null)
864                 _nextScope.doScope(target,baseRequest,request, response);
865             else if (_outerScope!=null)
866                 _outerScope.doHandle(target,baseRequest,request, response);
867             else 
868                 doHandle(target,baseRequest,request, response);
869             // end manual inline (pathentic attempt to reduce stack depth)
870         }
871         finally
872         {
873             if (old_context!=_scontext)
874             {
875                 // reset the classloader
876                 if (_classLoader!=null)
877                 {
878                     current_thread.setContextClassLoader(old_classloader);
879                 }
880                 
881                 // reset the context and servlet path.
882                 baseRequest.setContext(old_context);
883                 baseRequest.setContextPath(old_context_path);
884                 baseRequest.setServletPath(old_servlet_path);
885                 baseRequest.setPathInfo(old_path_info); 
886             }
887         }
888     }
889     
890     /* ------------------------------------------------------------ */
891     /**
892      * @see org.eclipse.jetty.server.handler.ScopedHandler#doHandle(java.lang.String, org.eclipse.jetty.server.Request, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
893      */
894     @Override
895     public void doHandle(String target,Request baseRequest,HttpServletRequest request,HttpServletResponse response) throws IOException, ServletException
896     {
897         final DispatcherType dispatch=baseRequest.getDispatcherType();
898         final boolean new_context=baseRequest.takeNewContext();
899         try
900         {
901             if (new_context)
902             {
903                 // Handle the REALLY SILLY request events!
904                 if (_requestAttributeListeners!=null)
905                 {
906                     final int s=LazyList.size(_requestAttributeListeners);
907                     for(int i=0;i<s;i++)
908                         baseRequest.addEventListener(((EventListener)LazyList.get(_requestAttributeListeners,i)));
909                 }
910 
911                 if (_requestListeners!=null)
912                 {
913                     final int s=LazyList.size(_requestListeners);
914                     final ServletRequestEvent sre = new ServletRequestEvent(_scontext,request);
915                     for(int i=0;i<s;i++)
916                         ((ServletRequestListener)LazyList.get(_requestListeners,i)).requestInitialized(sre);
917                 }
918             }
919             
920             if (DispatcherType.REQUEST.equals(dispatch) && isProtectedTarget(target))
921                 throw new HttpException(HttpServletResponse.SC_NOT_FOUND);
922             
923             // start manual inline of nextHandle(target,baseRequest,request,response);
924             //noinspection ConstantIfStatement
925             if (false)
926                 nextHandle(target,baseRequest,request,response);
927             else if (_nextScope!=null && _nextScope==_handler)
928                 _nextScope.doHandle(target,baseRequest,request, response);
929             else if (_handler!=null)
930                 _handler.handle(target,baseRequest, request, response);
931             // end manual inline
932         }
933         catch(HttpException e)
934         {
935             Log.debug(e);
936             response.sendError(e.getStatus(), e.getReason());
937         }
938         finally
939         {
940             // Handle more REALLY SILLY request events!
941             if (new_context)
942             {
943                 if (_requestListeners!=null)
944                 {
945                     final int s=LazyList.size(_requestListeners);
946                     final ServletRequestEvent sre = new ServletRequestEvent(_scontext,request);
947                     for(int i=0;i<s;i++)
948                         ((ServletRequestListener)LazyList.get(_requestListeners,i)).requestInitialized(sre);
949                 }
950                 
951                 if (_requestAttributeListeners!=null)
952                 {
953                     for(int i=LazyList.size(_requestAttributeListeners);i-->0;)
954                         baseRequest.removeEventListener(((EventListener)LazyList.get(_requestAttributeListeners,i)));
955                 }
956             }
957         }
958     }
959     
960     /* ------------------------------------------------------------ */
961     /* Handle a runnable in this context
962      */
963     public void handle(Runnable runnable)
964     {   
965         ClassLoader old_classloader=null;
966         Thread current_thread=null;
967         try
968         {
969             // Set the classloader
970             if (_classLoader!=null)
971             {
972                 current_thread=Thread.currentThread();
973                 old_classloader=current_thread.getContextClassLoader();
974                 current_thread.setContextClassLoader(_classLoader);
975             }
976             
977             runnable.run();
978         }
979         finally
980         {
981             if (old_classloader!=null)
982             {
983                 current_thread.setContextClassLoader(old_classloader);
984             }
985         }
986     }
987 
988     /* ------------------------------------------------------------ */
989     /** Check the target.
990      * Called by {@link #handle(String, Request, HttpServletRequest, HttpServletResponse)} when a
991      * target within a context is determined.  If the target is protected, 404 is returned.
992      * The default implementation always returns false.
993      * @see org.eclipse.jetty.webapp.WebAppContext#isProtectedTarget(String)
994      */
995     /* ------------------------------------------------------------ */
996     protected boolean isProtectedTarget(String target)
997     { 
998         return false;
999     }
1000 
1001     /* ------------------------------------------------------------ */
1002     /* 
1003      * @see javax.servlet.ServletContext#removeAttribute(java.lang.String)
1004      */
1005     public void removeAttribute(String name)
1006     {
1007         setManagedAttribute(name,null);
1008         _attributes.removeAttribute(name);
1009     }
1010 
1011     /* ------------------------------------------------------------ */
1012     /* Set a context attribute.
1013      * Attributes set via this API cannot be overriden by the ServletContext.setAttribute API.
1014      * Their lifecycle spans the stop/start of a context.  No attribute listener events are 
1015      * triggered by this API.
1016      * @see javax.servlet.ServletContext#setAttribute(java.lang.String, java.lang.Object)
1017      */
1018     public void setAttribute(String name, Object value)
1019     {
1020         setManagedAttribute(name,value);
1021         _attributes.setAttribute(name,value);
1022     }
1023     
1024     /* ------------------------------------------------------------ */
1025     /**
1026      * @param attributes The attributes to set.
1027      */
1028     public void setAttributes(Attributes attributes)
1029     {
1030         if (attributes instanceof AttributesMap)
1031         {
1032             _attributes = (AttributesMap)attributes;
1033             Enumeration e = _attributes.getAttributeNames();
1034             while (e.hasMoreElements())
1035             {
1036                 String name = (String)e.nextElement();
1037                 setManagedAttribute(name,attributes.getAttribute(name));
1038             }
1039         }
1040         else
1041         {
1042             _attributes=new AttributesMap();
1043             Enumeration e = attributes.getAttributeNames();
1044             while (e.hasMoreElements())
1045             {
1046                 String name = (String)e.nextElement();
1047                 Object value=attributes.getAttribute(name);
1048                 setManagedAttribute(name,value);
1049                 _attributes.setAttribute(name,value);
1050             }
1051         }
1052     }
1053 
1054     /* ------------------------------------------------------------ */
1055     public void clearAttributes()
1056     {
1057         Enumeration e = _attributes.getAttributeNames();
1058         while (e.hasMoreElements())
1059         {
1060             String name = (String)e.nextElement();
1061             setManagedAttribute(name,null);
1062         }
1063         _attributes.clearAttributes();
1064     }
1065 
1066     /* ------------------------------------------------------------ */
1067     private void setManagedAttribute(String name, Object value)
1068     {   
1069         if (_managedAttributes!=null && _managedAttributes.containsKey(name))
1070         {
1071             Object old =_managedAttributes.put(name,value);
1072             if (old!=null)
1073                 getServer().getContainer().removeBean(old);
1074             if (value!=null)
1075             {
1076                 _logger.info("Managing "+name);
1077                 getServer().getContainer().addBean(value);
1078             }
1079         }
1080     }
1081     
1082     /* ------------------------------------------------------------ */
1083     /**
1084      * @param classLoader The classLoader to set.
1085      */
1086     public void setClassLoader(ClassLoader classLoader)
1087     {
1088         _classLoader = classLoader;
1089     }
1090     
1091     /* ------------------------------------------------------------ */
1092     /**
1093      * @param contextPath The _contextPath to set.
1094      */
1095     public void setContextPath(String contextPath)
1096     {
1097         if (contextPath!=null && contextPath.length()>1 && contextPath.endsWith("/"))
1098             throw new IllegalArgumentException("ends with /");
1099         _contextPath = contextPath;
1100         
1101         if (getServer()!=null && (getServer().isStarting() || getServer().isStarted()))
1102         {
1103             Handler[] contextCollections = getServer().getChildHandlersByClass(ContextHandlerCollection.class);
1104             for (int h=0;contextCollections!=null&& h<contextCollections.length;h++)
1105                 ((ContextHandlerCollection)contextCollections[h]).mapContexts();
1106         }
1107     }
1108     
1109     /* ------------------------------------------------------------ */
1110     /**
1111      * @param initParams The initParams to set.
1112      */
1113     public void setInitParams(Map<String,String> initParams)
1114     {
1115         if (initParams == null)
1116             return;
1117         _initParams = new HashMap<String,String>(initParams);
1118     }
1119     
1120     /* ------------------------------------------------------------ */
1121     /**
1122      * @param servletContextName The servletContextName to set.
1123      */
1124     public void setDisplayName(String servletContextName)
1125     {
1126         _displayName = servletContextName;
1127     }
1128     
1129     /* ------------------------------------------------------------ */
1130     /**
1131      * @return Returns the resourceBase.
1132      */
1133     public Resource getBaseResource()
1134     {
1135         if (_baseResource==null)
1136             return null;
1137         return _baseResource;
1138     }
1139 
1140     /* ------------------------------------------------------------ */
1141     /**
1142      * @return Returns the base resource as a string.
1143      */
1144     public String getResourceBase()
1145     {
1146         if (_baseResource==null)
1147             return null;
1148         return _baseResource.toString();
1149     }
1150     
1151     /* ------------------------------------------------------------ */
1152     /**
1153      * @param base The resourceBase to set.
1154      */
1155     public void setBaseResource(Resource base) 
1156     {
1157         _baseResource=base;
1158     }
1159 
1160     /* ------------------------------------------------------------ */
1161     /**
1162      * @param resourceBase The base resource as a string.
1163      */
1164     public void setResourceBase(String resourceBase) 
1165     {
1166         try
1167         {
1168             setBaseResource(newResource(resourceBase));
1169         }
1170         catch (Exception e)
1171         {
1172             Log.warn(e.toString());
1173             Log.debug(e);
1174             throw new IllegalArgumentException(resourceBase);
1175         }
1176     }
1177     /* ------------------------------------------------------------ */
1178     /**
1179      * @return True if aliases are allowed
1180      */
1181     public boolean isAliases()
1182     {
1183         return _aliases;
1184     }
1185 
1186     /* ------------------------------------------------------------ */
1187     /**
1188      * @param aliases  aliases are allowed
1189      */
1190     public void setAliases(boolean aliases)
1191     {
1192         _aliases = aliases;
1193     }
1194 
1195     /* ------------------------------------------------------------ */
1196     /**
1197      * @return Returns the mimeTypes.
1198      */
1199     public MimeTypes getMimeTypes()
1200     {
1201         return _mimeTypes;
1202     }
1203     
1204     /* ------------------------------------------------------------ */
1205     /**
1206      * @param mimeTypes The mimeTypes to set.
1207      */
1208     public void setMimeTypes(MimeTypes mimeTypes)
1209     {
1210         _mimeTypes = mimeTypes;
1211     }
1212 
1213     /* ------------------------------------------------------------ */
1214     /**
1215      */
1216     public void setWelcomeFiles(String[] files) 
1217     {
1218         _welcomeFiles=files;
1219     }
1220 
1221     /* ------------------------------------------------------------ */
1222     /**
1223      * @return The names of the files which the server should consider to be welcome files in this context.
1224      * @see <a href="http://jcp.org/aboutJava/communityprocess/final/jsr154/index.html">The Servlet Specification</a>
1225      * @see #setWelcomeFiles
1226      */
1227     public String[] getWelcomeFiles() 
1228     {
1229         return _welcomeFiles;
1230     }
1231 
1232     /* ------------------------------------------------------------ */
1233     /**
1234      * @return Returns the errorHandler.
1235      */
1236     public ErrorHandler getErrorHandler()
1237     {
1238         return _errorHandler;
1239     }
1240 
1241     /* ------------------------------------------------------------ */
1242     /**
1243      * @param errorHandler The errorHandler to set.
1244      */
1245     public void setErrorHandler(ErrorHandler errorHandler)
1246     {
1247         if (errorHandler!=null)
1248             errorHandler.setServer(getServer());
1249         if (getServer()!=null)
1250             getServer().getContainer().update(this, _errorHandler, errorHandler, "errorHandler",true);
1251         _errorHandler = errorHandler;
1252     }
1253     
1254     /* ------------------------------------------------------------ */
1255     public int getMaxFormContentSize()
1256     {
1257         return _maxFormContentSize;
1258     }
1259     
1260     /* ------------------------------------------------------------ */
1261     public void setMaxFormContentSize(int maxSize)
1262     {
1263         _maxFormContentSize=maxSize;
1264     }
1265 
1266 
1267     /* ------------------------------------------------------------ */
1268     /**
1269      * @return True if URLs are compacted to replace multiple '/'s with a single '/'
1270      */
1271     public boolean isCompactPath()
1272     {
1273         return _compactPath;
1274     }
1275 
1276     /* ------------------------------------------------------------ */
1277     /**
1278      * @param compactPath True if URLs are compacted to replace multiple '/'s with a single '/'
1279      */
1280     public void setCompactPath(boolean compactPath)
1281     {
1282         _compactPath=compactPath;
1283     }
1284 
1285     /* ------------------------------------------------------------ */
1286     public String toString()
1287     {
1288         
1289         return super.toString()+"@"+Integer.toHexString(hashCode())+getContextPath()+","+getBaseResource();
1290     }
1291 
1292     /* ------------------------------------------------------------ */
1293     public synchronized Class<?> loadClass(String className)
1294         throws ClassNotFoundException
1295     {
1296         if (className==null)
1297             return null;
1298         
1299         if (_classLoader==null)
1300             return Loader.loadClass(this.getClass(), className);
1301 
1302         return _classLoader.loadClass(className);
1303     }
1304     
1305 
1306     /* ------------------------------------------------------------ */
1307     public void addLocaleEncoding(String locale,String encoding)
1308     {
1309         if (_localeEncodingMap==null)
1310             _localeEncodingMap=new HashMap<String,String>();
1311         _localeEncodingMap.put(locale, encoding);
1312     }
1313     
1314     /* ------------------------------------------------------------ */
1315     /**
1316      * Get the character encoding for a locale. The full locale name is first
1317      * looked up in the map of encodings. If no encoding is found, then the
1318      * locale language is looked up. 
1319      *
1320      * @param locale a <code>Locale</code> value
1321      * @return a <code>String</code> representing the character encoding for
1322      * the locale or null if none found.
1323      */
1324     public String getLocaleEncoding(Locale locale)
1325     {
1326         if (_localeEncodingMap==null)
1327             return null;
1328         String encoding = _localeEncodingMap.get(locale.toString());
1329         if (encoding==null)
1330             encoding = _localeEncodingMap.get(locale.getLanguage());
1331         return encoding;
1332     }
1333     
1334     /* ------------------------------------------------------------ */
1335     /* 
1336      */
1337     public Resource getResource(String path) throws MalformedURLException
1338     {
1339         if (path==null || !path.startsWith(URIUtil.SLASH))
1340             throw new MalformedURLException(path);
1341         
1342         if (_baseResource==null)
1343             return null;
1344 
1345         try
1346         {
1347             path=URIUtil.canonicalPath(path);
1348             Resource resource=_baseResource.addPath(path);
1349             
1350             if (!_aliases && resource.getAlias()!=null)
1351             {
1352                 if (resource.exists())
1353                     Log.warn("Aliased resource: "+resource+"~="+resource.getAlias());
1354                 else if (Log.isDebugEnabled())
1355                     Log.debug("Aliased resource: "+resource+"~="+resource.getAlias());
1356                 return null;
1357             }
1358             
1359             return resource;
1360         }
1361         catch(Exception e)
1362         {
1363             Log.ignore(e);
1364         }
1365                     
1366         return null;
1367     }
1368 
1369     /* ------------------------------------------------------------ */
1370     /** Convert URL to Resource
1371      * wrapper for {@link Resource#newResource(URL)} enables extensions to 
1372      * provide alternate resource implementations.
1373      */
1374     public Resource newResource(URL url) throws IOException
1375     {
1376         return Resource.newResource(url);
1377     }
1378 
1379     /* ------------------------------------------------------------ */
1380     /** Convert URL to Resource
1381      * wrapper for {@link Resource#newResource(String)} enables extensions to 
1382      * provide alternate resource implementations.
1383      */
1384     public Resource newResource(String url) throws IOException
1385     {
1386         return Resource.newResource(url);
1387     }
1388 
1389     /* ------------------------------------------------------------ */
1390     /* 
1391      */
1392     public Set<String> getResourcePaths(String path)
1393     {           
1394         try
1395         {
1396             path=URIUtil.canonicalPath(path);
1397             Resource resource=getResource(path);
1398             
1399             if (resource!=null && resource.exists())
1400             {
1401                 if (!path.endsWith(URIUtil.SLASH))
1402                     path=path+URIUtil.SLASH;
1403                 
1404                 String[] l=resource.list();
1405                 if (l!=null)
1406                 {
1407                     HashSet<String> set = new HashSet<String>();
1408                     for(int i=0;i<l.length;i++)
1409                         set.add(path+l[i]);
1410                     return set;
1411                 }   
1412             }
1413         }
1414         catch(Exception e)
1415         {
1416             Log.ignore(e);
1417         }
1418         return Collections.emptySet();
1419     }
1420 
1421 
1422 
1423     /* ------------------------------------------------------------ */
1424     private String normalizeHostname( String host )
1425     {
1426         if ( host == null )
1427             return null;
1428         
1429         if ( host.endsWith( "." ) )
1430             return host.substring( 0, host.length() -1);
1431       
1432             return host;
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 }