View Javadoc

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