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