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