Home | History | Annotate | Download | only in servlet
      1 //
      2 //  ========================================================================
      3 //  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
      4 //  ------------------------------------------------------------------------
      5 //  All rights reserved. This program and the accompanying materials
      6 //  are made available under the terms of the Eclipse Public License v1.0
      7 //  and Apache License v2.0 which accompanies this distribution.
      8 //
      9 //      The Eclipse Public License is available at
     10 //      http://www.eclipse.org/legal/epl-v10.html
     11 //
     12 //      The Apache License v2.0 is available at
     13 //      http://www.opensource.org/licenses/apache2.0.php
     14 //
     15 //  You may elect to redistribute this code under either of these licenses.
     16 //  ========================================================================
     17 //
     18 
     19 package org.eclipse.jetty.servlet;
     20 
     21 import java.io.IOException;
     22 import java.util.ArrayList;
     23 import java.util.Arrays;
     24 import java.util.Collections;
     25 import java.util.EnumSet;
     26 import java.util.HashMap;
     27 import java.util.HashSet;
     28 import java.util.ListIterator;
     29 import java.util.Set;
     30 import java.util.List;
     31 import java.util.Map;
     32 import java.util.Queue;
     33 import java.util.concurrent.ConcurrentHashMap;
     34 import java.util.concurrent.ConcurrentLinkedQueue;
     35 import java.util.concurrent.ConcurrentMap;
     36 
     37 import javax.servlet.AsyncContext;
     38 import javax.servlet.DispatcherType;
     39 import javax.servlet.Filter;
     40 import javax.servlet.FilterChain;
     41 import javax.servlet.RequestDispatcher;
     42 import javax.servlet.Servlet;
     43 import javax.servlet.ServletContext;
     44 import javax.servlet.ServletException;
     45 import javax.servlet.ServletRegistration;
     46 import javax.servlet.ServletRequest;
     47 import javax.servlet.ServletResponse;
     48 import javax.servlet.ServletSecurityElement;
     49 import javax.servlet.UnavailableException;
     50 import javax.servlet.http.HttpServletRequest;
     51 import javax.servlet.http.HttpServletResponse;
     52 
     53 import org.eclipse.jetty.continuation.ContinuationThrowable;
     54 import org.eclipse.jetty.http.HttpException;
     55 import org.eclipse.jetty.http.PathMap;
     56 import org.eclipse.jetty.io.EofException;
     57 import org.eclipse.jetty.io.RuntimeIOException;
     58 import org.eclipse.jetty.security.IdentityService;
     59 import org.eclipse.jetty.security.SecurityHandler;
     60 import org.eclipse.jetty.server.AbstractHttpConnection;
     61 import org.eclipse.jetty.server.AsyncContinuation;
     62 import org.eclipse.jetty.server.Dispatcher;
     63 import org.eclipse.jetty.server.AbstractHttpConnection;
     64 import org.eclipse.jetty.server.Request;
     65 import org.eclipse.jetty.server.Server;
     66 import org.eclipse.jetty.server.ServletRequestHttpWrapper;
     67 import org.eclipse.jetty.server.ServletResponseHttpWrapper;
     68 import org.eclipse.jetty.server.UserIdentity;
     69 import org.eclipse.jetty.server.handler.ContextHandler;
     70 import org.eclipse.jetty.server.handler.ScopedHandler;
     71 import org.eclipse.jetty.servlet.Holder.Source;
     72 import org.eclipse.jetty.util.LazyList;
     73 import org.eclipse.jetty.util.MultiException;
     74 import org.eclipse.jetty.util.MultiMap;
     75 import org.eclipse.jetty.util.TypeUtil;
     76 import org.eclipse.jetty.util.URIUtil;
     77 import org.eclipse.jetty.util.log.Log;
     78 import org.eclipse.jetty.util.log.Logger;
     79 
     80 /* --------------------------------------------------------------------- */
     81 /** Servlet HttpHandler.
     82  * This handler maps requests to servlets that implement the
     83  * javax.servlet.http.HttpServlet API.
     84  * <P>
     85  * This handler does not implement the full J2EE features and is intended to
     86  * be used directly when a full web application is not required.  If a Web application is required,
     87  * then this handler should be used as part of a <code>org.eclipse.jetty.webapp.WebAppContext</code>.
     88  * <p>
     89  * Unless run as part of a {@link ServletContextHandler} or derivative, the {@link #initialize()}
     90  * method must be called manually after start().
     91  */
     92 public class ServletHandler extends ScopedHandler
     93 {
     94     private static final Logger LOG = Log.getLogger(ServletHandler.class);
     95 
     96     /* ------------------------------------------------------------ */
     97     public static final String __DEFAULT_SERVLET="default";
     98 
     99     /* ------------------------------------------------------------ */
    100     private ServletContextHandler _contextHandler;
    101     private ContextHandler.Context _servletContext;
    102     private FilterHolder[] _filters=new FilterHolder[0];
    103     private FilterMapping[] _filterMappings;
    104     private int _matchBeforeIndex = -1; //index of last programmatic FilterMapping with isMatchAfter=false
    105     private int _matchAfterIndex = -1;  //index of 1st programmatic FilterMapping with isMatchAfter=true
    106     private boolean _filterChainsCached=true;
    107     private int _maxFilterChainsCacheSize=512;
    108     private boolean _startWithUnavailable=false;
    109     private IdentityService _identityService;
    110 
    111     private ServletHolder[] _servlets=new ServletHolder[0];
    112     private ServletMapping[] _servletMappings;
    113 
    114     private final Map<String,FilterHolder> _filterNameMap= new HashMap<String,FilterHolder>();
    115     private List<FilterMapping> _filterPathMappings;
    116     private MultiMap<String> _filterNameMappings;
    117 
    118     private final Map<String,ServletHolder> _servletNameMap=new HashMap<String,ServletHolder>();
    119     private PathMap _servletPathMap;
    120 
    121     protected final ConcurrentMap<String,FilterChain> _chainCache[] = new ConcurrentMap[FilterMapping.ALL];
    122     protected final Queue<String>[] _chainLRU = new Queue[FilterMapping.ALL];
    123 
    124 
    125     /* ------------------------------------------------------------ */
    126     /** Constructor.
    127      */
    128     public ServletHandler()
    129     {
    130     }
    131 
    132     /* ------------------------------------------------------------ */
    133     /*
    134      * @see org.eclipse.jetty.server.handler.AbstractHandler#setServer(org.eclipse.jetty.server.Server)
    135      */
    136     public void setServer(Server server)
    137     {
    138         Server old=getServer();
    139         if (old!=null && old!=server)
    140         {
    141             getServer().getContainer().update(this, _filters, null, "filter",true);
    142             getServer().getContainer().update(this, _filterMappings, null, "filterMapping",true);
    143             getServer().getContainer().update(this, _servlets, null, "servlet",true);
    144             getServer().getContainer().update(this, _servletMappings, null, "servletMapping",true);
    145         }
    146 
    147         super.setServer(server);
    148 
    149         if (server!=null && old!=server)
    150         {
    151             server.getContainer().update(this, null, _filters, "filter",true);
    152             server.getContainer().update(this, null, _filterMappings, "filterMapping",true);
    153             server.getContainer().update(this, null, _servlets, "servlet",true);
    154             server.getContainer().update(this, null, _servletMappings, "servletMapping",true);
    155         }
    156     }
    157 
    158     /* ----------------------------------------------------------------- */
    159     @Override
    160     protected synchronized void doStart()
    161         throws Exception
    162     {
    163         _servletContext=ContextHandler.getCurrentContext();
    164         _contextHandler=(ServletContextHandler)(_servletContext==null?null:_servletContext.getContextHandler());
    165 
    166         if (_contextHandler!=null)
    167         {
    168             SecurityHandler security_handler = (SecurityHandler)_contextHandler.getChildHandlerByClass(SecurityHandler.class);
    169             if (security_handler!=null)
    170                 _identityService=security_handler.getIdentityService();
    171         }
    172 
    173         updateNameMappings();
    174         updateMappings();
    175 
    176         if(_filterChainsCached)
    177         {
    178             _chainCache[FilterMapping.REQUEST]=new ConcurrentHashMap<String,FilterChain>();
    179             _chainCache[FilterMapping.FORWARD]=new ConcurrentHashMap<String,FilterChain>();
    180             _chainCache[FilterMapping.INCLUDE]=new ConcurrentHashMap<String,FilterChain>();
    181             _chainCache[FilterMapping.ERROR]=new ConcurrentHashMap<String,FilterChain>();
    182             _chainCache[FilterMapping.ASYNC]=new ConcurrentHashMap<String,FilterChain>();
    183 
    184             _chainLRU[FilterMapping.REQUEST]=new ConcurrentLinkedQueue<String>();
    185             _chainLRU[FilterMapping.FORWARD]=new ConcurrentLinkedQueue<String>();
    186             _chainLRU[FilterMapping.INCLUDE]=new ConcurrentLinkedQueue<String>();
    187             _chainLRU[FilterMapping.ERROR]=new ConcurrentLinkedQueue<String>();
    188             _chainLRU[FilterMapping.ASYNC]=new ConcurrentLinkedQueue<String>();
    189         }
    190 
    191         super.doStart();
    192 
    193         if (_contextHandler==null || !(_contextHandler instanceof ServletContextHandler))
    194             initialize();
    195     }
    196 
    197     /* ----------------------------------------------------------------- */
    198     @Override
    199     protected synchronized void doStop()
    200         throws Exception
    201     {
    202         super.doStop();
    203 
    204         // Stop filters
    205         List<FilterHolder> filterHolders = new ArrayList<FilterHolder>();
    206         List<FilterMapping> filterMappings = LazyList.array2List(_filterMappings);
    207         if (_filters!=null)
    208         {
    209             for (int i=_filters.length; i-->0;)
    210             {
    211                 try { _filters[i].stop(); }catch(Exception e){LOG.warn(Log.EXCEPTION,e);}
    212                 if (_filters[i].getSource() != Source.EMBEDDED)
    213                 {
    214                     //remove all of the mappings that were for non-embedded filters
    215                     _filterNameMap.remove(_filters[i].getName());
    216                     //remove any mappings associated with this filter
    217                     ListIterator<FilterMapping> fmitor = filterMappings.listIterator();
    218                     while (fmitor.hasNext())
    219                     {
    220                         FilterMapping fm = fmitor.next();
    221                         if (fm.getFilterName().equals(_filters[i].getName()))
    222                             fmitor.remove();
    223                     }
    224                 }
    225                 else
    226                     filterHolders.add(_filters[i]); //only retain embedded
    227             }
    228         }
    229         _filters = (FilterHolder[]) LazyList.toArray(filterHolders, FilterHolder.class);
    230         _filterMappings = (FilterMapping[]) LazyList.toArray(filterMappings, FilterMapping.class);
    231         _matchAfterIndex = (_filterMappings == null || _filterMappings.length == 0 ? -1 : _filterMappings.length-1);
    232         _matchBeforeIndex = -1;
    233 
    234 
    235         // Stop servlets
    236         List<ServletHolder> servletHolders = new ArrayList<ServletHolder>();  //will be remaining servlets
    237         List<ServletMapping> servletMappings = LazyList.array2List(_servletMappings); //will be remaining mappings
    238         if (_servlets!=null)
    239         {
    240             for (int i=_servlets.length; i-->0;)
    241             {
    242                 try { _servlets[i].stop(); }catch(Exception e){LOG.warn(Log.EXCEPTION,e);}
    243                 if (_servlets[i].getSource() != Source.EMBEDDED)
    244                 {
    245                     //remove from servlet name map
    246                     _servletNameMap.remove(_servlets[i].getName());
    247                     //remove any mappings associated with this servlet
    248                     ListIterator<ServletMapping> smitor = servletMappings.listIterator();
    249                     while (smitor.hasNext())
    250                     {
    251                         ServletMapping sm = smitor.next();
    252                         if (sm.getServletName().equals(_servlets[i].getName()))
    253                             smitor.remove();
    254                     }
    255                 }
    256                 else
    257                     servletHolders.add(_servlets[i]); //only retain embedded
    258             }
    259         }
    260         _servlets = (ServletHolder[]) LazyList.toArray(servletHolders, ServletHolder.class);
    261         _servletMappings = (ServletMapping[])LazyList.toArray(servletMappings, ServletMapping.class);
    262 
    263 
    264         //will be regenerated on next start
    265         _filterPathMappings=null;
    266         _filterNameMappings=null;
    267         _servletPathMap=null;
    268     }
    269 
    270     /* ------------------------------------------------------------ */
    271     protected IdentityService getIdentityService()
    272     {
    273         return _identityService;
    274     }
    275 
    276     /* ------------------------------------------------------------ */
    277     /**
    278      * @return Returns the contextLog.
    279      */
    280     public Object getContextLog()
    281     {
    282         return null;
    283     }
    284 
    285     /* ------------------------------------------------------------ */
    286     /**
    287      * @return Returns the filterMappings.
    288      */
    289     public FilterMapping[] getFilterMappings()
    290     {
    291         return _filterMappings;
    292     }
    293 
    294     /* ------------------------------------------------------------ */
    295     /** Get Filters.
    296      * @return Array of defined servlets
    297      */
    298     public FilterHolder[] getFilters()
    299     {
    300         return _filters;
    301     }
    302 
    303     /* ------------------------------------------------------------ */
    304     /** ServletHolder matching path.
    305      * @param pathInContext Path within _context.
    306      * @return PathMap Entries pathspec to ServletHolder
    307      */
    308     public PathMap.Entry getHolderEntry(String pathInContext)
    309     {
    310         if (_servletPathMap==null)
    311             return null;
    312         return _servletPathMap.getMatch(pathInContext);
    313     }
    314 
    315     /* ------------------------------------------------------------ */
    316     public ServletContext getServletContext()
    317     {
    318         return _servletContext;
    319     }
    320 
    321     /* ------------------------------------------------------------ */
    322     /**
    323      * @return Returns the servletMappings.
    324      */
    325     public ServletMapping[] getServletMappings()
    326     {
    327         return _servletMappings;
    328     }
    329 
    330     /* ------------------------------------------------------------ */
    331     /**
    332      * @return Returns the servletMappings.
    333      */
    334     public ServletMapping getServletMapping(String pattern)
    335     {
    336         ServletMapping theMapping = null;
    337         if (_servletMappings!=null)
    338         {
    339             for (ServletMapping m:_servletMappings)
    340             {
    341                 String[] paths=m.getPathSpecs();
    342                 if (paths!=null)
    343                 {
    344                     for (String path:paths)
    345                     {
    346                         if (pattern.equals(path))
    347                             theMapping = m;
    348                     }
    349                 }
    350             }
    351         }
    352         return theMapping;
    353     }
    354 
    355     /* ------------------------------------------------------------ */
    356     /** Get Servlets.
    357      * @return Array of defined servlets
    358      */
    359     public ServletHolder[] getServlets()
    360     {
    361         return _servlets;
    362     }
    363 
    364     /* ------------------------------------------------------------ */
    365     public ServletHolder getServlet(String name)
    366     {
    367         return (ServletHolder)_servletNameMap.get(name);
    368     }
    369 
    370     /* ------------------------------------------------------------ */
    371     @Override
    372     public void doScope(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
    373     {
    374         // Get the base requests
    375         final String old_servlet_path=baseRequest.getServletPath();
    376         final String old_path_info=baseRequest.getPathInfo();
    377 
    378         DispatcherType type = baseRequest.getDispatcherType();
    379 
    380         ServletHolder servlet_holder=null;
    381         UserIdentity.Scope old_scope=null;
    382 
    383         // find the servlet
    384         if (target.startsWith("/"))
    385         {
    386             // Look for the servlet by path
    387             PathMap.Entry entry=getHolderEntry(target);
    388             if (entry!=null)
    389             {
    390                 servlet_holder=(ServletHolder)entry.getValue();
    391 
    392                 String servlet_path_spec=(String)entry.getKey();
    393                 String servlet_path=entry.getMapped()!=null?entry.getMapped():PathMap.pathMatch(servlet_path_spec,target);
    394                 String path_info=PathMap.pathInfo(servlet_path_spec,target);
    395 
    396                 if (DispatcherType.INCLUDE.equals(type))
    397                 {
    398                     baseRequest.setAttribute(Dispatcher.INCLUDE_SERVLET_PATH,servlet_path);
    399                     baseRequest.setAttribute(Dispatcher.INCLUDE_PATH_INFO, path_info);
    400                 }
    401                 else
    402                 {
    403                     baseRequest.setServletPath(servlet_path);
    404                     baseRequest.setPathInfo(path_info);
    405                 }
    406             }
    407         }
    408         else
    409         {
    410             // look for a servlet by name!
    411             servlet_holder=(ServletHolder)_servletNameMap.get(target);
    412         }
    413 
    414         if (LOG.isDebugEnabled())
    415             LOG.debug("servlet {}|{}|{} -> {}",baseRequest.getContextPath(),baseRequest.getServletPath(),baseRequest.getPathInfo(),servlet_holder);
    416 
    417         try
    418         {
    419             // Do the filter/handling thang
    420             old_scope=baseRequest.getUserIdentityScope();
    421             baseRequest.setUserIdentityScope(servlet_holder);
    422 
    423             // start manual inline of nextScope(target,baseRequest,request,response);
    424             if (never())
    425                 nextScope(target,baseRequest,request,response);
    426             else if (_nextScope!=null)
    427                 _nextScope.doScope(target,baseRequest,request, response);
    428             else if (_outerScope!=null)
    429                 _outerScope.doHandle(target,baseRequest,request, response);
    430             else
    431                 doHandle(target,baseRequest,request, response);
    432             // end manual inline (pathentic attempt to reduce stack depth)
    433         }
    434         finally
    435         {
    436             if (old_scope!=null)
    437                 baseRequest.setUserIdentityScope(old_scope);
    438 
    439             if (!(DispatcherType.INCLUDE.equals(type)))
    440             {
    441                 baseRequest.setServletPath(old_servlet_path);
    442                 baseRequest.setPathInfo(old_path_info);
    443             }
    444         }
    445     }
    446 
    447     /* ------------------------------------------------------------ */
    448     /*
    449      * @see org.eclipse.jetty.server.Handler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, int)
    450      */
    451     @Override
    452     public void doHandle(String target, Request baseRequest,HttpServletRequest request, HttpServletResponse response)
    453         throws IOException, ServletException
    454     {
    455         DispatcherType type = baseRequest.getDispatcherType();
    456 
    457         ServletHolder servlet_holder=(ServletHolder) baseRequest.getUserIdentityScope();
    458         FilterChain chain=null;
    459 
    460         // find the servlet
    461         if (target.startsWith("/"))
    462         {
    463             if (servlet_holder!=null && _filterMappings!=null && _filterMappings.length>0)
    464                 chain=getFilterChain(baseRequest, target, servlet_holder);
    465         }
    466         else
    467         {
    468             if (servlet_holder!=null)
    469             {
    470                 if (_filterMappings!=null && _filterMappings.length>0)
    471                 {
    472                     chain=getFilterChain(baseRequest, null,servlet_holder);
    473                 }
    474             }
    475         }
    476 
    477         LOG.debug("chain={}",chain);
    478 
    479         Throwable th=null;
    480         try
    481         {
    482             if (servlet_holder==null)
    483             {
    484                 if (getHandler()==null)
    485                     notFound(request, response);
    486                 else
    487                     nextHandle(target,baseRequest,request,response);
    488             }
    489             else
    490             {
    491                 // unwrap any tunnelling of base Servlet request/responses
    492                 ServletRequest req = request;
    493                 if (req instanceof ServletRequestHttpWrapper)
    494                     req = ((ServletRequestHttpWrapper)req).getRequest();
    495                 ServletResponse res = response;
    496                 if (res instanceof ServletResponseHttpWrapper)
    497                     res = ((ServletResponseHttpWrapper)res).getResponse();
    498 
    499                 // Do the filter/handling thang
    500                 if (chain!=null)
    501                     chain.doFilter(req, res);
    502                 else
    503                     servlet_holder.handle(baseRequest,req,res);
    504             }
    505         }
    506         catch(EofException e)
    507         {
    508             throw e;
    509         }
    510         catch(RuntimeIOException e)
    511         {
    512             throw e;
    513         }
    514         catch(ContinuationThrowable e)
    515         {
    516             throw e;
    517         }
    518         catch(Exception e)
    519         {
    520             if (!(DispatcherType.REQUEST.equals(type) || DispatcherType.ASYNC.equals(type)))
    521             {
    522                 if (e instanceof IOException)
    523                     throw (IOException)e;
    524                 if (e instanceof RuntimeException)
    525                     throw (RuntimeException)e;
    526                 if (e instanceof ServletException)
    527                     throw (ServletException)e;
    528             }
    529 
    530             // unwrap cause
    531             th=e;
    532             if (th instanceof UnavailableException)
    533             {
    534                 LOG.debug(th);
    535             }
    536             else if (th instanceof ServletException)
    537             {
    538                 LOG.warn(th);
    539                 Throwable cause=((ServletException)th).getRootCause();
    540                 if (cause!=null)
    541                     th=cause;
    542             }
    543 
    544             // handle or log exception
    545             if (th instanceof HttpException)
    546                 throw (HttpException)th;
    547             else if (th instanceof RuntimeIOException)
    548                 throw (RuntimeIOException)th;
    549             else if (th instanceof EofException)
    550                 throw (EofException)th;
    551 
    552             else if (LOG.isDebugEnabled())
    553             {
    554                 LOG.warn(request.getRequestURI(), th);
    555                 LOG.debug(request.toString());
    556             }
    557             else if (th instanceof IOException || th instanceof UnavailableException)
    558             {
    559                 LOG.debug(request.getRequestURI(),th);
    560             }
    561             else
    562             {
    563                 LOG.warn(request.getRequestURI(),th);
    564             }
    565 
    566             request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,th.getClass());
    567             request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,th);
    568             if (!response.isCommitted())
    569             {
    570                 if (th instanceof UnavailableException)
    571                 {
    572                     UnavailableException ue = (UnavailableException)th;
    573                     if (ue.isPermanent())
    574                         response.sendError(HttpServletResponse.SC_NOT_FOUND);
    575                     else
    576                         response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
    577                 }
    578                 else
    579                     response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
    580             }
    581             else
    582                 LOG.debug("Response already committed for handling "+th);
    583 
    584         }
    585         catch(Error e)
    586         {
    587             if (!(DispatcherType.REQUEST.equals(type) || DispatcherType.ASYNC.equals(type)))
    588                 throw e;
    589             th=e;
    590             LOG.warn("Error for "+request.getRequestURI(),e);
    591             if(LOG.isDebugEnabled())LOG.debug(request.toString());
    592 
    593             request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,e.getClass());
    594             request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,e);
    595             if (!response.isCommitted())
    596                 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
    597             else
    598                 LOG.debug("Response already committed for handling ",e);
    599         }
    600         finally
    601         {
    602             if (servlet_holder!=null)
    603                 baseRequest.setHandled(true);
    604 
    605             // Complete async requests
    606             if (th!=null && request.isAsyncStarted())
    607                 ((AsyncContinuation)request.getAsyncContext()).errorComplete();
    608         }
    609     }
    610 
    611     /* ------------------------------------------------------------ */
    612     protected FilterChain getFilterChain(Request baseRequest, String pathInContext, ServletHolder servletHolder)
    613     {
    614         String key=pathInContext==null?servletHolder.getName():pathInContext;
    615         int dispatch = FilterMapping.dispatch(baseRequest.getDispatcherType());
    616 
    617         if (_filterChainsCached && _chainCache!=null)
    618         {
    619             FilterChain chain = (FilterChain)_chainCache[dispatch].get(key);
    620             if (chain!=null)
    621                 return chain;
    622         }
    623 
    624         // Build list of filters
    625         Object filters= null;
    626         // Path filters
    627         if (pathInContext!=null && _filterPathMappings!=null)
    628         {
    629             for (int i= 0; i < _filterPathMappings.size(); i++)
    630             {
    631                 FilterMapping mapping = (FilterMapping)_filterPathMappings.get(i);
    632                 if (mapping.appliesTo(pathInContext, dispatch))
    633                     filters= LazyList.add(filters, mapping.getFilterHolder());
    634             }
    635         }
    636 
    637         // Servlet name filters
    638         if (servletHolder != null && _filterNameMappings!=null && _filterNameMappings.size() > 0)
    639         {
    640             // Servlet name filters
    641             if (_filterNameMappings.size() > 0)
    642             {
    643                 Object o= _filterNameMappings.get(servletHolder.getName());
    644                 for (int i=0; i<LazyList.size(o);i++)
    645                 {
    646                     FilterMapping mapping = (FilterMapping)LazyList.get(o,i);
    647                     if (mapping.appliesTo(dispatch))
    648                         filters=LazyList.add(filters,mapping.getFilterHolder());
    649                 }
    650 
    651                 o= _filterNameMappings.get("*");
    652                 for (int i=0; i<LazyList.size(o);i++)
    653                 {
    654                     FilterMapping mapping = (FilterMapping)LazyList.get(o,i);
    655                     if (mapping.appliesTo(dispatch))
    656                         filters=LazyList.add(filters,mapping.getFilterHolder());
    657                 }
    658             }
    659         }
    660 
    661         if (filters==null)
    662             return null;
    663 
    664 
    665         FilterChain chain = null;
    666         if (_filterChainsCached)
    667         {
    668             if (LazyList.size(filters) > 0)
    669                 chain= new CachedChain(filters, servletHolder);
    670 
    671             final Map<String,FilterChain> cache=_chainCache[dispatch];
    672             final Queue<String> lru=_chainLRU[dispatch];
    673 
    674         	// Do we have too many cached chains?
    675         	while (_maxFilterChainsCacheSize>0 && cache.size()>=_maxFilterChainsCacheSize)
    676         	{
    677         	    // The LRU list is not atomic with the cache map, so be prepared to invalidate if
    678         	    // a key is not found to delete.
    679         	    // Delete by LRU (where U==created)
    680         	    String k=lru.poll();
    681         	    if (k==null)
    682         	    {
    683         	        cache.clear();
    684         	        break;
    685         	    }
    686         	    cache.remove(k);
    687         	}
    688 
    689         	cache.put(key,chain);
    690         	lru.add(key);
    691         }
    692         else if (LazyList.size(filters) > 0)
    693             chain = new Chain(baseRequest,filters, servletHolder);
    694 
    695         return chain;
    696     }
    697 
    698     /* ------------------------------------------------------------ */
    699     protected void invalidateChainsCache()
    700     {
    701         if (_chainLRU[FilterMapping.REQUEST]!=null)
    702         {
    703             _chainLRU[FilterMapping.REQUEST].clear();
    704             _chainLRU[FilterMapping.FORWARD].clear();
    705             _chainLRU[FilterMapping.INCLUDE].clear();
    706             _chainLRU[FilterMapping.ERROR].clear();
    707             _chainLRU[FilterMapping.ASYNC].clear();
    708 
    709             _chainCache[FilterMapping.REQUEST].clear();
    710             _chainCache[FilterMapping.FORWARD].clear();
    711             _chainCache[FilterMapping.INCLUDE].clear();
    712             _chainCache[FilterMapping.ERROR].clear();
    713             _chainCache[FilterMapping.ASYNC].clear();
    714         }
    715     }
    716 
    717     /* ------------------------------------------------------------ */
    718     /**
    719      * @return true if the handler is started and there are no unavailable servlets
    720      */
    721     public boolean isAvailable()
    722     {
    723         if (!isStarted())
    724             return false;
    725         ServletHolder[] holders = getServlets();
    726         for (int i=0;i<holders.length;i++)
    727         {
    728             ServletHolder holder = holders[i];
    729             if (holder!=null && !holder.isAvailable())
    730                 return false;
    731         }
    732         return true;
    733     }
    734 
    735     /* ------------------------------------------------------------ */
    736     /**
    737      * @param start True if this handler will start with unavailable servlets
    738      */
    739     public void setStartWithUnavailable(boolean start)
    740     {
    741         _startWithUnavailable=start;
    742     }
    743 
    744     /* ------------------------------------------------------------ */
    745     /**
    746      * @return True if this handler will start with unavailable servlets
    747      */
    748     public boolean isStartWithUnavailable()
    749     {
    750         return _startWithUnavailable;
    751     }
    752 
    753 
    754 
    755     /* ------------------------------------------------------------ */
    756     /** Initialize filters and load-on-startup servlets.
    757      * Called automatically from start if autoInitializeServlet is true.
    758      */
    759     public void initialize()
    760         throws Exception
    761     {
    762         MultiException mx = new MultiException();
    763 
    764         // Start filters
    765         if (_filters!=null)
    766         {
    767             for (int i=0;i<_filters.length; i++)
    768                 _filters[i].start();
    769         }
    770 
    771         if (_servlets!=null)
    772         {
    773             // Sort and Initialize servlets
    774             ServletHolder[] servlets = (ServletHolder[])_servlets.clone();
    775             Arrays.sort(servlets);
    776             for (int i=0; i<servlets.length; i++)
    777             {
    778                 try
    779                 {
    780                     if (servlets[i].getClassName()==null && servlets[i].getForcedPath()!=null)
    781                     {
    782                         ServletHolder forced_holder = (ServletHolder)_servletPathMap.match(servlets[i].getForcedPath());
    783                         if (forced_holder==null || forced_holder.getClassName()==null)
    784                         {
    785                             mx.add(new IllegalStateException("No forced path servlet for "+servlets[i].getForcedPath()));
    786                             continue;
    787                         }
    788                         servlets[i].setClassName(forced_holder.getClassName());
    789                     }
    790 
    791                     servlets[i].start();
    792                 }
    793                 catch(Throwable e)
    794                 {
    795                     LOG.debug(Log.EXCEPTION,e);
    796                     mx.add(e);
    797                 }
    798             }
    799             mx.ifExceptionThrow();
    800         }
    801     }
    802 
    803     /* ------------------------------------------------------------ */
    804     /**
    805      * @return Returns the filterChainsCached.
    806      */
    807     public boolean isFilterChainsCached()
    808     {
    809         return _filterChainsCached;
    810     }
    811 
    812     /* ------------------------------------------------------------ */
    813     /**
    814      * see also newServletHolder(Class)
    815      */
    816     public ServletHolder newServletHolder(Holder.Source source)
    817     {
    818         return new ServletHolder(source);
    819     }
    820 
    821     /* ------------------------------------------------------------ */
    822     /** Convenience method to add a servlet Holder.
    823     public ServletHolder newServletHolder(Class<? extends Servlet> servlet)
    824     {
    825         return new ServletHolder(servlet);
    826     }
    827 
    828     /* ------------------------------------------------------------ */
    829     /** Convenience method to add a servlet.
    830      * @return The servlet holder.
    831      */
    832     public ServletHolder addServletWithMapping (String className,String pathSpec)
    833     {
    834         ServletHolder holder = newServletHolder(Holder.Source.EMBEDDED);
    835         holder.setClassName(className);
    836         addServletWithMapping(holder,pathSpec);
    837         return holder;
    838     }
    839 
    840     /* ------------------------------------------------------------ */
    841     /** conveniance method to add a servlet.
    842      * @return The servlet holder.
    843      */
    844     public ServletHolder addServletWithMapping (Class<? extends Servlet> servlet,String pathSpec)
    845     {
    846         ServletHolder holder = newServletHolder(Holder.Source.EMBEDDED);
    847         holder.setHeldClass(servlet);
    848         //DUPLICATES adding servlet from addServletWithMapping(holder, pathSpec)?
    849         //setServlets((ServletHolder[])LazyList.addToArray(getServlets(), holder, ServletHolder.class));
    850         addServletWithMapping(holder,pathSpec);
    851 
    852         return holder;
    853     }
    854 
    855     /* ------------------------------------------------------------ */
    856     /** conveniance method to add a servlet.
    857      * @param servlet servlet holder to add
    858      * @param pathSpec servlet mappings for the servletHolder
    859      */
    860     public void addServletWithMapping (ServletHolder servlet,String pathSpec)
    861     {
    862         ServletHolder[] holders=getServlets();
    863         if (holders!=null)
    864             holders = holders.clone();
    865 
    866         try
    867         {
    868             setServlets((ServletHolder[])LazyList.addToArray(holders, servlet, ServletHolder.class));
    869 
    870             ServletMapping mapping = new ServletMapping();
    871             mapping.setServletName(servlet.getName());
    872             mapping.setPathSpec(pathSpec);
    873             setServletMappings((ServletMapping[])LazyList.addToArray(getServletMappings(), mapping, ServletMapping.class));
    874         }
    875         catch (Exception e)
    876         {
    877             setServlets(holders);
    878             if (e instanceof RuntimeException)
    879                 throw (RuntimeException)e;
    880             throw new RuntimeException(e);
    881         }
    882     }
    883 
    884 
    885     /* ------------------------------------------------------------ */
    886     /**Convenience method to add a pre-constructed ServletHolder.
    887      * @param holder
    888      */
    889     public void addServlet(ServletHolder holder)
    890     {
    891         setServlets((ServletHolder[])LazyList.addToArray(getServlets(), holder, ServletHolder.class));
    892     }
    893 
    894     /* ------------------------------------------------------------ */
    895     /** Convenience method to add a pre-constructed ServletMapping.
    896      * @param mapping
    897      */
    898     public void addServletMapping (ServletMapping mapping)
    899     {
    900         setServletMappings((ServletMapping[])LazyList.addToArray(getServletMappings(), mapping, ServletMapping.class));
    901     }
    902 
    903     public Set<String>  setServletSecurity(ServletRegistration.Dynamic registration, ServletSecurityElement servletSecurityElement) {
    904         if (_contextHandler != null) {
    905             return _contextHandler.setServletSecurity(registration, servletSecurityElement);
    906         }
    907         return Collections.emptySet();
    908     }
    909 
    910     /* ------------------------------------------------------------ */
    911     /**
    912      * @see #newFilterHolder(Class)
    913      */
    914     public FilterHolder newFilterHolder(Holder.Source source)
    915     {
    916         return new FilterHolder(source);
    917     }
    918 
    919     /* ------------------------------------------------------------ */
    920     public FilterHolder getFilter(String name)
    921     {
    922         return (FilterHolder)_filterNameMap.get(name);
    923     }
    924 
    925 
    926     /* ------------------------------------------------------------ */
    927     /** Convenience method to add a filter.
    928      * @param filter  class of filter to create
    929      * @param pathSpec filter mappings for filter
    930      * @param dispatches see {@link FilterMapping#setDispatches(int)}
    931      * @return The filter holder.
    932      */
    933     public FilterHolder addFilterWithMapping (Class<? extends Filter> filter,String pathSpec,EnumSet<DispatcherType> dispatches)
    934     {
    935         FilterHolder holder = newFilterHolder(Holder.Source.EMBEDDED);
    936         holder.setHeldClass(filter);
    937         addFilterWithMapping(holder,pathSpec,dispatches);
    938 
    939         return holder;
    940     }
    941 
    942     /* ------------------------------------------------------------ */
    943     /** Convenience method to add a filter.
    944      * @param className of filter
    945      * @param pathSpec filter mappings for filter
    946      * @param dispatches see {@link FilterMapping#setDispatches(int)}
    947      * @return The filter holder.
    948      */
    949     public FilterHolder addFilterWithMapping (String className,String pathSpec,EnumSet<DispatcherType> dispatches)
    950     {
    951         FilterHolder holder = newFilterHolder(Holder.Source.EMBEDDED);
    952         holder.setClassName(className);
    953 
    954         addFilterWithMapping(holder,pathSpec,dispatches);
    955         return holder;
    956     }
    957 
    958     /* ------------------------------------------------------------ */
    959     /** Convenience method to add a filter.
    960      * @param holder filter holder to add
    961      * @param pathSpec filter mappings for filter
    962      * @param dispatches see {@link FilterMapping#setDispatches(int)}
    963      */
    964     public void addFilterWithMapping (FilterHolder holder,String pathSpec,EnumSet<DispatcherType> dispatches)
    965     {
    966         FilterHolder[] holders = getFilters();
    967         if (holders!=null)
    968             holders = (FilterHolder[])holders.clone();
    969 
    970         try
    971         {
    972             setFilters((FilterHolder[])LazyList.addToArray(holders, holder, FilterHolder.class));
    973 
    974             FilterMapping mapping = new FilterMapping();
    975             mapping.setFilterName(holder.getName());
    976             mapping.setPathSpec(pathSpec);
    977             mapping.setDispatcherTypes(dispatches);
    978             //setFilterMappings((FilterMapping[])LazyList.addToArray(getFilterMappings(), mapping, FilterMapping.class));
    979             addFilterMapping(mapping);
    980 
    981         }
    982         catch (RuntimeException e)
    983         {
    984             setFilters(holders);
    985             throw e;
    986         }
    987         catch (Error e)
    988         {
    989             setFilters(holders);
    990             throw e;
    991         }
    992 
    993     }
    994 
    995     /* ------------------------------------------------------------ */
    996     /** Convenience method to add a filter.
    997      * @param filter  class of filter to create
    998      * @param pathSpec filter mappings for filter
    999      * @param dispatches see {@link FilterMapping#setDispatches(int)}
   1000      * @return The filter holder.
   1001      */
   1002     public FilterHolder addFilterWithMapping (Class<? extends Filter> filter,String pathSpec,int dispatches)
   1003     {
   1004         FilterHolder holder = newFilterHolder(Holder.Source.EMBEDDED);
   1005         holder.setHeldClass(filter);
   1006         addFilterWithMapping(holder,pathSpec,dispatches);
   1007 
   1008         return holder;
   1009     }
   1010 
   1011     /* ------------------------------------------------------------ */
   1012     /** Convenience method to add a filter.
   1013      * @param className of filter
   1014      * @param pathSpec filter mappings for filter
   1015      * @param dispatches see {@link FilterMapping#setDispatches(int)}
   1016      * @return The filter holder.
   1017      */
   1018     public FilterHolder addFilterWithMapping (String className,String pathSpec,int dispatches)
   1019     {
   1020         FilterHolder holder = newFilterHolder(Holder.Source.EMBEDDED);
   1021         holder.setClassName(className);
   1022 
   1023         addFilterWithMapping(holder,pathSpec,dispatches);
   1024         return holder;
   1025     }
   1026 
   1027     /* ------------------------------------------------------------ */
   1028     /** Convenience method to add a filter.
   1029      * @param holder filter holder to add
   1030      * @param pathSpec filter mappings for filter
   1031      * @param dispatches see {@link FilterMapping#setDispatches(int)}
   1032      */
   1033     public void addFilterWithMapping (FilterHolder holder,String pathSpec,int dispatches)
   1034     {
   1035         FilterHolder[] holders = getFilters();
   1036         if (holders!=null)
   1037             holders = (FilterHolder[])holders.clone();
   1038 
   1039         try
   1040         {
   1041             setFilters((FilterHolder[])LazyList.addToArray(holders, holder, FilterHolder.class));
   1042 
   1043             FilterMapping mapping = new FilterMapping();
   1044             mapping.setFilterName(holder.getName());
   1045             mapping.setPathSpec(pathSpec);
   1046             mapping.setDispatches(dispatches);
   1047             //setFilterMappings((FilterMapping[])LazyList.addToArray(getFilterMappings(), mapping, FilterMapping.class));
   1048             addFilterMapping(mapping);
   1049         }
   1050         catch (RuntimeException e)
   1051         {
   1052             setFilters(holders);
   1053             throw e;
   1054         }
   1055         catch (Error e)
   1056         {
   1057             setFilters(holders);
   1058             throw e;
   1059         }
   1060 
   1061     }
   1062 
   1063     /* ------------------------------------------------------------ */
   1064     /** Convenience method to add a filter with a mapping
   1065      * @param className
   1066      * @param pathSpec
   1067      * @param dispatches
   1068      * @return the filter holder created
   1069      * @deprecated use {@link #addFilterWithMapping(Class, String, EnumSet<DispatcherType>)} instead
   1070      */
   1071     public FilterHolder addFilter (String className,String pathSpec,EnumSet<DispatcherType> dispatches)
   1072     {
   1073         return addFilterWithMapping(className, pathSpec, dispatches);
   1074     }
   1075 
   1076     /* ------------------------------------------------------------ */
   1077     /**
   1078      * convenience method to add a filter and mapping
   1079      * @param filter
   1080      * @param filterMapping
   1081      */
   1082     public void addFilter (FilterHolder filter, FilterMapping filterMapping)
   1083     {
   1084         if (filter != null)
   1085             setFilters((FilterHolder[])LazyList.addToArray(getFilters(), filter, FilterHolder.class));
   1086         if (filterMapping != null)
   1087             //setFilterMappings((FilterMapping[])LazyList.addToArray(getFilterMappings(), filterMapping, FilterMapping.class));
   1088             addFilterMapping(filterMapping);
   1089     }
   1090 
   1091     /* ------------------------------------------------------------ */
   1092     /** Convenience method to add a preconstructed FilterHolder
   1093      * @param filter
   1094      */
   1095     public void addFilter (FilterHolder filter)
   1096     {
   1097         if (filter != null)
   1098             setFilters((FilterHolder[])LazyList.addToArray(getFilters(), filter, FilterHolder.class));
   1099     }
   1100 
   1101     /* ------------------------------------------------------------ */
   1102     /** Convenience method to add a preconstructed FilterMapping
   1103      * @param mapping
   1104      */
   1105     public void addFilterMapping (FilterMapping mapping)
   1106     {
   1107         if (mapping != null)
   1108         {
   1109             Source source = (mapping.getFilterHolder()==null?null:mapping.getFilterHolder().getSource());
   1110             FilterMapping[] mappings =getFilterMappings();
   1111             if (mappings==null || mappings.length==0)
   1112             {
   1113                 setFilterMappings(insertFilterMapping(mapping,0,false));
   1114                 if (source != null && source == Source.JAVAX_API)
   1115                     _matchAfterIndex = 0;
   1116             }
   1117             else
   1118             {
   1119                 //there are existing entries. If this is a programmatic filtermapping, it is added at the end of the list.
   1120                 //If this is a normal filtermapping, it is inserted after all the other filtermappings (matchBefores and normals),
   1121                 //but before the first matchAfter filtermapping.
   1122                 if (source != null && Source.JAVAX_API == source)
   1123                 {
   1124                     setFilterMappings(insertFilterMapping(mapping,mappings.length-1, false));
   1125                     if (_matchAfterIndex < 0)
   1126                         _matchAfterIndex = getFilterMappings().length-1;
   1127                 }
   1128                 else
   1129                 {
   1130                     //insert non-programmatic filter mappings before any matchAfters, if any
   1131                     if (_matchAfterIndex < 0)
   1132                         setFilterMappings(insertFilterMapping(mapping,mappings.length-1, false));
   1133                     else
   1134                     {
   1135                         FilterMapping[] new_mappings = insertFilterMapping(mapping, _matchAfterIndex, true);
   1136                         ++_matchAfterIndex;
   1137                         setFilterMappings(new_mappings);
   1138                     }
   1139                 }
   1140             }
   1141         }
   1142     }
   1143 
   1144 
   1145     /* ------------------------------------------------------------ */
   1146     /** Convenience method to add a preconstructed FilterMapping
   1147      * @param mapping
   1148      */
   1149     public void prependFilterMapping (FilterMapping mapping)
   1150     {
   1151         if (mapping != null)
   1152         {
   1153             Source source = mapping.getFilterHolder().getSource();
   1154 
   1155             FilterMapping[] mappings = getFilterMappings();
   1156             if (mappings==null || mappings.length==0)
   1157             {
   1158                 setFilterMappings(insertFilterMapping(mapping, 0, false));
   1159                 if (source != null && Source.JAVAX_API == source)
   1160                     _matchBeforeIndex = 0;
   1161             }
   1162             else
   1163             {
   1164                 if (source != null && Source.JAVAX_API == source)
   1165                 {
   1166                     //programmatically defined filter mappings are prepended to mapping list in the order
   1167                     //in which they were defined. In other words, insert this mapping at the tail of the
   1168                     //programmatically prepended filter mappings, BEFORE the first web.xml defined filter mapping.
   1169 
   1170                     if (_matchBeforeIndex < 0)
   1171                     {
   1172                         //no programmatically defined prepended filter mappings yet, prepend this one
   1173                         _matchBeforeIndex = 0;
   1174                         FilterMapping[] new_mappings = insertFilterMapping(mapping, 0, true);
   1175                         setFilterMappings(new_mappings);
   1176                     }
   1177                     else
   1178                     {
   1179                         FilterMapping[] new_mappings = insertFilterMapping(mapping,_matchBeforeIndex, false);
   1180                         ++_matchBeforeIndex;
   1181                         setFilterMappings(new_mappings);
   1182                     }
   1183                 }
   1184                 else
   1185                 {
   1186                     //non programmatically defined, just prepend to list
   1187                     FilterMapping[] new_mappings = insertFilterMapping(mapping, 0, true);
   1188                     setFilterMappings(new_mappings);
   1189                 }
   1190 
   1191                 //adjust matchAfterIndex ptr to take account of the mapping we just prepended
   1192                 if (_matchAfterIndex >= 0)
   1193                     ++_matchAfterIndex;
   1194             }
   1195         }
   1196     }
   1197 
   1198 
   1199 
   1200     /**
   1201      * Insert a filtermapping in the list
   1202      * @param mapping the FilterMapping to add
   1203      * @param pos the position in the existing arry at which to add it
   1204      * @param before if true, insert before  pos, if false insert after it
   1205      * @return
   1206      */
   1207     protected FilterMapping[] insertFilterMapping (FilterMapping mapping, int pos, boolean before)
   1208     {
   1209         if (pos < 0)
   1210             throw new IllegalArgumentException("FilterMapping insertion pos < 0");
   1211         FilterMapping[] mappings = getFilterMappings();
   1212 
   1213         if (mappings==null || mappings.length==0)
   1214         {
   1215             return new FilterMapping[] {mapping};
   1216         }
   1217         FilterMapping[] new_mappings = new FilterMapping[mappings.length+1];
   1218 
   1219 
   1220         if (before)
   1221         {
   1222             //copy existing filter mappings up to but not including the pos
   1223             System.arraycopy(mappings,0,new_mappings,0,pos);
   1224 
   1225             //add in the new mapping
   1226             new_mappings[pos] = mapping;
   1227 
   1228             //copy the old pos mapping and any remaining existing mappings
   1229             System.arraycopy(mappings,pos,new_mappings,pos+1, mappings.length-pos);
   1230 
   1231         }
   1232         else
   1233         {
   1234             //copy existing filter mappings up to and including the pos
   1235             System.arraycopy(mappings,0,new_mappings,0,pos+1);
   1236             //add in the new mapping after the pos
   1237             new_mappings[pos+1] = mapping;
   1238 
   1239             //copy the remaining existing mappings
   1240             if (mappings.length > pos+1)
   1241                 System.arraycopy(mappings,pos+1,new_mappings,pos+2, mappings.length-(pos+1));
   1242         }
   1243         return new_mappings;
   1244     }
   1245 
   1246 
   1247     /* ------------------------------------------------------------ */
   1248     protected synchronized void updateNameMappings()
   1249     {
   1250         // update filter name map
   1251         _filterNameMap.clear();
   1252         if (_filters!=null)
   1253         {
   1254             for (int i=0;i<_filters.length;i++)
   1255             {
   1256                 _filterNameMap.put(_filters[i].getName(),_filters[i]);
   1257                 _filters[i].setServletHandler(this);
   1258             }
   1259         }
   1260 
   1261         // Map servlet names to holders
   1262         _servletNameMap.clear();
   1263         if (_servlets!=null)
   1264         {
   1265             // update the maps
   1266             for (int i=0;i<_servlets.length;i++)
   1267             {
   1268                 _servletNameMap.put(_servlets[i].getName(),_servlets[i]);
   1269                 _servlets[i].setServletHandler(this);
   1270             }
   1271         }
   1272     }
   1273 
   1274     /* ------------------------------------------------------------ */
   1275     protected synchronized void updateMappings()
   1276     {
   1277         // update filter mappings
   1278         if (_filterMappings==null)
   1279         {
   1280             _filterPathMappings=null;
   1281             _filterNameMappings=null;
   1282         }
   1283         else
   1284         {
   1285             _filterPathMappings=new ArrayList();
   1286             _filterNameMappings=new MultiMap();
   1287             for (int i=0;i<_filterMappings.length;i++)
   1288             {
   1289                 FilterHolder filter_holder = (FilterHolder)_filterNameMap.get(_filterMappings[i].getFilterName());
   1290                 if (filter_holder==null)
   1291                     throw new IllegalStateException("No filter named "+_filterMappings[i].getFilterName());
   1292                 _filterMappings[i].setFilterHolder(filter_holder);
   1293                 if (_filterMappings[i].getPathSpecs()!=null)
   1294                     _filterPathMappings.add(_filterMappings[i]);
   1295 
   1296                 if (_filterMappings[i].getServletNames()!=null)
   1297                 {
   1298                     String[] names=_filterMappings[i].getServletNames();
   1299                     for (int j=0;j<names.length;j++)
   1300                     {
   1301                         if (names[j]!=null)
   1302                             _filterNameMappings.add(names[j], _filterMappings[i]);
   1303                     }
   1304                 }
   1305             }
   1306         }
   1307 
   1308         // Map servlet paths to holders
   1309         if (_servletMappings==null || _servletNameMap==null)
   1310         {
   1311             _servletPathMap=null;
   1312         }
   1313         else
   1314         {
   1315             PathMap pm = new PathMap();
   1316 
   1317             // update the maps
   1318             for (int i=0;i<_servletMappings.length;i++)
   1319             {
   1320                 ServletHolder servlet_holder = (ServletHolder)_servletNameMap.get(_servletMappings[i].getServletName());
   1321                 if (servlet_holder==null)
   1322                     throw new IllegalStateException("No such servlet: "+_servletMappings[i].getServletName());
   1323                 else if (servlet_holder.isEnabled() && _servletMappings[i].getPathSpecs()!=null)
   1324                 {
   1325                     String[] pathSpecs = _servletMappings[i].getPathSpecs();
   1326                     for (int j=0;j<pathSpecs.length;j++)
   1327                         if (pathSpecs[j]!=null)
   1328                             pm.put(pathSpecs[j],servlet_holder);
   1329                 }
   1330             }
   1331 
   1332             _servletPathMap=pm;
   1333         }
   1334 
   1335         // flush filter chain cache
   1336         if (_chainCache!=null)
   1337         {
   1338             for (int i=_chainCache.length;i-->0;)
   1339             {
   1340                 if (_chainCache[i]!=null)
   1341                     _chainCache[i].clear();
   1342             }
   1343         }
   1344 
   1345         if (LOG.isDebugEnabled())
   1346         {
   1347             LOG.debug("filterNameMap="+_filterNameMap);
   1348             LOG.debug("pathFilters="+_filterPathMappings);
   1349             LOG.debug("servletFilterMap="+_filterNameMappings);
   1350             LOG.debug("servletPathMap="+_servletPathMap);
   1351             LOG.debug("servletNameMap="+_servletNameMap);
   1352         }
   1353 
   1354         try
   1355         {
   1356             if (_contextHandler!=null && _contextHandler.isStarted() || _contextHandler==null && isStarted())
   1357                 initialize();
   1358         }
   1359         catch (Exception e)
   1360         {
   1361             throw new RuntimeException(e);
   1362         }
   1363     }
   1364 
   1365     /* ------------------------------------------------------------ */
   1366     protected void notFound(HttpServletRequest request,
   1367                   HttpServletResponse response)
   1368         throws IOException
   1369     {
   1370         if(LOG.isDebugEnabled())
   1371             LOG.debug("Not Found "+request.getRequestURI());
   1372         //Override to send an error back, eg with: response.sendError(HttpServletResponse.SC_NOT_FOUND);
   1373     }
   1374 
   1375     /* ------------------------------------------------------------ */
   1376     /**
   1377      * @param filterChainsCached The filterChainsCached to set.
   1378      */
   1379     public void setFilterChainsCached(boolean filterChainsCached)
   1380     {
   1381         _filterChainsCached = filterChainsCached;
   1382     }
   1383 
   1384     /* ------------------------------------------------------------ */
   1385     /**
   1386      * @param filterMappings The filterMappings to set.
   1387      */
   1388     public void setFilterMappings(FilterMapping[] filterMappings)
   1389     {
   1390         if (getServer()!=null)
   1391             getServer().getContainer().update(this,_filterMappings,filterMappings,"filterMapping",true);
   1392         _filterMappings = filterMappings;
   1393         updateMappings();
   1394         invalidateChainsCache();
   1395     }
   1396 
   1397     /* ------------------------------------------------------------ */
   1398     public synchronized void setFilters(FilterHolder[] holders)
   1399     {
   1400         if (getServer()!=null)
   1401             getServer().getContainer().update(this,_filters,holders,"filter",true);
   1402         _filters=holders;
   1403         updateNameMappings();
   1404         invalidateChainsCache();
   1405     }
   1406 
   1407     /* ------------------------------------------------------------ */
   1408     /**
   1409      * @param servletMappings The servletMappings to set.
   1410      */
   1411     public void setServletMappings(ServletMapping[] servletMappings)
   1412     {
   1413         if (getServer()!=null)
   1414             getServer().getContainer().update(this,_servletMappings,servletMappings,"servletMapping",true);
   1415         _servletMappings = servletMappings;
   1416         updateMappings();
   1417         invalidateChainsCache();
   1418     }
   1419 
   1420     /* ------------------------------------------------------------ */
   1421     /** Set Servlets.
   1422      * @param holders Array of servletsto define
   1423      */
   1424     public synchronized void setServlets(ServletHolder[] holders)
   1425     {
   1426         if (getServer()!=null)
   1427             getServer().getContainer().update(this,_servlets,holders,"servlet",true);
   1428         _servlets=holders;
   1429         updateNameMappings();
   1430         invalidateChainsCache();
   1431     }
   1432 
   1433     /* ------------------------------------------------------------ */
   1434     /* ------------------------------------------------------------ */
   1435     private class CachedChain implements FilterChain
   1436     {
   1437         FilterHolder _filterHolder;
   1438         CachedChain _next;
   1439         ServletHolder _servletHolder;
   1440 
   1441         /* ------------------------------------------------------------ */
   1442         CachedChain(Object filters, ServletHolder servletHolder)
   1443         {
   1444             if (LazyList.size(filters)>0)
   1445             {
   1446                 _filterHolder=(FilterHolder)LazyList.get(filters, 0);
   1447                 filters=LazyList.remove(filters,0);
   1448                 _next=new CachedChain(filters,servletHolder);
   1449             }
   1450             else
   1451                 _servletHolder=servletHolder;
   1452         }
   1453 
   1454         /* ------------------------------------------------------------ */
   1455         public void doFilter(ServletRequest request, ServletResponse response)
   1456             throws IOException, ServletException
   1457         {
   1458             final Request baseRequest=(request instanceof Request)?((Request)request):AbstractHttpConnection.getCurrentConnection().getRequest();
   1459 
   1460             // pass to next filter
   1461             if (_filterHolder!=null)
   1462             {
   1463                 if (LOG.isDebugEnabled())
   1464                     LOG.debug("call filter " + _filterHolder);
   1465                 Filter filter= _filterHolder.getFilter();
   1466                 if (_filterHolder.isAsyncSupported())
   1467                     filter.doFilter(request, response, _next);
   1468                 else
   1469                 {
   1470                     final boolean suspendable=baseRequest.isAsyncSupported();
   1471                     if (suspendable)
   1472                     {
   1473                         try
   1474                         {
   1475                             baseRequest.setAsyncSupported(false);
   1476                             filter.doFilter(request, response, _next);
   1477                         }
   1478                         finally
   1479                         {
   1480                             baseRequest.setAsyncSupported(true);
   1481                         }
   1482                     }
   1483                     else
   1484                         filter.doFilter(request, response, _next);
   1485                 }
   1486                 return;
   1487             }
   1488 
   1489             // Call servlet
   1490 
   1491             HttpServletRequest srequest = (HttpServletRequest)request;
   1492             if (_servletHolder != null)
   1493             {
   1494                 if (LOG.isDebugEnabled())
   1495                     LOG.debug("call servlet " + _servletHolder);
   1496                 _servletHolder.handle(baseRequest,request, response);
   1497             }
   1498             else if (getHandler()==null)
   1499                 notFound(srequest, (HttpServletResponse)response);
   1500             else
   1501                 nextHandle(URIUtil.addPaths(srequest.getServletPath(),srequest.getPathInfo()),
   1502                            baseRequest,srequest,(HttpServletResponse)response);
   1503 
   1504         }
   1505 
   1506         public String toString()
   1507         {
   1508             if (_filterHolder!=null)
   1509                 return _filterHolder+"->"+_next.toString();
   1510             if (_servletHolder!=null)
   1511                 return _servletHolder.toString();
   1512             return "null";
   1513         }
   1514     }
   1515 
   1516     /* ------------------------------------------------------------ */
   1517     /* ------------------------------------------------------------ */
   1518     private class Chain implements FilterChain
   1519     {
   1520         final Request _baseRequest;
   1521         final Object _chain;
   1522         final ServletHolder _servletHolder;
   1523         int _filter= 0;
   1524 
   1525         /* ------------------------------------------------------------ */
   1526         Chain(Request baseRequest, Object filters, ServletHolder servletHolder)
   1527         {
   1528             _baseRequest=baseRequest;
   1529             _chain= filters;
   1530             _servletHolder= servletHolder;
   1531         }
   1532 
   1533         /* ------------------------------------------------------------ */
   1534         public void doFilter(ServletRequest request, ServletResponse response)
   1535             throws IOException, ServletException
   1536         {
   1537             if (LOG.isDebugEnabled())
   1538                 LOG.debug("doFilter " + _filter);
   1539 
   1540             // pass to next filter
   1541             if (_filter < LazyList.size(_chain))
   1542             {
   1543                 FilterHolder holder= (FilterHolder)LazyList.get(_chain, _filter++);
   1544                 if (LOG.isDebugEnabled())
   1545                     LOG.debug("call filter " + holder);
   1546                 Filter filter= holder.getFilter();
   1547 
   1548                 if (holder.isAsyncSupported() || !_baseRequest.isAsyncSupported())
   1549                 {
   1550                     filter.doFilter(request, response, this);
   1551                 }
   1552                 else
   1553                 {
   1554                     try
   1555                     {
   1556                         _baseRequest.setAsyncSupported(false);
   1557                         filter.doFilter(request, response, this);
   1558                     }
   1559                     finally
   1560                     {
   1561                         _baseRequest.setAsyncSupported(true);
   1562                     }
   1563                 }
   1564 
   1565                 return;
   1566             }
   1567 
   1568             // Call servlet
   1569             HttpServletRequest srequest = (HttpServletRequest)request;
   1570             if (_servletHolder != null)
   1571             {
   1572                 if (LOG.isDebugEnabled())
   1573                     LOG.debug("call servlet " + _servletHolder);
   1574                 _servletHolder.handle(_baseRequest,request, response);
   1575             }
   1576             else if (getHandler()==null)
   1577                 notFound(srequest, (HttpServletResponse)response);
   1578             else
   1579             {
   1580                 Request baseRequest=(request instanceof Request)?((Request)request):AbstractHttpConnection.getCurrentConnection().getRequest();
   1581                 nextHandle(URIUtil.addPaths(srequest.getServletPath(),srequest.getPathInfo()),
   1582                            baseRequest,srequest,(HttpServletResponse)response);
   1583             }
   1584         }
   1585 
   1586         /* ------------------------------------------------------------ */
   1587         public String toString()
   1588         {
   1589             StringBuilder b = new StringBuilder();
   1590             for (int i=0; i<LazyList.size(_chain);i++)
   1591             {
   1592                 Object o=LazyList.get(_chain, i);
   1593                 b.append(o.toString());
   1594                 b.append("->");
   1595             }
   1596             b.append(_servletHolder);
   1597             return b.toString();
   1598         }
   1599     }
   1600 
   1601     /* ------------------------------------------------------------ */
   1602     /**
   1603      * @return The maximum entries in a filter chain cache.
   1604      */
   1605     public int getMaxFilterChainsCacheSize()
   1606     {
   1607         return _maxFilterChainsCacheSize;
   1608     }
   1609 
   1610     /* ------------------------------------------------------------ */
   1611     /** Set the maximum filter chain cache size.
   1612      * Filter chains are cached if {@link #isFilterChainsCached()} is true. If the max cache size
   1613      * is greater than zero, then the cache is flushed whenever it grows to be this size.
   1614      *
   1615      * @param maxFilterChainsCacheSize  the maximum number of entries in a filter chain cache.
   1616      */
   1617     public void setMaxFilterChainsCacheSize(int maxFilterChainsCacheSize)
   1618     {
   1619         _maxFilterChainsCacheSize = maxFilterChainsCacheSize;
   1620     }
   1621 
   1622     /* ------------------------------------------------------------ */
   1623     void destroyServlet(Servlet servlet)
   1624     {
   1625         if (_contextHandler!=null)
   1626             _contextHandler.destroyServlet(servlet);
   1627     }
   1628 
   1629     /* ------------------------------------------------------------ */
   1630     void destroyFilter(Filter filter)
   1631     {
   1632         if (_contextHandler!=null)
   1633             _contextHandler.destroyFilter(filter);
   1634     }
   1635 
   1636     /* ------------------------------------------------------------ */
   1637     @Override
   1638     public void dump(Appendable out,String indent) throws IOException
   1639     {
   1640         super.dumpThis(out);
   1641         dump(out,indent,
   1642                 TypeUtil.asList(getHandlers()),
   1643                 getBeans(),
   1644                 TypeUtil.asList(getFilterMappings()),
   1645                 TypeUtil.asList(getFilters()),
   1646                 TypeUtil.asList(getServletMappings()),
   1647                 TypeUtil.asList(getServlets()));
   1648     }
   1649 }
   1650