• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 //  ========================================================================
3 //  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
4 //  ------------------------------------------------------------------------
5 //  All rights reserved. This program and the accompanying materials
6 //  are made available under the terms of the Eclipse Public License v1.0
7 //  and Apache License v2.0 which accompanies this distribution.
8 //
9 //      The Eclipse Public License is available at
10 //      http://www.eclipse.org/legal/epl-v10.html
11 //
12 //      The Apache License v2.0 is available at
13 //      http://www.opensource.org/licenses/apache2.0.php
14 //
15 //  You may elect to redistribute this code under either of these licenses.
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 /** Servlet Instance and Context Holder.
59  * Holds the name, params and some state of a javax.servlet.Servlet
60  * instance. It implements the ServletConfig interface.
61  * This class will organise the loading of the servlet when needed or
62  * requested.
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     /** Constructor .
90      */
ServletHolder()91     public ServletHolder()
92     {
93         this(Source.EMBEDDED);
94     }
95 
96     /* ---------------------------------------------------------------- */
97     /** Constructor .
98      */
ServletHolder(Holder.Source creator)99     public ServletHolder(Holder.Source creator)
100     {
101         super(creator);
102     }
103 
104     /* ---------------------------------------------------------------- */
105     /** Constructor for existing servlet.
106      */
ServletHolder(Servlet servlet)107     public ServletHolder(Servlet servlet)
108     {
109         this(Source.EMBEDDED);
110         setServlet(servlet);
111     }
112 
113     /* ---------------------------------------------------------------- */
114     /** Constructor for servlet class.
115      */
ServletHolder(String name, Class<? extends Servlet> servlet)116     public ServletHolder(String name, Class<? extends Servlet> servlet)
117     {
118         this(Source.EMBEDDED);
119         setName(name);
120         setHeldClass(servlet);
121     }
122 
123     /* ---------------------------------------------------------------- */
124     /** Constructor for servlet class.
125      */
ServletHolder(String name, Servlet servlet)126     public ServletHolder(String name, Servlet servlet)
127     {
128         this(Source.EMBEDDED);
129         setName(name);
130         setServlet(servlet);
131     }
132 
133     /* ---------------------------------------------------------------- */
134     /** Constructor for servlet class.
135      */
ServletHolder(Class<? extends Servlet> servlet)136     public ServletHolder(Class<? extends Servlet> servlet)
137     {
138         this(Source.EMBEDDED);
139         setHeldClass(servlet);
140     }
141 
142     /* ---------------------------------------------------------------- */
143     /**
144      * @return The unavailable exception or null if not unavailable
145      */
getUnavailableException()146     public UnavailableException getUnavailableException()
147     {
148         return _unavailableEx;
149     }
150 
151     /* ------------------------------------------------------------ */
setServlet(Servlet servlet)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     /* ------------------------------------------------------------ */
getInitOrder()165     public int getInitOrder()
166     {
167         return _initOrder;
168     }
169 
170     /* ------------------------------------------------------------ */
171     /** Set the initialize order.
172      * Holders with order<0, are initialized on use. Those with
173      * order>=0 are initialized in increasing order when the handler
174      * is started.
175      */
setInitOrder(int order)176     public void setInitOrder(int order)
177     {
178         _initOnStartup=true;
179         _initOrder = order;
180     }
181 
isSetInitOrder()182     public boolean isSetInitOrder()
183     {
184         return _initOnStartup;
185     }
186 
187     /* ------------------------------------------------------------ */
188     /** Comparitor by init order.
189      */
compareTo(Object o)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             return c;
206         }
207         return 1;
208     }
209 
210     /* ------------------------------------------------------------ */
equals(Object o)211     public boolean equals(Object o)
212     {
213         return compareTo(o)==0;
214     }
215 
216     /* ------------------------------------------------------------ */
hashCode()217     public int hashCode()
218     {
219         return _name==null?System.identityHashCode(this):_name.hashCode();
220     }
221 
222     /* ------------------------------------------------------------ */
223     /** Link a user role.
224      * Translate the role name used by a servlet, to the link name
225      * used by the container.
226      * @param name The role name as used by the servlet
227      * @param link The role name as used by the container.
228      */
setUserRoleLink(String name,String link)229     public synchronized void setUserRoleLink(String name,String link)
230     {
231         if (_roleMap==null)
232             _roleMap=new HashMap<String, String>();
233         _roleMap.put(name,link);
234     }
235 
236     /* ------------------------------------------------------------ */
237     /** get a user role link.
238      * @param name The name of the role
239      * @return The name as translated by the link. If no link exists,
240      * the name is returned.
241      */
getUserRoleLink(String name)242     public String getUserRoleLink(String name)
243     {
244         if (_roleMap==null)
245             return name;
246         String link= _roleMap.get(name);
247         return (link==null)?name:link;
248     }
249 
250     /* ------------------------------------------------------------ */
getRoleMap()251     public Map<String, String> getRoleMap()
252     {
253         return _roleMap == null? NO_MAPPED_ROLES : _roleMap;
254     }
255 
256     /* ------------------------------------------------------------ */
257     /**
258      * @return Returns the forcedPath.
259      */
getForcedPath()260     public String getForcedPath()
261     {
262         return _forcedPath;
263     }
264 
265     /* ------------------------------------------------------------ */
266     /**
267      * @param forcedPath The forcedPath to set.
268      */
setForcedPath(String forcedPath)269     public void setForcedPath(String forcedPath)
270     {
271         _forcedPath = forcedPath;
272     }
273 
isEnabled()274     public boolean isEnabled()
275     {
276         return _enabled;
277     }
278 
279 
setEnabled(boolean enabled)280     public void setEnabled(boolean enabled)
281     {
282         _enabled = enabled;
283     }
284 
285 
286     /* ------------------------------------------------------------ */
doStart()287     public void doStart()
288         throws Exception
289     {
290         _unavailable=0;
291         if (!_enabled)
292             return;
293 
294 
295         //check servlet has a class (ie is not a preliminary registration). If preliminary, fail startup.
296         try
297         {
298             super.doStart();
299         }
300         catch (UnavailableException ue)
301         {
302             makeUnavailable(ue);
303             if (_servletHandler.isStartWithUnavailable())
304             {
305                 LOG.ignore(ue);
306                 return;
307             }
308             else
309                 throw ue;
310         }
311 
312 
313         //servlet is not an instance of javax.servlet.Servlet
314         try
315         {
316             checkServletType();
317         }
318         catch (UnavailableException ue)
319         {
320             makeUnavailable(ue);
321             if (_servletHandler.isStartWithUnavailable())
322             {
323                 LOG.ignore(ue);
324                 return;
325             }
326             else
327                 throw ue;
328         }
329 
330 
331         _identityService = _servletHandler.getIdentityService();
332         if (_identityService!=null && _runAsRole!=null)
333             _runAsToken=_identityService.newRunAsToken(_runAsRole);
334 
335         _config=new Config();
336 
337         if (_class!=null && javax.servlet.SingleThreadModel.class.isAssignableFrom(_class))
338             _servlet = new SingleThreadedWrapper();
339 
340         if (_extInstance || _initOnStartup)
341         {
342             try
343             {
344                 initServlet();
345             }
346             catch(Exception e)
347             {
348                 if (_servletHandler.isStartWithUnavailable())
349                     LOG.ignore(e);
350                 else
351                     throw e;
352             }
353         }
354     }
355 
356     /* ------------------------------------------------------------ */
doStop()357     public void doStop()
358         throws Exception
359     {
360         Object old_run_as = null;
361         if (_servlet!=null)
362         {
363             try
364             {
365                 if (_identityService!=null)
366                     old_run_as=_identityService.setRunAs(_identityService.getSystemUserIdentity(),_runAsToken);
367 
368                 destroyInstance(_servlet);
369             }
370             catch (Exception e)
371             {
372                 LOG.warn(e);
373             }
374             finally
375             {
376                 if (_identityService!=null)
377                     _identityService.unsetRunAs(old_run_as);
378             }
379         }
380 
381         if (!_extInstance)
382             _servlet=null;
383 
384         _config=null;
385     }
386 
387     /* ------------------------------------------------------------ */
destroyInstance(Object o)388     public void destroyInstance (Object o)
389     throws Exception
390     {
391         if (o==null)
392             return;
393         Servlet servlet =  ((Servlet)o);
394         getServletHandler().destroyServlet(servlet);
395         servlet.destroy();
396     }
397 
398     /* ------------------------------------------------------------ */
399     /** Get the servlet.
400      * @return The servlet
401      */
getServlet()402     public synchronized Servlet getServlet()
403         throws ServletException
404     {
405         // Handle previous unavailability
406         if (_unavailable!=0)
407         {
408             if (_unavailable<0 || _unavailable>0 && System.currentTimeMillis()<_unavailable)
409                 throw _unavailableEx;
410             _unavailable=0;
411             _unavailableEx=null;
412         }
413 
414         if (_servlet==null)
415             initServlet();
416         return _servlet;
417     }
418 
419     /* ------------------------------------------------------------ */
420     /** Get the servlet instance (no initialization done).
421      * @return The servlet or null
422      */
getServletInstance()423     public Servlet getServletInstance()
424     {
425         return _servlet;
426     }
427 
428     /* ------------------------------------------------------------ */
429     /**
430      * Check to ensure class of servlet is acceptable.
431      * @throws UnavailableException
432      */
checkServletType()433     public void checkServletType ()
434         throws UnavailableException
435     {
436         if (_class==null || !javax.servlet.Servlet.class.isAssignableFrom(_class))
437         {
438             throw new UnavailableException("Servlet "+_class+" is not a javax.servlet.Servlet");
439         }
440     }
441 
442     /* ------------------------------------------------------------ */
443     /**
444      * @return true if the holder is started and is not unavailable
445      */
isAvailable()446     public boolean isAvailable()
447     {
448         if (isStarted()&& _unavailable==0)
449             return true;
450         try
451         {
452             getServlet();
453         }
454         catch(Exception e)
455         {
456             LOG.ignore(e);
457         }
458 
459         return isStarted()&& _unavailable==0;
460     }
461 
462     /* ------------------------------------------------------------ */
makeUnavailable(UnavailableException e)463     private void makeUnavailable(UnavailableException e)
464     {
465         if (_unavailableEx==e && _unavailable!=0)
466             return;
467 
468         _servletHandler.getServletContext().log("unavailable",e);
469 
470         _unavailableEx=e;
471         _unavailable=-1;
472         if (e.isPermanent())
473             _unavailable=-1;
474         else
475         {
476             if (_unavailableEx.getUnavailableSeconds()>0)
477                 _unavailable=System.currentTimeMillis()+1000*_unavailableEx.getUnavailableSeconds();
478             else
479                 _unavailable=System.currentTimeMillis()+5000; // TODO configure
480         }
481     }
482 
483     /* ------------------------------------------------------------ */
484 
makeUnavailable(final Throwable e)485     private void makeUnavailable(final Throwable e)
486     {
487         if (e instanceof UnavailableException)
488             makeUnavailable((UnavailableException)e);
489         else
490         {
491             ServletContext ctx = _servletHandler.getServletContext();
492             if (ctx==null)
493                 LOG.info("unavailable",e);
494             else
495                 ctx.log("unavailable",e);
496             _unavailableEx=new UnavailableException(String.valueOf(e),-1)
497             {
498                 {
499                     initCause(e);
500                 }
501             };
502             _unavailable=-1;
503         }
504     }
505 
506     /* ------------------------------------------------------------ */
initServlet()507     private void initServlet()
508     	throws ServletException
509     {
510         Object old_run_as = null;
511         try
512         {
513             if (_servlet==null)
514                 _servlet=newInstance();
515             if (_config==null)
516                 _config=new Config();
517 
518             // Handle run as
519             if (_identityService!=null)
520             {
521                 old_run_as=_identityService.setRunAs(_identityService.getSystemUserIdentity(),_runAsToken);
522             }
523 
524             // Handle configuring servlets that implement org.apache.jasper.servlet.JspServlet
525             if (isJspServlet())
526             {
527                 initJspServlet();
528             }
529 
530             initMultiPart();
531 
532             _servlet.init(_config);
533         }
534         catch (UnavailableException e)
535         {
536             makeUnavailable(e);
537             _servlet=null;
538             _config=null;
539             throw e;
540         }
541         catch (ServletException e)
542         {
543             makeUnavailable(e.getCause()==null?e:e.getCause());
544             _servlet=null;
545             _config=null;
546             throw e;
547         }
548         catch (Exception e)
549         {
550             makeUnavailable(e);
551             _servlet=null;
552             _config=null;
553             throw new ServletException(this.toString(),e);
554         }
555         finally
556         {
557             // pop run-as role
558             if (_identityService!=null)
559                 _identityService.unsetRunAs(old_run_as);
560         }
561     }
562 
563 
564     /* ------------------------------------------------------------ */
565     /**
566      * @throws Exception
567      */
initJspServlet()568     protected void initJspServlet () throws Exception
569     {
570         ContextHandler ch = ((ContextHandler.Context)getServletHandler().getServletContext()).getContextHandler();
571 
572         /* Set the webapp's classpath for Jasper */
573         ch.setAttribute("org.apache.catalina.jsp_classpath", ch.getClassPath());
574 
575         /* Set the system classpath for Jasper */
576         setInitParameter("com.sun.appserv.jsp.classpath", Loader.getClassPath(ch.getClassLoader().getParent()));
577 
578         /* Set up other classpath attribute */
579         if ("?".equals(getInitParameter("classpath")))
580         {
581             String classpath = ch.getClassPath();
582             LOG.debug("classpath=" + classpath);
583             if (classpath != null)
584                 setInitParameter("classpath", classpath);
585         }
586     }
587 
588     /* ------------------------------------------------------------ */
589     /**
590      * Register a ServletRequestListener that will ensure tmp multipart
591      * files are deleted when the request goes out of scope.
592      *
593      * @throws Exception
594      */
initMultiPart()595     protected void initMultiPart () throws Exception
596     {
597         //if this servlet can handle multipart requests, ensure tmp files will be
598         //cleaned up correctly
599         if (((Registration)getRegistration()).getMultipartConfig() != null)
600         {
601             //Register a listener to delete tmp files that are created as a result of this
602             //servlet calling Request.getPart() or Request.getParts()
603             ContextHandler ch = ((ContextHandler.Context)getServletHandler().getServletContext()).getContextHandler();
604             ch.addEventListener(new Request.MultiPartCleanerListener());
605         }
606     }
607 
608     /* ------------------------------------------------------------ */
609     /**
610      * @see org.eclipse.jetty.server.UserIdentity.Scope#getContextPath()
611      */
getContextPath()612     public String getContextPath()
613     {
614         return _config.getServletContext().getContextPath();
615     }
616 
617     /* ------------------------------------------------------------ */
618     /**
619      * @see org.eclipse.jetty.server.UserIdentity.Scope#getRoleRefMap()
620      */
getRoleRefMap()621     public Map<String, String> getRoleRefMap()
622     {
623         return _roleMap;
624     }
625 
626     /* ------------------------------------------------------------ */
getRunAsRole()627     public String getRunAsRole()
628     {
629         return _runAsRole;
630     }
631 
632     /* ------------------------------------------------------------ */
setRunAsRole(String role)633     public void setRunAsRole(String role)
634     {
635         _runAsRole = role;
636     }
637 
638     /* ------------------------------------------------------------ */
639     /** Service a request with this servlet.
640      */
handle(Request baseRequest, ServletRequest request, ServletResponse response)641     public void handle(Request baseRequest,
642                        ServletRequest request,
643                        ServletResponse response)
644         throws ServletException,
645                UnavailableException,
646                IOException
647     {
648         if (_class==null)
649             throw new UnavailableException("Servlet Not Initialized");
650 
651         Servlet servlet=_servlet;
652         synchronized(this)
653         {
654             if (!isStarted())
655                 throw new UnavailableException("Servlet not initialized", -1);
656             if (_unavailable!=0 || !_initOnStartup)
657                 servlet=getServlet();
658             if (servlet==null)
659                 throw new UnavailableException("Could not instantiate "+_class);
660         }
661 
662         // Service the request
663         boolean servlet_error=true;
664         Object old_run_as = null;
665         boolean suspendable = baseRequest.isAsyncSupported();
666         try
667         {
668             // Handle aliased path
669             if (_forcedPath!=null)
670                 // TODO complain about poor naming to the Jasper folks
671                 request.setAttribute("org.apache.catalina.jsp_file",_forcedPath);
672 
673             // Handle run as
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             // pop run-as role
697             if (_identityService!=null)
698                 _identityService.unsetRunAs(old_run_as);
699 
700             // Handle error params.
701             if (servlet_error)
702                 request.setAttribute("javax.servlet.error.servlet_name",getName());
703         }
704     }
705 
706 
707     /* ------------------------------------------------------------ */
isJspServlet()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     /* ------------------------------------------------------------ */
isJspServlet(String classname)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         /* -------------------------------------------------------- */
getServletName()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 
addMapping(String... urlPatterns)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                     //if the servlet mapping was from a default descriptor, then allow it to be overridden
765                     if (!mapping.isDefault())
766                     {
767                         if (clash==null)
768                             clash=new HashSet<String>();
769                         clash.add(pattern);
770                     }
771                 }
772             }
773 
774             //if there were any clashes amongst the urls, return them
775             if (clash!=null)
776                 return clash;
777 
778             //otherwise apply all of them
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 
getMappings()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
getRunAsRole()806         public String getRunAsRole()
807         {
808             return _runAsRole;
809         }
810 
811         @Override
setLoadOnStartup(int loadOnStartup)812         public void setLoadOnStartup(int loadOnStartup)
813         {
814             illegalStateIfContextStarted();
815             ServletHolder.this.setInitOrder(loadOnStartup);
816         }
817 
getInitOrder()818         public int getInitOrder()
819         {
820             return ServletHolder.this.getInitOrder();
821         }
822 
823         @Override
setMultipartConfig(MultipartConfigElement element)824         public void setMultipartConfig(MultipartConfigElement element)
825         {
826             _multipartConfig = element;
827         }
828 
getMultipartConfig()829         public MultipartConfigElement getMultipartConfig()
830         {
831             return _multipartConfig;
832         }
833 
834         @Override
setRunAsRole(String role)835         public void setRunAsRole(String role)
836         {
837             _runAsRole = role;
838         }
839 
840         @Override
setServletSecurity(ServletSecurityElement securityElement)841         public Set<String> setServletSecurity(ServletSecurityElement securityElement)
842         {
843             return _servletHandler.setServletSecurity(this, securityElement);
844         }
845     }
846 
getRegistration()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 
destroy()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 
getServletConfig()870         public ServletConfig getServletConfig()
871         {
872             return _config;
873         }
874 
getServletInfo()875         public String getServletInfo()
876         {
877             return null;
878         }
879 
init(ServletConfig config)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 
service(ServletRequest req, ServletResponse res)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      * @return the newly created Servlet instance
946      * @throws ServletException
947      * @throws IllegalAccessException
948      * @throws InstantiationException
949      */
newInstance()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 }
970