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