]> WPIA git - gigi.git/blob - lib/jetty/org/eclipse/jetty/servlet/ServletHolder.java
Importing upstream Jetty jetty-9.2.1.v20140609
[gigi.git] / lib / jetty / org / eclipse / jetty / servlet / ServletHolder.java
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.lang.reflect.Method;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Set;
32 import java.util.Stack;
33
34 import javax.servlet.MultipartConfigElement;
35 import javax.servlet.Servlet;
36 import javax.servlet.ServletConfig;
37 import javax.servlet.ServletContext;
38 import javax.servlet.ServletException;
39 import javax.servlet.ServletRegistration;
40 import javax.servlet.ServletRequest;
41 import javax.servlet.ServletResponse;
42 import javax.servlet.ServletSecurityElement;
43 import javax.servlet.SingleThreadModel;
44 import javax.servlet.UnavailableException;
45
46 import org.eclipse.jetty.security.IdentityService;
47 import org.eclipse.jetty.security.RunAsToken;
48 import org.eclipse.jetty.server.Request;
49 import org.eclipse.jetty.server.UserIdentity;
50 import org.eclipse.jetty.server.handler.ContextHandler;
51 import org.eclipse.jetty.util.Loader;
52 import org.eclipse.jetty.util.annotation.ManagedAttribute;
53 import org.eclipse.jetty.util.annotation.ManagedObject;
54 import org.eclipse.jetty.util.log.Log;
55 import org.eclipse.jetty.util.log.Logger;
56
57
58
59
60 /* --------------------------------------------------------------------- */
61 /** Servlet Instance and Context Holder.
62  * Holds the name, params and some state of a javax.servlet.Servlet
63  * instance. It implements the ServletConfig interface.
64  * This class will organise the loading of the servlet when needed or
65  * requested.
66  *
67  *
68  */
69 @ManagedObject("Servlet Holder")
70 public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope, Comparable<ServletHolder>
71 {
72     private static final Logger LOG = Log.getLogger(ServletHolder.class);
73
74     /* ---------------------------------------------------------------- */
75     private int _initOrder = -1;
76     private boolean _initOnStartup=false;
77     private Map<String, String> _roleMap;
78     private String _forcedPath;
79     private String _runAsRole;
80     private RunAsToken _runAsToken;
81     private IdentityService _identityService;
82     private ServletRegistration.Dynamic _registration;
83
84
85     private transient Servlet _servlet;
86     private transient Config _config;
87     private transient long _unavailable;
88     private transient boolean _enabled = true;
89     private transient UnavailableException _unavailableEx;
90
91     public static final  String JSP_GENERATED_PACKAGE_NAME = "org.eclipse.jetty.servlet.jspPackagePrefix";
92     public static final Map<String,String> NO_MAPPED_ROLES = Collections.emptyMap();
93
94     /* ---------------------------------------------------------------- */
95     /** Constructor .
96      */
97     public ServletHolder()
98     {
99         this(Source.EMBEDDED);
100     }
101
102     /* ---------------------------------------------------------------- */
103     /** Constructor .
104      */
105     public ServletHolder(Holder.Source creator)
106     {
107         super(creator);
108     }
109
110     /* ---------------------------------------------------------------- */
111     /** Constructor for existing servlet.
112      */
113     public ServletHolder(Servlet servlet)
114     {
115         this(Source.EMBEDDED);
116         setServlet(servlet);
117     }
118
119     /* ---------------------------------------------------------------- */
120     /** Constructor for servlet class.
121      */
122     public ServletHolder(String name, Class<? extends Servlet> servlet)
123     {
124         this(Source.EMBEDDED);
125         setName(name);
126         setHeldClass(servlet);
127     }
128
129     /* ---------------------------------------------------------------- */
130     /** Constructor for servlet class.
131      */
132     public ServletHolder(String name, Servlet servlet)
133     {
134         this(Source.EMBEDDED);
135         setName(name);
136         setServlet(servlet);
137     }
138
139     /* ---------------------------------------------------------------- */
140     /** Constructor for servlet class.
141      */
142     public ServletHolder(Class<? extends Servlet> servlet)
143     {
144         this(Source.EMBEDDED);
145         setHeldClass(servlet);
146     }
147
148     /* ---------------------------------------------------------------- */
149     /**
150      * @return The unavailable exception or null if not unavailable
151      */
152     public UnavailableException getUnavailableException()
153     {
154         return _unavailableEx;
155     }
156
157     /* ------------------------------------------------------------ */
158     public synchronized void setServlet(Servlet servlet)
159     {
160         if (servlet==null || servlet instanceof SingleThreadModel)
161             throw new IllegalArgumentException();
162
163         _extInstance=true;
164         _servlet=servlet;
165         setHeldClass(servlet.getClass());
166         if (getName()==null)
167             setName(servlet.getClass().getName()+"-"+super.hashCode());
168     }
169
170     /* ------------------------------------------------------------ */
171     @ManagedAttribute(value="initialization order", readonly=true)
172     public int getInitOrder()
173     {
174         return _initOrder;
175     }
176
177     /* ------------------------------------------------------------ */
178     /** Set the initialize order.
179      * Holders with order<0, are initialized on use. Those with
180      * order>=0 are initialized in increasing order when the handler
181      * is started.
182      */
183     public void setInitOrder(int order)
184     {
185         _initOnStartup=order>=0;
186         _initOrder = order;
187     }
188
189     /* ------------------------------------------------------------ */
190     /** Comparitor by init order.
191      */
192     @Override
193     public int compareTo(ServletHolder sh)
194     {
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
208     /* ------------------------------------------------------------ */
209     public boolean equals(Object o)
210     {
211         return o instanceof ServletHolder && compareTo((ServletHolder)o)==0;
212     }
213
214     /* ------------------------------------------------------------ */
215     public int hashCode()
216     {
217         return _name==null?System.identityHashCode(this):_name.hashCode();
218     }
219
220     /* ------------------------------------------------------------ */
221     /** Link a user role.
222      * Translate the role name used by a servlet, to the link name
223      * used by the container.
224      * @param name The role name as used by the servlet
225      * @param link The role name as used by the container.
226      */
227     public synchronized void setUserRoleLink(String name,String link)
228     {
229         if (_roleMap==null)
230             _roleMap=new HashMap<String, String>();
231         _roleMap.put(name,link);
232     }
233
234     /* ------------------------------------------------------------ */
235     /** get a user role link.
236      * @param name The name of the role
237      * @return The name as translated by the link. If no link exists,
238      * the name is returned.
239      */
240     public String getUserRoleLink(String name)
241     {
242         if (_roleMap==null)
243             return name;
244         String link= _roleMap.get(name);
245         return (link==null)?name:link;
246     }
247
248     /* ------------------------------------------------------------ */
249     /**
250      * @return Returns the forcedPath.
251      */
252     @ManagedAttribute(value="forced servlet path", readonly=true)
253     public String getForcedPath()
254     {
255         return _forcedPath;
256     }
257
258     /* ------------------------------------------------------------ */
259     /**
260      * @param forcedPath The forcedPath to set.
261      */
262     public void setForcedPath(String forcedPath)
263     {
264         _forcedPath = forcedPath;
265     }
266
267     public boolean isEnabled()
268     {
269         return _enabled;
270     }
271
272
273     public void setEnabled(boolean enabled)
274     {
275         _enabled = enabled;
276     }
277
278     
279     /* ------------------------------------------------------------ */
280     public void doStart()
281         throws Exception
282     {
283         _unavailable=0;
284         if (!_enabled)
285             return;
286         
287         // Handle JSP file forced paths
288         if (_forcedPath != null)
289         {
290             // Look for a precompiled JSP Servlet
291             String precompiled=getClassNameForJsp(_forcedPath);
292             LOG.debug("Checking for precompiled servlet {} for jsp {}", precompiled, _forcedPath);
293             ServletHolder jsp=getServletHandler().getServlet(precompiled);
294             if (jsp!=null)
295             {
296                 LOG.debug("JSP file {} for {} mapped to Servlet {}",_forcedPath, getName(),jsp.getClassName());
297                 // set the className for this servlet to the precompiled one
298                 setClassName(jsp.getClassName());
299             }
300             else
301             { 
302                 if (getClassName() == null)
303                 {
304                     // Look for normal JSP servlet
305                     jsp=getServletHandler().getServlet("jsp");
306                     if (jsp!=null)
307                     {
308                         LOG.debug("JSP file {} for {} mapped to Servlet {}",_forcedPath, getName(),jsp.getClassName());
309                         setClassName(jsp.getClassName());
310                         //copy jsp init params that don't exist for this servlet
311                         for (Map.Entry<String, String> entry:jsp.getInitParameters().entrySet())
312                         {
313                             if (!_initParams.containsKey(entry.getKey()))
314                                 setInitParameter(entry.getKey(), entry.getValue());
315                         }
316                         //jsp specific: set up the jsp-file on the JspServlet so it can precompile iff load-on-startup is >=0
317                         if (_initOnStartup)
318                             setInitParameter("jspFile", _forcedPath);
319                     }                       
320                 }
321             }
322         }
323         
324         
325         //check servlet has a class (ie is not a preliminary registration). If preliminary, fail startup.
326         try
327         {
328             super.doStart();
329         }
330         catch (UnavailableException ue)
331         {
332             makeUnavailable(ue);
333             if (_servletHandler.isStartWithUnavailable())
334             {
335                 LOG.ignore(ue);
336                 return;
337             }
338             else
339                 throw ue;
340         }
341
342
343         //servlet is not an instance of javax.servlet.Servlet
344         try
345         {
346             checkServletType();
347         }
348         catch (UnavailableException ue)
349         {
350             makeUnavailable(ue);
351             if (_servletHandler.isStartWithUnavailable())
352             {
353                 LOG.ignore(ue);
354                 return;
355             }
356             else
357                 throw ue;
358         }
359
360         //check if we need to forcibly set load-on-startup
361         checkInitOnStartup();
362
363         _identityService = _servletHandler.getIdentityService();
364         if (_identityService!=null && _runAsRole!=null)
365             _runAsToken=_identityService.newRunAsToken(_runAsRole);
366
367         _config=new Config();
368
369         if (_class!=null && javax.servlet.SingleThreadModel.class.isAssignableFrom(_class))
370             _servlet = new SingleThreadedWrapper();
371      
372     }
373     
374     
375     /* ------------------------------------------------------------ */
376     @Override
377     public void initialize ()
378     throws Exception
379     {
380         super.initialize();
381         if (_extInstance || _initOnStartup)
382         {
383             try
384             {
385                 initServlet();
386             }
387             catch(Exception e)
388             {
389                 if (_servletHandler.isStartWithUnavailable())
390                     LOG.ignore(e);
391                 else
392                     throw e;
393             }
394         }
395     }
396     
397     
398     /* ------------------------------------------------------------ */
399     public void doStop()
400         throws Exception
401     {
402         Object old_run_as = null;
403         if (_servlet!=null)
404         {
405             try
406             {
407                 if (_identityService!=null)
408                     old_run_as=_identityService.setRunAs(_identityService.getSystemUserIdentity(),_runAsToken);
409
410                 destroyInstance(_servlet);
411             }
412             catch (Exception e)
413             {
414                 LOG.warn(e);
415             }
416             finally
417             {
418                 if (_identityService!=null)
419                     _identityService.unsetRunAs(old_run_as);
420             }
421         }
422
423         if (!_extInstance)
424             _servlet=null;
425
426         _config=null;
427     }
428
429     /* ------------------------------------------------------------ */
430     @Override
431     public void destroyInstance (Object o)
432     throws Exception
433     {
434         if (o==null)
435             return;
436         Servlet servlet =  ((Servlet)o);
437         getServletHandler().destroyServlet(servlet);
438         servlet.destroy();
439     }
440
441     /* ------------------------------------------------------------ */
442     /** Get the servlet.
443      * @return The servlet
444      */
445     public synchronized Servlet getServlet()
446         throws ServletException
447     {
448         // Handle previous unavailability
449         if (_unavailable!=0)
450         {
451             if (_unavailable<0 || _unavailable>0 && System.currentTimeMillis()<_unavailable)
452                 throw _unavailableEx;
453             _unavailable=0;
454             _unavailableEx=null;
455         }
456
457         if (_servlet==null)
458             initServlet();
459         return _servlet;
460     }
461
462     /* ------------------------------------------------------------ */
463     /** Get the servlet instance (no initialization done).
464      * @return The servlet or null
465      */
466     public Servlet getServletInstance()
467     {
468         return _servlet;
469     }
470
471     /* ------------------------------------------------------------ */
472     /**
473      * Check to ensure class of servlet is acceptable.
474      * @throws UnavailableException
475      */
476     public void checkServletType ()
477         throws UnavailableException
478     {
479         if (_class==null || !javax.servlet.Servlet.class.isAssignableFrom(_class))
480         {
481             throw new UnavailableException("Servlet "+_class+" is not a javax.servlet.Servlet");
482         }
483     }
484
485     /* ------------------------------------------------------------ */
486     /**
487      * @return true if the holder is started and is not unavailable
488      */
489     public boolean isAvailable()
490     {
491         if (isStarted()&& _unavailable==0)
492             return true;
493         try
494         {
495             getServlet();
496         }
497         catch(Exception e)
498         {
499             LOG.ignore(e);
500         }
501
502         return isStarted()&& _unavailable==0;
503     }
504     
505     /* ------------------------------------------------------------ */
506     /**
507      * Check if there is a javax.servlet.annotation.ServletSecurity
508      * annotation on the servlet class. If there is, then we force
509      * it to be loaded on startup, because all of the security 
510      * constraints must be calculated as the container starts.
511      * 
512      */
513     private void checkInitOnStartup()
514     {
515         if (_class==null)
516             return;
517         
518         if ((_class.getAnnotation(javax.servlet.annotation.ServletSecurity.class) != null) && !_initOnStartup)
519             setInitOrder(Integer.MAX_VALUE);    
520     }
521
522     /* ------------------------------------------------------------ */
523     private void makeUnavailable(UnavailableException e)
524     {
525         if (_unavailableEx==e && _unavailable!=0)
526             return;
527
528         _servletHandler.getServletContext().log("unavailable",e);
529
530         _unavailableEx=e;
531         _unavailable=-1;
532         if (e.isPermanent())
533             _unavailable=-1;
534         else
535         {
536             if (_unavailableEx.getUnavailableSeconds()>0)
537                 _unavailable=System.currentTimeMillis()+1000*_unavailableEx.getUnavailableSeconds();
538             else
539                 _unavailable=System.currentTimeMillis()+5000; // TODO configure
540         }
541     }
542
543     /* ------------------------------------------------------------ */
544
545     private void makeUnavailable(final Throwable e)
546     {
547         if (e instanceof UnavailableException)
548             makeUnavailable((UnavailableException)e);
549         else
550         {
551             ServletContext ctx = _servletHandler.getServletContext();
552             if (ctx==null)
553                 LOG.info("unavailable",e);
554             else
555                 ctx.log("unavailable",e);
556             _unavailableEx=new UnavailableException(String.valueOf(e),-1)
557             {
558                 {
559                     initCause(e);
560                 }
561             };
562             _unavailable=-1;
563         }
564     }
565
566     /* ------------------------------------------------------------ */
567     private void initServlet()
568         throws ServletException
569     {
570         Object old_run_as = null;
571         try
572         {
573             if (_servlet==null)
574                 _servlet=newInstance();
575             if (_config==null)
576                 _config=new Config();
577             
578           
579
580             // Handle run as
581             if (_identityService!=null)
582             {
583                 old_run_as=_identityService.setRunAs(_identityService.getSystemUserIdentity(),_runAsToken);
584             }
585
586             // Handle configuring servlets that implement org.apache.jasper.servlet.JspServlet
587             if (isJspServlet())
588             {
589                 initJspServlet();
590             }
591
592             initMultiPart();
593
594             LOG.debug("Filter.init {}",_servlet);
595             _servlet.init(_config);
596         }
597         catch (UnavailableException e)
598         {
599             makeUnavailable(e);
600             _servlet=null;
601             _config=null;
602             throw e;
603         }
604         catch (ServletException e)
605         {
606             makeUnavailable(e.getCause()==null?e:e.getCause());
607             _servlet=null;
608             _config=null;
609             throw e;
610         }
611         catch (Exception e)
612         {
613             makeUnavailable(e);
614             _servlet=null;
615             _config=null;
616             throw new ServletException(this.toString(),e);
617         }
618         finally
619         {
620             // pop run-as role
621             if (_identityService!=null)
622                 _identityService.unsetRunAs(old_run_as);
623         }
624     }
625
626
627     /* ------------------------------------------------------------ */
628     /**
629      * @throws Exception
630      */
631     protected void initJspServlet () throws Exception
632     {
633         ContextHandler ch = ContextHandler.getContextHandler(getServletHandler().getServletContext());
634             
635         /* Set the webapp's classpath for Jasper */
636         ch.setAttribute("org.apache.catalina.jsp_classpath", ch.getClassPath());
637
638         /* Set the system classpath for Jasper */
639         setInitParameter("com.sun.appserv.jsp.classpath", Loader.getClassPath(ch.getClassLoader().getParent()));
640
641         /* Set up other classpath attribute */
642         if ("?".equals(getInitParameter("classpath")))
643         {
644             String classpath = ch.getClassPath();
645             LOG.debug("classpath=" + classpath);
646             if (classpath != null)
647                 setInitParameter("classpath", classpath);
648         }
649     }
650
651     /* ------------------------------------------------------------ */
652     /**
653      * Register a ServletRequestListener that will ensure tmp multipart
654      * files are deleted when the request goes out of scope.
655      * 
656      * @throws Exception
657      */
658     protected void initMultiPart () throws Exception
659     {
660         //if this servlet can handle multipart requests, ensure tmp files will be
661         //cleaned up correctly
662         if (((Registration)getRegistration()).getMultipartConfig() != null)
663         {
664             //Register a listener to delete tmp files that are created as a result of this
665             //servlet calling Request.getPart() or Request.getParts()
666
667             ContextHandler ch = ContextHandler.getContextHandler(getServletHandler().getServletContext());
668             ch.addEventListener(new Request.MultiPartCleanerListener());
669         }
670     }
671
672     /* ------------------------------------------------------------ */
673     /**
674      * @see org.eclipse.jetty.server.UserIdentity.Scope#getContextPath()
675      */
676     @Override
677     public String getContextPath()
678     {
679         return _config.getServletContext().getContextPath();
680     }
681
682     /* ------------------------------------------------------------ */
683     /**
684      * @see org.eclipse.jetty.server.UserIdentity.Scope#getRoleRefMap()
685      */
686     @Override
687     public Map<String, String> getRoleRefMap()
688     {
689         return _roleMap;
690     }
691
692     /* ------------------------------------------------------------ */
693     @ManagedAttribute(value="role to run servlet as", readonly=true)
694     public String getRunAsRole()
695     {
696         return _runAsRole;
697     }
698
699     /* ------------------------------------------------------------ */
700     public void setRunAsRole(String role)
701     {
702         _runAsRole = role;
703     }
704
705     /* ------------------------------------------------------------ */
706     /** Service a request with this servlet.
707      */
708     public void handle(Request baseRequest,
709                        ServletRequest request,
710                        ServletResponse response)
711         throws ServletException,
712                UnavailableException,
713                IOException
714     {
715         if (_class==null)
716             throw new UnavailableException("Servlet Not Initialized");
717
718         Servlet servlet=_servlet;
719         synchronized(this)
720         {
721             if (!isStarted())
722                 throw new UnavailableException("Servlet not initialized", -1);
723             if (_unavailable!=0 || (!_initOnStartup && servlet==null))
724                 servlet=getServlet();
725             if (servlet==null)
726                 throw new UnavailableException("Could not instantiate "+_class);
727         }
728
729         // Service the request
730         boolean servlet_error=true;
731         Object old_run_as = null;
732         boolean suspendable = baseRequest.isAsyncSupported();
733         try
734         {
735             // Handle aliased path
736             if (_forcedPath!=null)
737                 // TODO complain about poor naming to the Jasper folks
738                 request.setAttribute("org.apache.catalina.jsp_file",_forcedPath);
739
740             // Handle run as
741             if (_identityService!=null)
742                 old_run_as=_identityService.setRunAs(baseRequest.getResolvedUserIdentity(),_runAsToken);
743
744             if (!isAsyncSupported())
745                 baseRequest.setAsyncSupported(false);
746
747             MultipartConfigElement mpce = ((Registration)getRegistration()).getMultipartConfig();
748             if (mpce != null)
749                 request.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, mpce);
750
751             servlet.service(request,response);
752             servlet_error=false;
753         }
754         catch(UnavailableException e)
755         {
756             makeUnavailable(e);
757             throw _unavailableEx;
758         }
759         finally
760         {
761             baseRequest.setAsyncSupported(suspendable);
762
763             // pop run-as role
764             if (_identityService!=null)
765                 _identityService.unsetRunAs(old_run_as);
766
767             // Handle error params.
768             if (servlet_error)
769                 request.setAttribute("javax.servlet.error.servlet_name",getName());
770         }
771     }
772
773
774     /* ------------------------------------------------------------ */
775     private boolean isJspServlet ()
776     {
777         if (_servlet == null)
778             return false;
779
780         Class c = _servlet.getClass();
781
782         boolean result = false;
783         while (c != null && !result)
784         {
785             result = isJspServlet(c.getName());
786             c = c.getSuperclass();
787         }
788
789         return result;
790     }
791
792
793     /* ------------------------------------------------------------ */
794     private boolean isJspServlet (String classname)
795     {
796         if (classname == null)
797             return false;
798         return ("org.apache.jasper.servlet.JspServlet".equals(classname));
799     }
800     
801     
802     /* ------------------------------------------------------------ */
803     private String getNameOfJspClass (String jsp)
804     {
805         if (jsp == null)
806             return "";
807         
808         int i = jsp.lastIndexOf('/') + 1;
809         jsp = jsp.substring(i);
810         try
811         {
812             Class jspUtil = Loader.loadClass(Holder.class, "org.apache.jasper.compiler.JspUtil");
813             Method makeJavaIdentifier = jspUtil.getMethod("makeJavaIdentifier", String.class);
814             return (String)makeJavaIdentifier.invoke(null, jsp);
815         }
816         catch (Exception e)
817         {
818             String tmp = jsp.replace('.','_');
819             LOG.warn("Unable to make identifier for jsp "+jsp +" trying "+tmp+" instead");
820             if (LOG.isDebugEnabled())
821                 LOG.warn(e);
822             return tmp;
823         }
824     }
825     
826     
827     /* ------------------------------------------------------------ */
828     private String getPackageOfJspClass (String jsp)
829     {
830         if (jsp == null)
831             return "";
832         
833         int i = jsp.lastIndexOf('/');
834         if (i <= 0)
835             return "";
836         try
837         {
838             Class jspUtil = Loader.loadClass(Holder.class, "org.apache.jasper.compiler.JspUtil");
839             Method makeJavaPackage = jspUtil.getMethod("makeJavaPackage", String.class);
840             return (String)makeJavaPackage.invoke(null, jsp.substring(0,i));
841         } 
842         catch (Exception e)
843         {
844             String tmp = jsp.substring(1).replace('/','.');
845             LOG.warn("Unable to make package for jsp "+jsp +" trying "+tmp+" instead");
846             if (LOG.isDebugEnabled())
847                 LOG.warn(e);
848             return tmp;
849         }
850     }
851     
852     
853     /* ------------------------------------------------------------ */
854     private String getJspPackagePrefix ()
855     {
856         String jspPackageName = (String)getServletHandler().getServletContext().getInitParameter(JSP_GENERATED_PACKAGE_NAME );
857         if (jspPackageName == null)
858             jspPackageName = "org.apache.jsp";
859         
860         return jspPackageName;
861     }
862     
863     
864     /* ------------------------------------------------------------ */
865     private String getClassNameForJsp (String jsp)
866     {
867         if (jsp == null)
868             return null; 
869         
870         return getJspPackagePrefix() + "." +getPackageOfJspClass(jsp) + "." + getNameOfJspClass(jsp);
871     }
872
873
874     /* ------------------------------------------------------------ */
875     /* ------------------------------------------------------------ */
876     /* ------------------------------------------------------------ */
877     protected class Config extends HolderConfig implements ServletConfig
878     {
879         /* -------------------------------------------------------- */
880         @Override
881         public String getServletName()
882         {
883             return getName();
884         }
885
886     }
887
888     /* -------------------------------------------------------- */
889     /* -------------------------------------------------------- */
890     /* -------------------------------------------------------- */
891     public class Registration extends HolderRegistration implements ServletRegistration.Dynamic
892     {
893         protected MultipartConfigElement _multipartConfig;
894
895         @Override
896         public Set<String> addMapping(String... urlPatterns)
897         {
898             illegalStateIfContextStarted();
899             Set<String> clash=null;
900             for (String pattern : urlPatterns)
901             {
902                 ServletMapping mapping = _servletHandler.getServletMapping(pattern);
903                 if (mapping!=null)
904                 {
905                     //if the servlet mapping was from a default descriptor, then allow it to be overridden
906                     if (!mapping.isDefault())
907                     {
908                         if (clash==null)
909                             clash=new HashSet<String>();
910                         clash.add(pattern);
911                     }
912                 }
913             }
914
915             //if there were any clashes amongst the urls, return them
916             if (clash!=null)
917                 return clash;
918
919             //otherwise apply all of them
920             ServletMapping mapping = new ServletMapping();
921             mapping.setServletName(ServletHolder.this.getName());
922             mapping.setPathSpecs(urlPatterns);
923             _servletHandler.addServletMapping(mapping);
924
925             return Collections.emptySet();
926         }
927
928         @Override
929         public Collection<String> getMappings()
930         {
931             ServletMapping[] mappings =_servletHandler.getServletMappings();
932             List<String> patterns=new ArrayList<String>();
933             if (mappings!=null)
934             {
935                 for (ServletMapping mapping : mappings)
936                 {
937                     if (!mapping.getServletName().equals(getName()))
938                         continue;
939                     String[] specs=mapping.getPathSpecs();
940                     if (specs!=null && specs.length>0)
941                         patterns.addAll(Arrays.asList(specs));
942                 }
943             }
944             return patterns;
945         }
946
947         @Override
948         public String getRunAsRole()
949         {
950             return _runAsRole;
951         }
952
953         @Override
954         public void setLoadOnStartup(int loadOnStartup)
955         {
956             illegalStateIfContextStarted();
957             ServletHolder.this.setInitOrder(loadOnStartup);
958         }
959
960         public int getInitOrder()
961         {
962             return ServletHolder.this.getInitOrder();
963         }
964
965         @Override
966         public void setMultipartConfig(MultipartConfigElement element)
967         {
968             _multipartConfig = element;
969         }
970
971         public MultipartConfigElement getMultipartConfig()
972         {
973             return _multipartConfig;
974         }
975
976         @Override
977         public void setRunAsRole(String role)
978         {
979             _runAsRole = role;
980         }
981
982         @Override
983         public Set<String> setServletSecurity(ServletSecurityElement securityElement)
984         {
985             return _servletHandler.setServletSecurity(this, securityElement);
986         }
987     }
988
989     public ServletRegistration.Dynamic getRegistration()
990     {
991         if (_registration == null)
992             _registration = new Registration();
993         return _registration;
994     }
995
996     /* -------------------------------------------------------- */
997     /* -------------------------------------------------------- */
998     /* -------------------------------------------------------- */
999     private class SingleThreadedWrapper implements Servlet
1000     {
1001         Stack<Servlet> _stack=new Stack<Servlet>();
1002
1003         @Override
1004         public void destroy()
1005         {
1006             synchronized(this)
1007             {
1008                 while(_stack.size()>0)
1009                     try { (_stack.pop()).destroy(); } catch (Exception e) { LOG.warn(e); }
1010             }
1011         }
1012
1013         @Override
1014         public ServletConfig getServletConfig()
1015         {
1016             return _config;
1017         }
1018
1019         @Override
1020         public String getServletInfo()
1021         {
1022             return null;
1023         }
1024
1025         @Override
1026         public void init(ServletConfig config) throws ServletException
1027         {
1028             synchronized(this)
1029             {
1030                 if(_stack.size()==0)
1031                 {
1032                     try
1033                     {
1034                         Servlet s = newInstance();
1035                         s.init(config);
1036                         _stack.push(s);
1037                     }
1038                     catch (ServletException e)
1039                     {
1040                         throw e;
1041                     }
1042                     catch (Exception e)
1043                     {
1044                         throw new ServletException(e);
1045                     }
1046                 }
1047             }
1048         }
1049
1050         @Override
1051         public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException
1052         {
1053             Servlet s;
1054             synchronized(this)
1055             {
1056                 if(_stack.size()>0)
1057                     s=(Servlet)_stack.pop();
1058                 else
1059                 {
1060                     try
1061                     {
1062                         s = newInstance();
1063                         s.init(_config);
1064                     }
1065                     catch (ServletException e)
1066                     {
1067                         throw e;
1068                     }
1069                     catch (Exception e)
1070                     {
1071                         throw new ServletException(e);
1072                     }
1073                 }
1074             }
1075
1076             try
1077             {
1078                 s.service(req,res);
1079             }
1080             finally
1081             {
1082                 synchronized(this)
1083                 {
1084                     _stack.push(s);
1085                 }
1086             }
1087         }
1088     }
1089
1090     /* ------------------------------------------------------------ */
1091     /**
1092      * @return the newly created Servlet instance
1093      * @throws ServletException
1094      * @throws IllegalAccessException
1095      * @throws InstantiationException
1096      */
1097     protected Servlet newInstance() throws ServletException, IllegalAccessException, InstantiationException
1098     {
1099         try
1100         {
1101             ServletContext ctx = getServletHandler().getServletContext();
1102             if (ctx instanceof ServletContextHandler.Context)
1103                 return ((ServletContextHandler.Context)ctx).createServlet(getHeldClass());
1104             return getHeldClass().newInstance();
1105         }
1106         catch (ServletException se)
1107         {
1108             Throwable cause = se.getRootCause();
1109             if (cause instanceof InstantiationException)
1110                 throw (InstantiationException)cause;
1111             if (cause instanceof IllegalAccessException)
1112                 throw (IllegalAccessException)cause;
1113             throw se;
1114         }
1115     }
1116     
1117
1118     /* ------------------------------------------------------------ */
1119     @Override
1120     public String toString()
1121     {
1122         return String.format("%s@%x==%s,%d,%b",_name,hashCode(),_className,_initOrder,_servlet!=null);
1123     }
1124 }