blob: 53da17a3555cea343bf7ba7cfb402726ddde2fcf [file] [log] [blame]
Jake Slack03928ae2014-05-13 18:41:56 -07001//
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
19package org.eclipse.jetty.servlet;
20
21import java.io.IOException;
22import java.util.ArrayList;
23import java.util.Arrays;
24import java.util.Collections;
25import java.util.EnumSet;
26import java.util.HashMap;
27import java.util.HashSet;
28import java.util.ListIterator;
29import java.util.Set;
30import java.util.List;
31import java.util.Map;
32import java.util.Queue;
33import java.util.concurrent.ConcurrentHashMap;
34import java.util.concurrent.ConcurrentLinkedQueue;
35import java.util.concurrent.ConcurrentMap;
36
37import javax.servlet.AsyncContext;
38import javax.servlet.DispatcherType;
39import javax.servlet.Filter;
40import javax.servlet.FilterChain;
41import javax.servlet.RequestDispatcher;
42import javax.servlet.Servlet;
43import javax.servlet.ServletContext;
44import javax.servlet.ServletException;
45import javax.servlet.ServletRegistration;
46import javax.servlet.ServletRequest;
47import javax.servlet.ServletResponse;
48import javax.servlet.ServletSecurityElement;
49import javax.servlet.UnavailableException;
50import javax.servlet.http.HttpServletRequest;
51import javax.servlet.http.HttpServletResponse;
52
53import org.eclipse.jetty.continuation.ContinuationThrowable;
54import org.eclipse.jetty.http.HttpException;
55import org.eclipse.jetty.http.PathMap;
56import org.eclipse.jetty.io.EofException;
57import org.eclipse.jetty.io.RuntimeIOException;
58import org.eclipse.jetty.security.IdentityService;
59import org.eclipse.jetty.security.SecurityHandler;
60import org.eclipse.jetty.server.AbstractHttpConnection;
61import org.eclipse.jetty.server.AsyncContinuation;
62import org.eclipse.jetty.server.Dispatcher;
63import org.eclipse.jetty.server.AbstractHttpConnection;
64import org.eclipse.jetty.server.Request;
65import org.eclipse.jetty.server.Server;
66import org.eclipse.jetty.server.ServletRequestHttpWrapper;
67import org.eclipse.jetty.server.ServletResponseHttpWrapper;
68import org.eclipse.jetty.server.UserIdentity;
69import org.eclipse.jetty.server.handler.ContextHandler;
70import org.eclipse.jetty.server.handler.ScopedHandler;
71import org.eclipse.jetty.servlet.Holder.Source;
72import org.eclipse.jetty.util.LazyList;
73import org.eclipse.jetty.util.MultiException;
74import org.eclipse.jetty.util.MultiMap;
75import org.eclipse.jetty.util.TypeUtil;
76import org.eclipse.jetty.util.URIUtil;
77import org.eclipse.jetty.util.log.Log;
78import 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 */
92public 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}