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(response.encodeRedirectURL(URIUtil.addPaths(request.getRequestURI(),URIUtil.SLASH)+"?"+request.getQueryString()));
    695                         else
    696                             response.sendRedirect(response.encodeRedirectURL(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                 base_request.setRequestListeners(_requestListeners);
    749                 if (_requestAttributeListeners!=null)
    750                 {
    751                     final int s=LazyList.size(_requestAttributeListeners);
    752                     for(int i=0;i<s;i++)
    753                         base_request.addEventListener(((EventListener)LazyList.get(_requestAttributeListeners,i)));
    754                 }
    755             }
    756
    757             // Handle the request
    758             try
    759             {
    760                 if (dispatch==REQUEST && isProtectedTarget(target))
    761                     throw new HttpException(HttpServletResponse.SC_NOT_FOUND);
    762
    763                 Handler handler = getHandler();
    764                 if (handler!=null)
    765                     handler.handle(target, request, response, dispatch);
    766             }
    767             catch(HttpException e)
    768             {
    769                 Log.debug(e);
    770                 response.sendError(e.getStatus(), e.getReason());
    771             }
    772             finally
    773             {
    774                 // Handle more REALLY SILLY request events!
    775                 if (new_context)
    776                 {
    777                     base_request.takeRequestListeners();
    778                     if (_requestAttributeListeners!=null)
    779                     {
    780                         for(int i=LazyList.size(_requestAttributeListeners);i-->0;)
    781                             base_request.removeEventListener(((EventListener)LazyList.get(_requestAttributeListeners,i)));
    782                     }
    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.toString());
    989             Log.debug(e);
    990             throw new IllegalArgumentException(resourceBase);
    991         }
    992     }
    993
    994     /* ------------------------------------------------------------ */
    995     /**
    996      * @return Returns the mimeTypes.
    997      */
    998     public MimeTypes getMimeTypes()
    999     {
    1000         return _mimeTypes;
    1001     }
    1002
    1003     /* ------------------------------------------------------------ */
    1004     /**
    1005      * @param mimeTypes The mimeTypes to set.
    1006      */
    1007     public void setMimeTypes(MimeTypes mimeTypes)
    1008     {
    1009         _mimeTypes = mimeTypes;
    1010     }
    1011
    1012     /* ------------------------------------------------------------ */
    1013     /**
    1014      */
    1015     public void setWelcomeFiles(String[] files)
    1016     {
    1017         _welcomeFiles=files;
    1018     }
    1019
    1020     /* ------------------------------------------------------------ */
    1021     /**
    1022      * @return The names of the files which the server should consider to be welcome files in this context.
    1023      * @see <a href="http://jcp.org/aboutJava/communityprocess/final/jsr154/index.html">The Servlet Specification</a>
    1024      * @see #setWelcomeFiles
    1025      */
    1026     public String[] getWelcomeFiles()
    1027     {
    1028         return _welcomeFiles;
    1029     }
    1030
    1031     /* ------------------------------------------------------------ */
    1032     /**
    1033      * @return Returns the errorHandler.
    1034      */
    1035     public ErrorHandler getErrorHandler()
    1036     {
    1037         return _errorHandler;
    1038     }
    1039
    1040     /* ------------------------------------------------------------ */
    1041     /**
    1042      * @param errorHandler The errorHandler to set.
    1043      */
    1044     public void setErrorHandler(ErrorHandler errorHandler)
    1045     {
    1046         if (errorHandler!=null)
    1047             errorHandler.setServer(getServer());
    1048         if (getServer()!=null)
    1049             getServer().getContainer().update(this, _errorHandler, errorHandler, "errorHandler",true);
    1050         _errorHandler = errorHandler;
    1051     }
    1052
    1053     /* ------------------------------------------------------------ */
    1054     public int getMaxFormContentSize()
    1055     {
    1056         return _maxFormContentSize;
    1057     }
    1058
    1059     /* ------------------------------------------------------------ */
    1060     public void setMaxFormContentSize(int maxSize)
    1061     {
    1062         _maxFormContentSize=maxSize;
    1063     }
    1064
    1065
    1066     /* ------------------------------------------------------------ */
    1067     /**
    1068      * @return True if URLs are compacted to replace multiple '/'s with a single '/'
    1069      */
    1070     public boolean isCompactPath()
    1071     {
    1072         return _compactPath;
    1073     }
    1074
    1075     /* ------------------------------------------------------------ */
    1076     /**
    1077      * @param compactPath True if URLs are compacted to replace multiple '/'s with a single '/'
    1078      */
    1079     public void setCompactPath(boolean compactPath)
    1080     {
    1081         _compactPath=compactPath;
    1082     }
    1083
    1084     /* ------------------------------------------------------------ */
    1085     public String toString()
    1086     {
    1087
    1088         return this.getClass().getName()+"@"+Integer.toHexString(hashCode())+"{"+getContextPath()+","+getBaseResource()+"}";
    1089     }
    1090
    1091     /* ------------------------------------------------------------ */
    1092     public synchronized Class loadClass(String className)
    1093         throws ClassNotFoundException
    1094     {
    1095         if (className==null)
    1096             return null;
    1097
    1098         if (_classLoader==null)
    1099             return Loader.loadClass(this.getClass(), className);
    1100
    1101         return _classLoader.loadClass(className);
    1102     }
    1103
    1104
    1105     /* ------------------------------------------------------------ */
    1106     public void addLocaleEncoding(String locale,String encoding)
    1107     {
    1108         if (_localeEncodingMap==null)
    1109             _localeEncodingMap=new HashMap();
    1110         _localeEncodingMap.put(locale, encoding);
    1111     }
    1112
    1113     /* ------------------------------------------------------------ */
    1114     /**
    1115      * Get the character encoding for a locale. The full locale name is first
    1116      * looked up in the map of encodings. If no encoding is found, then the
    1117      * locale language is looked up.
    1118      *
    1119      * @param locale a <code>Locale</code> value
    1120      * @return a <code>String</code> representing the character encoding for
    1121      * the locale or null if none found.
    1122      */
    1123     public String getLocaleEncoding(Locale locale)
    1124     {
    1125         if (_localeEncodingMap==null)
    1126             return null;
    1127         String encoding = (String)_localeEncodingMap.get(locale.toString());
    1128         if (encoding==null)
    1129             encoding = (String)_localeEncodingMap.get(locale.getLanguage());
    1130         return encoding;
    1131     }
    1132
    1133     /* ------------------------------------------------------------ */
    1134     /*
    1135      */
    1136     public Resource getResource(String path) throws MalformedURLException
    1137     {
    1138         if (path==null || !path.startsWith(URIUtil.SLASH))
    1139             throw new MalformedURLException(path);
    1140
    1141         if (_baseResource==null)
    1142             return null;
    1143
    1144         try
    1145         {
    1146             path=URIUtil.canonicalPath(path);
    1147             Resource resource=_baseResource.addPath(path);
    1148             return resource;
    1149         }
    1150         catch(Exception e)
    1151         {
    1152             Log.ignore(e);
    1153         }
    1154
    1155         return null;
    1156     }
    1157
    1158
    1159     /* ------------------------------------------------------------ */
    1160     /*
    1161      */
    1162     public Set getResourcePaths(String path)
    1163     {
    1164         try
    1165         {
    1166             path=URIUtil.canonicalPath(path);
    1167             Resource resource=getResource(path);
    1168
    1169             if (resource!=null && resource.exists())
    1170             {
    1171                 if (!path.endsWith(URIUtil.SLASH))
    1172                     path=path+URIUtil.SLASH;
    1173
    1174                 String[] l=resource.list();
    1175                 if (l!=null)
    1176                 {
    1177                     HashSet set = new HashSet();
    1178                     for(int i=0;i<l.length;i++)
    1179                         set.add(path+l[i]);
    1180                     return set;
    1181                 }
    1182             }
    1183         }
    1184         catch(Exception e)
    1185         {
    1186             Log.ignore(e);
    1187         }
    1188         return Collections.EMPTY_SET;
    1189     }
    1190
    1191
    1192     /* ------------------------------------------------------------ */
    1193     /** Context.
    1194      * <p>
    1195      * Implements {@link javax.servlet.ServletContext} from the {@link javax.servlet} package.
    1196      * </p>
    1197      * @author gregw
    1198      *
    1199      */
    1200     public class SContext implements ServletContext
    1201     {
    1202         /* ------------------------------------------------------------ */
    1203         protected SContext()
    1204         {
    1205         }
    1206
    1207         /* ------------------------------------------------------------ */
    1208         public ContextHandler getContextHandler()
    1209         {
    1210             // TODO reduce visibility of this method
    1211             return ContextHandler.this;
    1212         }
    1213
    1214         /* ------------------------------------------------------------ */
    1215         /*
    1216          * @see javax.servlet.ServletContext#getContext(java.lang.String)
    1217          */
    1218         public ServletContext getContext(String uripath)
    1219         {
    1220             // TODO this is a very poor implementation!
    1221             // TODO move this to Server
    1222             ContextHandler context=null;
    1223             Handler[] handlers = getServer().getChildHandlersByClass(ContextHandler.class);
    1224             for (int i=0;i<handlers.length;i++)
    1225             {
    1226                 if (handlers[i]==null || !handlers[i].isStarted())
    1227                     continue;
    1228                 ContextHandler ch = (ContextHandler)handlers[i];
    1229                 String context_path=ch.getContextPath();
    1230                 if (uripath.equals(context_path) || (uripath.startsWith(context_path)&&uripath.charAt(context_path.length())=='/'))
    1231                 {
    1232                     if (context==null || context_path.length()>context.getContextPath().length())
    1233                         context=ch;
    1234                 }
    1235             }
    1236
    1237             if (context!=null)
    1238                 return context._scontext;
    1239             return null;
    1240         }
    1241
    1242         /* ------------------------------------------------------------ */
    1243         /*
    1244          * @see javax.servlet.ServletContext#getMajorVersion()
    1245          */
    1246         public int getMajorVersion()
    1247         {
    1248             return 2;
    1249         }
    1250
    1251         /* ------------------------------------------------------------ */
    1252         /*
    1253          * @see javax.servlet.ServletContext#getMimeType(java.lang.String)
    1254          */
    1255         public String getMimeType(String file)
    1256         {
    1257             if (_mimeTypes==null)
    1258                 return null;
    1259             Buffer mime = _mimeTypes.getMimeByExtension(file);
    1260             if (mime!=null)
    1261                 return mime.toString();
    1262             return null;
    1263         }
    1264
    1265         /* ------------------------------------------------------------ */
    1266         /*
    1267          * @see javax.servlet.ServletContext#getMinorVersion()
    1268          */
    1269         public int getMinorVersion()
    1270         {
    1271             return 5;
    1272         }
    1273
    1274         /* ------------------------------------------------------------ */
    1275         /*
    1276          * @see javax.servlet.ServletContext#getNamedDispatcher(java.lang.String)
    1277          */
    1278         public RequestDispatcher getNamedDispatcher(String name)
    1279         {
    1280             return null;
    1281         }
    1282
    1283         /* ------------------------------------------------------------ */
    1284         /*
    1285          * @see javax.servlet.ServletContext#getRealPath(java.lang.String)
    1286          */
    1287         public String getRealPath(String path)
    1288         {
    1289             if(path==null)
    1290                 return null;
    1291             if(path.length()==0)
    1292                 path = URIUtil.SLASH;
    1293             else if(path.charAt(0)!='/')
    1294                 path = URIUtil.SLASH + path;
    1295
    1296             try
    1297             {
    1298                 Resource resource=ContextHandler.this.getResource(path);
    1299                 if(resource!=null)
    1300                 {
    1301                     File file = resource.getFile();
    1302                     if (file!=null)
    1303                         return file.getCanonicalPath();
    1304                 }
    1305             }
    1306             catch (Exception e)
    1307             {
    1308                 Log.ignore(e);
    1309             }
    1310
    1311             return null;
    1312         }
    1313
    1314         /* ------------------------------------------------------------ */
    1315         /*
    1316          * @see javax.servlet.ServletContext#getRequestDispatcher(java.lang.String)
    1317          */
    1318         public RequestDispatcher getRequestDispatcher(String uriInContext)
    1319         {
    1320             return null;
    1321         }
    1322
    1323         /* ------------------------------------------------------------ */
    1324         /*
    1325          */
    1326         public URL getResource(String path) throws MalformedURLException
    1327         {
    1328             Resource resource=ContextHandler.this.getResource(path);
    1329             if (resource!=null && resource.exists())
    1330                 return resource.getURL();
    1331             return null;
    1332         }
    1333
    1334         /* ------------------------------------------------------------ */
    1335         /*
    1336          * @see javax.servlet.ServletContext#getResourceAsStream(java.lang.String)
    1337          */
    1338         public InputStream getResourceAsStream(String path)
    1339         {
    1340             try
    1341             {
    1342                 URL url=getResource(path);
    1343                 if (url==null)
    1344                     return null;
    1345                 return url.openStream();
    1346             }
    1347             catch(Exception e)
    1348             {
    1349                 Log.ignore(e);
    1350                 return null;
    1351             }
    1352         }
    1353
    1354         /* ------------------------------------------------------------ */
    1355         /*
    1356          * @see javax.servlet.ServletContext#getResourcePaths(java.lang.String)
    1357          */
    1358         public Set getResourcePaths(String path)
    1359         {
    1360             return ContextHandler.this.getResourcePaths(path);
    1361         }
    1362
    1363         /* ------------------------------------------------------------ */
    1364         /*
    1365          * @see javax.servlet.ServletContext#getServerInfo()
    1366          */
    1367         public String getServerInfo()
    1368         {
    1369             return "jetty/"+Server.getVersion();
    1370         }
    1371
    1372         /* ------------------------------------------------------------ */
    1373         /*
    1374          * @see javax.servlet.ServletContext#getServlet(java.lang.String)
    1375          */
    1376         public Servlet getServlet(String name) throws ServletException
    1377         {
    1378             return null;
    1379         }
    1380
    1381         /* ------------------------------------------------------------ */
    1382         /*
    1383          * @see javax.servlet.ServletContext#getServletNames()
    1384          */
    1385         public Enumeration getServletNames()
    1386         {
    1387             return Collections.enumeration(Collections.EMPTY_LIST);
    1388         }
    1389
    1390         /* ------------------------------------------------------------ */
    1391         /*
    1392          * @see javax.servlet.ServletContext#getServlets()
    1393          */
    1394         public Enumeration getServlets()
    1395         {
    1396             return Collections.enumeration(Collections.EMPTY_LIST);
    1397         }
    1398
    1399         /* ------------------------------------------------------------ */
    1400         /*
    1401          * @see javax.servlet.ServletContext#log(java.lang.Exception, java.lang.String)
    1402          */
    1403         public void log(Exception exception, String msg)
    1404         {
    1405             _logger.warn(msg,exception);
    1406         }
    1407
    1408         /* ------------------------------------------------------------ */
    1409         /*
    1410          * @see javax.servlet.ServletContext#log(java.lang.String)
    1411          */
    1412         public void log(String msg)
    1413         {
    1414             _logger.info(msg, null, null);
    1415         }
    1416
    1417         /* ------------------------------------------------------------ */
    1418         /*
    1419          * @see javax.servlet.ServletContext#log(java.lang.String, java.lang.Throwable)
    1420          */
    1421         public void log(String message, Throwable throwable)
    1422         {
    1423             _logger.warn(message,throwable);
    1424         }
    1425
    1426         /* ------------------------------------------------------------ */
    1427         /*
    1428          * @see javax.servlet.ServletContext#getInitParameter(java.lang.String)
    1429          */
    1430         public String getInitParameter(String name)
    1431         {
    1432             return ContextHandler.this.getInitParameter(name);
    1433         }
    1434
    1435         /* ------------------------------------------------------------ */
    1436         /*
    1437          * @see javax.servlet.ServletContext#getInitParameterNames()
    1438          */
    1439         public Enumeration getInitParameterNames()
    1440         {
    1441             return ContextHandler.this.getInitParameterNames();
    1442         }
    1443
    1444         /* ------------------------------------------------------------ */
    1445         /*
    1446          * @see javax.servlet.ServletContext#getAttribute(java.lang.String)
    1447          */
    1448         public synchronized Object getAttribute(String name)
    1449         {
    1450             Object o = ContextHandler.this.getAttribute(name);
    1451             if (o==null && _contextAttributes!=null)
    1452                 o=_contextAttributes.getAttribute(name);
    1453             return o;
    1454         }
    1455
    1456         /* ------------------------------------------------------------ */
    1457         /*
    1458          * @see javax.servlet.ServletContext#getAttributeNames()
    1459          */
    1460         public synchronized Enumeration getAttributeNames()
    1461         {
    1462             HashSet set = new HashSet();
    1463             if (_contextAttributes!=null)
    1464             {
    1465             	Enumeration e = _contextAttributes.getAttributeNames();
    1466             	while(e.hasMoreElements())
    1467             		set.add(e.nextElement());
    1468             }
    1469             Enumeration e = _attributes.getAttributeNames();
    1470             while(e.hasMoreElements())
    1471                 set.add(e.nextElement());
    1472
    1473             return Collections.enumeration(set);
    1474         }
    1475
    1476         /* ------------------------------------------------------------ */
    1477         /*
    1478          * @see javax.servlet.ServletContext#setAttribute(java.lang.String, java.lang.Object)
    1479          */
    1480         public synchronized void setAttribute(String name, Object value)
    1481         {
    1482
    1483             if (_contextAttributes==null)
    1484             {
    1485             	// Set it on the handler
    1486             	ContextHandler.this.setAttribute(name, value);
    1487                 return;
    1488             }
    1489
    1490             setManagedAttribute(name,value);
    1491             Object old_value=_contextAttributes.getAttribute(name);
    1492
    1493             if (value==null)
    1494                 _contextAttributes.removeAttribute(name);
    1495             else
    1496                 _contextAttributes.setAttribute(name,value);
    1497
    1498             if (_contextAttributeListeners!=null)
    1499             {
    1500                 ServletContextAttributeEvent event =
    1501                     new ServletContextAttributeEvent(_scontext,name, old_value==null?value:old_value);
    1502
    1503                 for(int i=0;i<LazyList.size(_contextAttributeListeners);i++)
    1504                 {
    1505                     ServletContextAttributeListener l = (ServletContextAttributeListener)LazyList.get(_contextAttributeListeners,i);
    1506
    1507                     if (old_value==null)
    1508                         l.attributeAdded(event);
    1509                     else if (value==null)
    1510                         l.attributeRemoved(event);
    1511                     else
    1512                         l.attributeReplaced(event);
    1513                 }
    1514             }
    1515         }
    1516
    1517         /* ------------------------------------------------------------ */
    1518         /*
    1519          * @see javax.servlet.ServletContext#removeAttribute(java.lang.String)
    1520          */
    1521         public synchronized void removeAttribute(String name)
    1522         {
    1523             setManagedAttribute(name,null);
    1524
    1525             if (_contextAttributes==null)
    1526             {
    1527             	// Set it on the handler
    1528             	_attributes.removeAttribute(name);
    1529                 return;
    1530             }
    1531
    1532             Object old_value=_contextAttributes.getAttribute(name);
    1533             _contextAttributes.removeAttribute(name);
    1534             if (old_value!=null)
    1535             {
    1536                 if (_contextAttributeListeners!=null)
    1537                 {
    1538                     ServletContextAttributeEvent event =
    1539                         new ServletContextAttributeEvent(_scontext,name, old_value);
    1540
    1541                     for(int i=0;i<LazyList.size(_contextAttributeListeners);i++)
    1542                         ((ServletContextAttributeListener)LazyList.get(_contextAttributeListeners,i)).attributeRemoved(event);
    1543                 }
    1544             }
    1545         }
    1546
    1547         /* ------------------------------------------------------------ */
    1548         /*
    1549          * @see javax.servlet.ServletContext#getServletContextName()
    1550          */
    1551         public String getServletContextName()
    1552         {
    1553             String name = ContextHandler.this.getDisplayName();
    1554             if (name==null)
    1555                 name=ContextHandler.this.getContextPath();
    1556             return name;
    1557         }
    1558
    1559         /* ------------------------------------------------------------ */
    1560         /**
    1561          * @return Returns the _contextPath.
    1562          */
    1563         public String getContextPath()
    1564         {
    1565             if ((_contextPath != null) && _contextPath.equals(URIUtil.SLASH))
    1566                 return "";
    1567
    1568             return _contextPath;
    1569         }
    1570
    1571         /* ------------------------------------------------------------ */
    1572         public String toString()
    1573         {
    1574             return "ServletContext@"+Integer.toHexString(hashCode())+"{"+(getContextPath().equals("")?URIUtil.SLASH:getContextPath())+","+getBaseResource()+"}";
    1575         }
    1576     }
    1577
    1578     /* ------------------------------------------------------------ */
    1579     private String normalizeHostname( String host )
    1580     {
    1581         if ( host == null )
    1582             return null;
    1583
    1584         if ( host.endsWith( "." ) )
    1585             return host.substring( 0, host.length() -1);
    1586
    1587             return host;
    1588     }
    1589
    1590 }