Source code: org/mortbay/jetty/servlet/WebApplicationHandler.java
1 // ===========================================================================
2 // Copyright (c) 1996 Mort Bay Consulting Pty. Ltd. All rights reserved.
3 // $Id: WebApplicationHandler.java,v 1.30 2003/10/12 11:58:33 gregwilkins Exp $
4 // ---------------------------------------------------------------------------
5
6 package org.mortbay.jetty.servlet;
7
8 import java.io.IOException;
9 import java.util.ArrayList;
10 import java.util.EventListener;
11 import java.util.HashMap;
12 import java.util.Iterator;
13 import java.util.List;
14 import java.util.Map;
15
16 import javax.servlet.Filter;
17 import javax.servlet.FilterChain;
18 import javax.servlet.ServletException;
19 import javax.servlet.ServletRequest;
20 import javax.servlet.ServletRequestAttributeListener;
21 import javax.servlet.ServletRequestListener;
22 import javax.servlet.ServletResponse;
23 import javax.servlet.UnavailableException;
24 import javax.servlet.http.HttpServletRequest;
25 import javax.servlet.http.HttpServletResponse;
26 import javax.servlet.http.HttpSessionActivationListener;
27 import javax.servlet.http.HttpSessionAttributeListener;
28 import javax.servlet.http.HttpSessionBindingListener;
29 import javax.servlet.http.HttpSessionListener;
30
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogFactory;
33 import org.mortbay.http.HttpContext;
34 import org.mortbay.http.HttpResponse;
35 import org.mortbay.util.LazyList;
36 import org.mortbay.util.MultiException;
37 import org.mortbay.util.MultiMap;
38 import org.mortbay.util.StringUtil;
39 import org.mortbay.util.TypeUtil;
40 import org.mortbay.util.LogSupport;
41
42 /* --------------------------------------------------------------------- */
43 /** WebApp HttpHandler.
44 * This handler extends the ServletHandler with security, filter and resource
45 * capabilities to provide full J2EE web container support.
46 * <p>
47 * @since Jetty 4.1
48 * @see org.mortbay.jetty.servlet.WebApplicationContext
49 * @version $Id: WebApplicationHandler.java,v 1.30 2003/10/12 11:58:33 gregwilkins Exp $
50 * @author Greg Wilkins
51 */
52 public class WebApplicationHandler extends ServletHandler
53 {
54 private static Log log= LogFactory.getLog(WebApplicationHandler.class);
55
56 private Map _filterMap= new HashMap();
57 private List _pathFilters= new ArrayList();
58 private List _filters= new ArrayList();
59 private MultiMap _servletFilterMap= new MultiMap();
60 private boolean _acceptRanges= true;
61
62 private transient boolean _started= false;
63 private transient WebApplicationContext _webApplicationContext;
64
65 protected transient Object _requestListeners;
66 protected transient Object _requestAttributeListeners;
67 protected transient Object _sessionListeners;
68
69 /* ------------------------------------------------------------ */
70 public boolean isAcceptRanges()
71 {
72 return _acceptRanges;
73 }
74
75 /* ------------------------------------------------------------ */
76 /** Set if the handler accepts range requests.
77 * Default is false;
78 * @param ar True if the handler should accept ranges
79 */
80 public void setAcceptRanges(boolean ar)
81 {
82 _acceptRanges= ar;
83 }
84
85 /* ------------------------------------------------------------ */
86 public FilterHolder defineFilter(String name, String className)
87 {
88 FilterHolder holder= new FilterHolder(this, name, className);
89 _filterMap.put(holder.getName(), holder);
90 _filters.add(holder);
91 return holder;
92 }
93
94 /* ------------------------------------------------------------ */
95 public FilterHolder getFilter(String name)
96 {
97 return (FilterHolder)_filterMap.get(name);
98 }
99
100 /* ------------------------------------------------------------ */
101 public FilterHolder mapServletToFilter(String servletName, String filterName)
102 {
103 FilterHolder holder= (FilterHolder)_filterMap.get(filterName);
104 if (holder == null)
105 throw new IllegalArgumentException("Unknown filter :" + filterName);
106 if (log.isDebugEnabled())
107 log.debug("Filter servlet " + servletName + " --> " + filterName);
108 _servletFilterMap.add(servletName, holder);
109 holder.addServlet(servletName);
110 return holder;
111 }
112
113 /* ------------------------------------------------------------ */
114 public List getFilters()
115 {
116 return _filters;
117 }
118
119 /* ------------------------------------------------------------ */
120 public FilterHolder mapPathToFilter(String pathSpec, String filterName)
121 {
122 FilterHolder holder= (FilterHolder)_filterMap.get(filterName);
123 if (holder == null)
124 throw new IllegalArgumentException("Unknown filter :" + filterName);
125
126 if (log.isDebugEnabled())
127 log.debug("Filter path " + pathSpec + " --> " + filterName);
128
129 if (!holder.isMappedToPath())
130 _pathFilters.add(holder);
131 holder.addPathSpec(pathSpec);
132
133 return holder;
134 }
135
136 /* ------------------------------------------------------------ */
137 public synchronized void addEventListener(EventListener listener)
138 throws IllegalArgumentException
139 {
140 boolean known= false;
141
142 if ((listener instanceof HttpSessionActivationListener)
143 || (listener instanceof HttpSessionAttributeListener)
144 || (listener instanceof HttpSessionBindingListener)
145 || (listener instanceof HttpSessionListener))
146 {
147 if (_sessionManager != null)
148 _sessionManager.addEventListener(listener);
149 _sessionListeners= LazyList.add(_sessionListeners, listener);
150 known= true;
151 }
152
153 if (listener instanceof ServletRequestListener)
154 {
155 known= true;
156 _requestListeners= LazyList.add(_requestListeners, listener);
157 }
158
159 if (listener instanceof ServletRequestAttributeListener)
160 {
161 known= true;
162 _requestAttributeListeners= LazyList.add(_requestAttributeListeners, listener);
163 }
164
165 if (!known)
166 throw new IllegalArgumentException(listener.toString());
167 }
168
169 /* ------------------------------------------------------------ */
170 public synchronized void removeEventListener(EventListener listener)
171 {
172 if (_sessionManager != null)
173 _sessionManager.removeEventListener(listener);
174
175 _sessionListeners= LazyList.remove(_sessionListeners, listener);
176 _requestListeners= LazyList.remove(_requestListeners, listener);
177 _requestAttributeListeners= LazyList.remove(_requestAttributeListeners, listener);
178 }
179
180 /* ------------------------------------------------------------ */
181 public void setSessionManager(SessionManager sm)
182 {
183 if (isStarted())
184 throw new IllegalStateException("Started");
185
186 SessionManager old= getSessionManager();
187
188 int mii= 0;
189 boolean setMii= false;
190
191 if (getHttpContext() != null)
192 {
193 // recover config and remove listeners from old session manager
194 if (old != null && old != sm)
195 {
196 old.initialize(null);
197 if (_sessionListeners != null)
198 {
199 for (Iterator i= LazyList.iterator(_sessionListeners); i.hasNext();)
200 {
201 EventListener listener= (EventListener)i.next();
202 _sessionManager.removeEventListener(listener);
203 }
204 }
205 mii= _sessionManager.getMaxInactiveInterval();
206 setMii= true;
207 }
208
209 // Set listeners and config on new listener.
210 if (sm != null && sm != sm)
211 {
212 if (_sessionListeners != null)
213 {
214 for (Iterator i= LazyList.iterator(_sessionListeners); i.hasNext();)
215 {
216 EventListener listener= (EventListener)i.next();
217 sm.addEventListener(listener);
218 }
219 }
220 sm.initialize(this);
221 if (setMii)
222 sm.setMaxInactiveInterval(mii);
223 }
224 }
225
226 super.setSessionManager(sm);
227 }
228
229 /* ------------------------------------------------------------ */
230 public boolean isStarted()
231 {
232 return _started && super.isStarted();
233 }
234
235 /* ----------------------------------------------------------------- */
236 public synchronized void start() throws Exception
237 {
238 // Start Servlet Handler
239 super.start();
240 if (log.isDebugEnabled())
241 log.debug("Path Filters: " + _pathFilters);
242 if (log.isDebugEnabled())
243 log.debug("Servlet Filters: " + _servletFilterMap);
244 _started= true;
245 if (getHttpContext() instanceof WebApplicationContext)
246 _webApplicationContext= (WebApplicationContext)getHttpContext();
247
248 if (LazyList.size(_requestAttributeListeners) > 0 || LazyList.size(_requestListeners) > 0)
249 {
250 FilterHolder holder=
251 new FilterHolder(
252 this,
253 "RequestAttributeListener",
254 "org.mortbay.jetty.servlet.RequestListenerFilter");
255 holder.addAppliesTo(FilterHolder.__ALL);
256 holder.addPathSpec("/");
257 holder.start();
258 RequestListenerFilter filter= (RequestListenerFilter)holder.getFilter();
259 filter.setRequestAttributeListeners(_requestAttributeListeners);
260 filter.setRequestListeners(_requestListeners);
261 _pathFilters.add(0, holder);
262 }
263 }
264
265 /* ------------------------------------------------------------ */
266 public void initializeServlets() throws Exception
267 {
268 // initialize Filters
269 MultiException mex= new MultiException();
270 Iterator iter= _filters.iterator();
271 while (iter.hasNext())
272 {
273 FilterHolder holder= (FilterHolder)iter.next();
274 try
275 {
276 holder.start();
277 }
278 catch (Exception e)
279 {
280 mex.add(e);
281 }
282 }
283
284 // initialize Servlets
285 try
286 {
287 super.initializeServlets();
288 }
289 catch (Exception e)
290 {
291 mex.add(e);
292 }
293
294 mex.ifExceptionThrow();
295 }
296
297 /* ------------------------------------------------------------ */
298 public synchronized void stop() throws InterruptedException
299 {
300 try
301 {
302 // Stop servlets
303 super.stop();
304
305 // Stop filters
306 for (int i= _filters.size(); i-- > 0;)
307 {
308 FilterHolder holder= (FilterHolder)_filters.get(i);
309 holder.stop();
310 }
311 }
312 finally
313 {
314 _started= false;
315 _webApplicationContext= null;
316 _sessionListeners= null;
317 _requestListeners= null;
318 _requestAttributeListeners= null;
319 }
320 }
321
322 /* ------------------------------------------------------------ */
323 protected String getErrorPage(int status, ServletHttpRequest request)
324 {
325 String error_page= null;
326 Class exClass= (Class)request.getAttribute(ServletHandler.__J_S_ERROR_EXCEPTION_TYPE);
327
328 if (ServletException.class.equals(exClass))
329 {
330 error_page= _webApplicationContext.getErrorPage(exClass.getName());
331 if (error_page == null)
332 {
333 Throwable th= (Throwable)request.getAttribute(ServletHandler.__J_S_ERROR_EXCEPTION);
334 while (th instanceof ServletException)
335 th= ((ServletException)th).getRootCause();
336 if (th != null)
337 exClass= th.getClass();
338 }
339 }
340
341 if (error_page == null && exClass != null)
342 {
343 while (error_page == null && exClass != null && _webApplicationContext != null)
344 {
345 error_page= _webApplicationContext.getErrorPage(exClass.getName());
346 exClass= exClass.getSuperclass();
347 }
348
349 if (error_page == null)
350 {}
351 }
352
353 if (error_page == null && _webApplicationContext != null)
354 error_page= _webApplicationContext.getErrorPage(TypeUtil.toString(status));
355
356 return error_page;
357 }
358
359 /* ------------------------------------------------------------ */
360 protected void dispatch(
361 String pathInContext,
362 HttpServletRequest request,
363 HttpServletResponse response,
364 ServletHolder servletHolder)
365 throws ServletException, UnavailableException, IOException
366 {
367 // Determine request type.
368 int requestType= 0;
369
370 if (request instanceof Dispatcher.DispatcherRequest)
371 {
372 // Handle dispatch to j_security_check
373 HttpContext context= getHttpContext();
374 if (context != null
375 && context instanceof ServletHttpContext
376 && pathInContext != null
377 && pathInContext.endsWith(FormAuthenticator.__J_SECURITY_CHECK))
378 {
379 ServletHttpRequest servletHttpRequest= (ServletHttpRequest)request;
380 ServletHttpResponse servletHttpResponse= (ServletHttpResponse)response;
381 ServletHttpContext servletContext= (ServletHttpContext)context;
382
383 if (!servletContext
384 .jSecurityCheck(
385 pathInContext,
386 servletHttpRequest.getHttpRequest(),
387 servletHttpResponse.getHttpResponse()))
388 return;
389 }
390
391 // Forward or include
392 requestType= ((Dispatcher.DispatcherRequest)request).getFilterType();
393 if (requestType == FilterHolder.__FORWARD)
394 {
395 // Error
396 requestType= FilterHolder.__ERROR;
397 }
398 }
399 else
400 {
401 // Error or request
402 ServletHttpRequest servletHttpRequest= (ServletHttpRequest)request;
403 ServletHttpResponse servletHttpResponse= (ServletHttpResponse)response;
404 HttpResponse httpResponse= servletHttpResponse.getHttpResponse();
405
406 // Request
407 requestType= FilterHolder.__REQUEST;
408 // protect web-inf and meta-inf
409 if (StringUtil.startsWithIgnoreCase(pathInContext, "/web-inf")
410 || StringUtil.startsWithIgnoreCase(pathInContext, "/meta-inf"))
411 {
412 response.sendError(HttpResponse.__404_Not_Found);
413 return;
414 }
415
416 // Security Check
417 if (!getHttpContext()
418 .checkSecurityConstraints(
419 pathInContext,
420 servletHttpRequest.getHttpRequest(),
421 httpResponse))
422 return;
423 }
424
425 // Build list of filters
426 Object filters= null;
427
428 // Path filters
429 if (pathInContext != null && _pathFilters.size() > 0)
430 {
431 for (int i= 0; i < _pathFilters.size(); i++)
432 {
433 FilterHolder holder= (FilterHolder)_pathFilters.get(i);
434 if (holder.appliesTo(pathInContext, requestType))
435 filters= LazyList.add(filters, holder);
436 }
437 }
438
439 // Servlet filters
440 if (servletHolder != null && _servletFilterMap.size() > 0)
441 {
442 Object o= _servletFilterMap.get(servletHolder.getName());
443 if (o != null)
444 {
445 if (o instanceof List)
446 {
447 List list= (List)o;
448 for (int i= 0; i < list.size(); i++)
449 {
450 FilterHolder holder= (FilterHolder)list.get(i);
451 if (holder.appliesTo(requestType))
452 filters= LazyList.add(filters, holder);
453 }
454 }
455 else
456 {
457 FilterHolder holder= (FilterHolder)o;
458 if (holder.appliesTo(requestType))
459 filters= LazyList.add(filters, holder);
460 }
461 }
462 }
463
464 // Do the handling thang
465 if (LazyList.size(filters) > 0)
466 {
467 Chain chain= new Chain(pathInContext, filters, servletHolder);
468 chain.doFilter(request, response);
469 }
470 else
471 {
472 // Call servlet
473 if (servletHolder != null)
474 {
475 if (LogSupport.isTraceEnabled(log))
476 log.trace("call servlet " + servletHolder);
477 servletHolder.handle(request, response);
478 }
479 else // Not found
480 notFound(request, response);
481 }
482 }
483
484 /* ------------------------------------------------------------ */
485 /* ------------------------------------------------------------ */
486 /* ------------------------------------------------------------ */
487 private class Chain implements FilterChain
488 {
489 String _pathInContext;
490 int _filter= 0;
491 Object _filters;
492 ServletHolder _servletHolder;
493
494 /* ------------------------------------------------------------ */
495 Chain(String pathInContext, Object filters, ServletHolder servletHolder)
496 {
497 _pathInContext= pathInContext;
498 _filters= filters;
499 _servletHolder= servletHolder;
500 }
501
502 /* ------------------------------------------------------------ */
503 public void doFilter(ServletRequest request, ServletResponse response)
504 throws IOException, ServletException
505 {
506 if (LogSupport.isTraceEnabled(log))
507 log.trace("doFilter " + _filter);
508
509 // pass to next filter
510 if (_filter < LazyList.size(_filters))
511 {
512 FilterHolder holder= (FilterHolder)LazyList.get(_filters, _filter++);
513 if (LogSupport.isTraceEnabled(log))
514 log.trace("call filter " + holder);
515 Filter filter= holder.getFilter();
516 filter.doFilter(request, response, this);
517 return;
518 }
519
520 // Call servlet
521 if (_servletHolder != null)
522 {
523 if (LogSupport.isTraceEnabled(log))
524 log.trace("call servlet " + _servletHolder);
525 _servletHolder.handle(request, response);
526 }
527 else // Not found
528 notFound((HttpServletRequest)request, (HttpServletResponse)response);
529 }
530 }
531 }