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