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