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