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