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