1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.mortbay.jetty.servlet;
16
17 import java.io.IOException;
18 import java.security.Principal;
19 import java.util.Enumeration;
20 import java.util.HashMap;
21 import java.util.Map;
22 import java.util.Stack;
23
24 import javax.servlet.Servlet;
25 import javax.servlet.ServletConfig;
26 import javax.servlet.ServletContext;
27 import javax.servlet.ServletException;
28 import javax.servlet.ServletRequest;
29 import javax.servlet.ServletResponse;
30 import javax.servlet.SingleThreadModel;
31 import javax.servlet.UnavailableException;
32
33 import org.mortbay.jetty.HttpConnection;
34 import org.mortbay.jetty.Request;
35 import org.mortbay.jetty.handler.ContextHandler;
36 import org.mortbay.jetty.security.SecurityHandler;
37 import org.mortbay.jetty.security.UserRealm;
38 import org.mortbay.log.Log;
39
40
41
42
43
44
45
46
47
48
49
50
51 public class ServletHolder extends Holder
52 implements Comparable
53 {
54
55 private int _initOrder;
56 private boolean _initOnStartup=false;
57 private Map _roleMap;
58 private String _forcedPath;
59 private String _runAs;
60 private UserRealm _realm;
61
62 private transient Servlet _servlet;
63 private transient Config _config;
64 private transient long _unavailable;
65 private transient UnavailableException _unavailableEx;
66
67
68
69
70
71 public ServletHolder()
72 {}
73
74
75
76
77 public ServletHolder(Servlet servlet)
78 {
79 setServlet(servlet);
80 }
81
82
83
84
85 public ServletHolder(Class servlet)
86 {
87 super(servlet);
88 }
89
90
91
92
93
94 public UnavailableException getUnavailableException()
95 {
96 return _unavailableEx;
97 }
98
99
100 public synchronized void setServlet(Servlet servlet)
101 {
102 if (servlet==null || servlet instanceof SingleThreadModel)
103 throw new IllegalArgumentException();
104
105 _extInstance=true;
106 _servlet=servlet;
107 setHeldClass(servlet.getClass());
108 if (getName()==null)
109 setName(servlet.getClass().getName()+"-"+super.hashCode());
110 }
111
112
113 public int getInitOrder()
114 {
115 return _initOrder;
116 }
117
118
119
120
121
122
123
124 public void setInitOrder(int order)
125 {
126 _initOnStartup=true;
127 _initOrder = order;
128 }
129
130
131
132
133 public int compareTo(Object o)
134 {
135 if (o instanceof ServletHolder)
136 {
137 ServletHolder sh= (ServletHolder)o;
138 if (sh==this)
139 return 0;
140 if (sh._initOrder<_initOrder)
141 return 1;
142 if (sh._initOrder>_initOrder)
143 return -1;
144
145 int c=(_className!=null && sh._className!=null)?_className.compareTo(sh._className):0;
146 if (c==0)
147 c=_name.compareTo(sh._name);
148 if (c==0)
149 c=this.hashCode()>o.hashCode()?1:-1;
150 return c;
151 }
152 return 1;
153 }
154
155
156 public boolean equals(Object o)
157 {
158 return compareTo(o)==0;
159 }
160
161
162 public int hashCode()
163 {
164 return _name==null?System.identityHashCode(this):_name.hashCode();
165 }
166
167
168
169
170
171
172
173
174 public synchronized void setUserRoleLink(String name,String link)
175 {
176 if (_roleMap==null)
177 _roleMap=new HashMap();
178 _roleMap.put(name,link);
179 }
180
181
182
183
184
185
186
187 public String getUserRoleLink(String name)
188 {
189 if (_roleMap==null)
190 return name;
191 String link=(String)_roleMap.get(name);
192 return (link==null)?name:link;
193 }
194
195
196 public Map getRoleMap()
197 {
198 return _roleMap;
199 }
200
201
202
203
204
205
206 public void setRunAs(String role)
207 {
208 _runAs=role;
209 }
210
211
212 public String getRunAs()
213 {
214 return _runAs;
215 }
216
217
218
219
220
221 public String getForcedPath()
222 {
223 return _forcedPath;
224 }
225
226
227
228
229
230 public void setForcedPath(String forcedPath)
231 {
232 _forcedPath = forcedPath;
233 }
234
235
236 public void doStart()
237 throws Exception
238 {
239 _unavailable=0;
240 try
241 {
242 super.doStart();
243 checkServletType();
244 }
245 catch (UnavailableException ue)
246 {
247 makeUnavailable(ue);
248 }
249
250 _config=new Config();
251
252 if (_runAs!=null)
253 _realm=((SecurityHandler)(ContextHandler.getCurrentContext()
254 .getContextHandler().getChildHandlerByClass(SecurityHandler.class))).getUserRealm();
255
256 if (javax.servlet.SingleThreadModel.class.isAssignableFrom(_class))
257 _servlet = new SingleThreadedWrapper();
258
259 if (_extInstance || _initOnStartup)
260 {
261 try
262 {
263 initServlet();
264 }
265 catch(Exception e)
266 {
267 if (_servletHandler.isStartWithUnavailable())
268 Log.ignore(e);
269 else
270 throw e;
271 }
272 }
273 }
274
275
276 public void doStop()
277 {
278 Principal user=null;
279 try
280 {
281
282 if (_runAs!=null && _realm!=null)
283 user=_realm.pushRole(null,_runAs);
284
285 if (_servlet!=null)
286 {
287 try
288 {
289 destroyInstance(_servlet);
290 }
291 catch (Exception e)
292 {
293 Log.warn(e);
294 }
295 }
296
297 if (!_extInstance)
298 _servlet=null;
299
300 _config=null;
301 }
302 finally
303 {
304 super.doStop();
305
306 if (_runAs!=null && _realm!=null && user!=null)
307 _realm.popRole(user);
308 }
309 }
310
311
312 public void destroyInstance (Object o)
313 throws Exception
314 {
315 if (o==null)
316 return;
317 Servlet servlet = ((Servlet)o);
318 servlet.destroy();
319 getServletHandler().customizeServletDestroy(servlet);
320 }
321
322
323
324
325
326 public synchronized Servlet getServlet()
327 throws ServletException
328 {
329
330 if (_unavailable!=0)
331 {
332 if (_unavailable<0 || _unavailable>0 && System.currentTimeMillis()<_unavailable)
333 throw _unavailableEx;
334 _unavailable=0;
335 _unavailableEx=null;
336 }
337
338 if (_servlet==null)
339 initServlet();
340 return _servlet;
341 }
342
343
344
345
346
347 public Servlet getServletInstance()
348 {
349 return _servlet;
350 }
351
352
353
354
355
356
357 public void checkServletType ()
358 throws UnavailableException
359 {
360 if (!javax.servlet.Servlet.class.isAssignableFrom(_class))
361 {
362 throw new UnavailableException("Servlet "+_class+" is not a javax.servlet.Servlet");
363 }
364 }
365
366
367
368
369
370 public boolean isAvailable()
371 {
372 if (isStarted()&& _unavailable==0)
373 return true;
374 try
375 {
376 getServlet();
377 }
378 catch(Exception e)
379 {
380 Log.ignore(e);
381 }
382
383 return isStarted()&& _unavailable==0;
384 }
385
386
387 private void makeUnavailable(UnavailableException e)
388 {
389 if (_unavailableEx==e && _unavailable!=0)
390 return;
391
392 _servletHandler.getServletContext().log("Unavailable "+e);
393
394 _unavailableEx=e;
395 _unavailable=-1;
396 if (e.isPermanent())
397 _unavailable=-1;
398 else
399 {
400 if (_unavailableEx.getUnavailableSeconds()>0)
401 _unavailable=System.currentTimeMillis()+1000*_unavailableEx.getUnavailableSeconds();
402 else
403 _unavailable=System.currentTimeMillis()+5000;
404 }
405 }
406
407
408 private void makeUnavailable(Throwable e)
409 {
410 if (e instanceof UnavailableException)
411 makeUnavailable((UnavailableException)e);
412 else
413 {
414 _servletHandler.getServletContext().log("unavailable",e);
415 _unavailableEx=new UnavailableException(e.toString(),-1);
416 _unavailable=-1;
417 }
418 }
419
420
421 private void initServlet()
422 throws ServletException
423 {
424 Principal user=null;
425 try
426 {
427 if (_servlet==null)
428 _servlet=(Servlet)newInstance();
429 if (_config==null)
430 _config=new Config();
431
432
433 if (!(_servlet instanceof SingleThreadedWrapper))
434 _servlet = getServletHandler().customizeServlet(_servlet);
435
436
437 if (_runAs!=null && _realm!=null)
438 user=_realm.pushRole(null,_runAs);
439
440 _servlet.init(_config);
441 }
442 catch (UnavailableException e)
443 {
444 makeUnavailable(e);
445 _servlet=null;
446 _config=null;
447 throw e;
448 }
449 catch (ServletException e)
450 {
451 makeUnavailable(e.getCause()==null?e:e.getCause());
452 _servlet=null;
453 _config=null;
454 throw e;
455 }
456 catch (Exception e)
457 {
458 makeUnavailable(e);
459 _servlet=null;
460 _config=null;
461 throw new ServletException(e);
462 }
463 finally
464 {
465
466 if (_runAs!=null && _realm!=null && user!=null)
467 _realm.popRole(user);
468 }
469 }
470
471
472
473
474 public void handle(ServletRequest request,
475 ServletResponse response)
476 throws ServletException,
477 UnavailableException,
478 IOException
479 {
480 if (_class==null)
481 throw new UnavailableException("Servlet Not Initialized");
482
483 Servlet servlet=_servlet;
484 synchronized(this)
485 {
486 if (_unavailable!=0 || !_initOnStartup)
487 servlet=getServlet();
488 if (servlet==null)
489 throw new UnavailableException("Could not instantiate "+_class);
490 }
491
492
493 boolean servlet_error=true;
494 Principal user=null;
495 Request base_request=null;
496 try
497 {
498
499 if (_forcedPath!=null)
500
501 request.setAttribute("org.apache.catalina.jsp_file",_forcedPath);
502
503
504 if (_runAs!=null && _realm!=null)
505 {
506 base_request=HttpConnection.getCurrentConnection().getRequest();
507 user=_realm.pushRole(base_request.getUserPrincipal(),_runAs);
508 base_request.setUserPrincipal(user);
509 }
510
511 servlet.service(request,response);
512 servlet_error=false;
513 }
514 catch(UnavailableException e)
515 {
516 makeUnavailable(e);
517 throw _unavailableEx;
518 }
519 finally
520 {
521
522 if (_runAs!=null && _realm!=null && user!=null && base_request!=null)
523 {
524 user=_realm.popRole(user);
525 base_request.setUserPrincipal(user);
526 }
527
528
529 if (servlet_error)
530 request.setAttribute("javax.servlet.error.servlet_name",getName());
531 }
532 }
533
534
535
536
537
538 class Config implements ServletConfig
539 {
540
541 public String getServletName()
542 {
543 return getName();
544 }
545
546
547 public ServletContext getServletContext()
548 {
549 return _servletHandler.getServletContext();
550 }
551
552
553 public String getInitParameter(String param)
554 {
555 return ServletHolder.this.getInitParameter(param);
556 }
557
558
559 public Enumeration getInitParameterNames()
560 {
561 return ServletHolder.this.getInitParameterNames();
562 }
563 }
564
565
566
567
568 private class SingleThreadedWrapper implements Servlet
569 {
570 Stack _stack=new Stack();
571
572 public void destroy()
573 {
574 synchronized(this)
575 {
576 while(_stack.size()>0)
577 try { ((Servlet)_stack.pop()).destroy(); } catch (Exception e) { Log.warn(e); }
578 }
579 }
580
581 public ServletConfig getServletConfig()
582 {
583 return _config;
584 }
585
586 public String getServletInfo()
587 {
588 return null;
589 }
590
591 public void init(ServletConfig config) throws ServletException
592 {
593 synchronized(this)
594 {
595 if(_stack.size()==0)
596 {
597 try
598 {
599 Servlet s = (Servlet) newInstance();
600 s = getServletHandler().customizeServlet(s);
601 s.init(config);
602 _stack.push(s);
603 }
604 catch (ServletException e)
605 {
606 throw e;
607 }
608 catch (Exception e)
609 {
610 throw new ServletException(e);
611 }
612 }
613 }
614 }
615
616 public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException
617 {
618 Servlet s;
619 synchronized(this)
620 {
621 if(_stack.size()>0)
622 s=(Servlet)_stack.pop();
623 else
624 {
625 try
626 {
627 s = (Servlet) newInstance();
628 s = getServletHandler().customizeServlet(s);
629 s.init(_config);
630 }
631 catch (ServletException e)
632 {
633 throw e;
634 }
635 catch (IOException e)
636 {
637 throw e;
638 }
639 catch (Exception e)
640 {
641 throw new ServletException(e);
642 }
643 }
644 }
645
646 try
647 {
648 s.service(req,res);
649 }
650 finally
651 {
652 synchronized(this)
653 {
654 _stack.push(s);
655 }
656 }
657 }
658
659 }
660 }
661
662
663
664
665