KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > catalina > core > StandardWrapper


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18
19 package org.apache.catalina.core;
20
21 import java.lang.reflect.Method JavaDoc;
22 import java.io.IOException JavaDoc;
23 import java.io.InputStream JavaDoc;
24 import java.io.PrintStream JavaDoc;
25 import java.util.ArrayList JavaDoc;
26 import java.util.Enumeration JavaDoc;
27 import java.util.HashMap JavaDoc;
28 import java.util.HashSet JavaDoc;
29 import java.util.Properties JavaDoc;
30 import java.util.Stack JavaDoc;
31 import java.security.AccessController JavaDoc;
32 import java.security.PrivilegedActionException JavaDoc;
33 import java.security.PrivilegedExceptionAction JavaDoc;
34 import javax.servlet.Servlet JavaDoc;
35 import javax.servlet.ServletConfig JavaDoc;
36 import javax.servlet.ServletContext JavaDoc;
37 import javax.servlet.ServletException JavaDoc;
38 import javax.servlet.ServletRequest JavaDoc;
39 import javax.servlet.ServletResponse JavaDoc;
40 import javax.servlet.SingleThreadModel JavaDoc;
41 import javax.servlet.UnavailableException JavaDoc;
42 import javax.management.ListenerNotFoundException JavaDoc;
43 import javax.management.MBeanNotificationInfo JavaDoc;
44 import javax.management.Notification JavaDoc;
45 import javax.management.NotificationBroadcasterSupport JavaDoc;
46 import javax.management.NotificationEmitter JavaDoc;
47 import javax.management.NotificationFilter JavaDoc;
48 import javax.management.NotificationListener JavaDoc;
49 import javax.management.ObjectName JavaDoc;
50
51 import org.apache.PeriodicEventListener;
52 import org.apache.catalina.Container;
53 import org.apache.catalina.ContainerServlet;
54 import org.apache.catalina.Context;
55 import org.apache.catalina.InstanceEvent;
56 import org.apache.catalina.InstanceListener;
57 import org.apache.catalina.LifecycleException;
58 import org.apache.catalina.Loader;
59 import org.apache.catalina.Wrapper;
60 import org.apache.catalina.security.SecurityUtil;
61 import org.apache.catalina.util.Enumerator;
62 import org.apache.catalina.util.InstanceSupport;
63 import org.apache.tomcat.util.IntrospectionUtils;
64 import org.apache.tomcat.util.log.SystemLogHandler;
65 import org.apache.tomcat.util.modeler.Registry;
66
67 /**
68  * Standard implementation of the <b>Wrapper</b> interface that represents
69  * an individual servlet definition. No child Containers are allowed, and
70  * the parent Container must be a Context.
71  *
72  * @author Craig R. McClanahan
73  * @author Remy Maucherat
74  * @version $Revision: 467989 $ $Date: 2006-10-26 15:08:58 +0200 (jeu., 26 oct. 2006) $
75  */

76 public class StandardWrapper
77     extends ContainerBase
78     implements ServletConfig JavaDoc, Wrapper, NotificationEmitter JavaDoc {
79
80     protected static org.apache.commons.logging.Log log=
81         org.apache.commons.logging.LogFactory.getLog( StandardWrapper.class );
82
83     protected static final String JavaDoc[] DEFAULT_SERVLET_METHODS = new String JavaDoc[] {
84                                                     "GET", "HEAD", "POST" };
85
86     // ----------------------------------------------------------- Constructors
87

88
89     /**
90      * Create a new StandardWrapper component with the default basic Valve.
91      */

92     public StandardWrapper() {
93
94         super();
95         swValve=new StandardWrapperValve();
96         pipeline.setBasic(swValve);
97         broadcaster = new NotificationBroadcasterSupport JavaDoc();
98
99         if (restrictedServlets == null) {
100             restrictedServlets = new Properties JavaDoc();
101             try {
102                 InputStream JavaDoc is =
103                     this.getClass().getClassLoader().getResourceAsStream
104                         ("org/apache/catalina/core/RestrictedServlets.properties");
105                 if (is != null) {
106                     restrictedServlets.load(is);
107                 } else {
108                     log.error(sm.getString("standardWrapper.restrictedServletsResource"));
109                 }
110             } catch (IOException JavaDoc e) {
111                 log.error(sm.getString("standardWrapper.restrictedServletsResource"), e);
112             }
113         }
114         
115     }
116
117
118     // ----------------------------------------------------- Instance Variables
119

120
121     /**
122      * The date and time at which this servlet will become available (in
123      * milliseconds since the epoch), or zero if the servlet is available.
124      * If this value equals Long.MAX_VALUE, the unavailability of this
125      * servlet is considered permanent.
126      */

127     protected long available = 0L;
128     
129     /**
130      * The broadcaster that sends j2ee notifications.
131      */

132     protected NotificationBroadcasterSupport JavaDoc broadcaster = null;
133     
134     /**
135      * The count of allocations that are currently active (even if they
136      * are for the same instance, as will be true on a non-STM servlet).
137      */

138     protected int countAllocated = 0;
139
140
141     /**
142      * The facade associated with this wrapper.
143      */

144     protected StandardWrapperFacade facade =
145         new StandardWrapperFacade(this);
146
147
148     /**
149      * The descriptive information string for this implementation.
150      */

151     protected static final String JavaDoc info =
152         "org.apache.catalina.core.StandardWrapper/1.0";
153
154
155     /**
156      * The (single) initialized instance of this servlet.
157      */

158     protected Servlet JavaDoc instance = null;
159
160
161     /**
162      * The support object for our instance listeners.
163      */

164     protected InstanceSupport instanceSupport = new InstanceSupport(this);
165
166
167     /**
168      * The context-relative URI of the JSP file for this servlet.
169      */

170     protected String JavaDoc jspFile = null;
171
172
173     /**
174      * The load-on-startup order value (negative value means load on
175      * first call) for this servlet.
176      */

177     protected int loadOnStartup = -1;
178
179
180     /**
181      * Mappings associated with the wrapper.
182      */

183     protected ArrayList JavaDoc mappings = new ArrayList JavaDoc();
184
185
186     /**
187      * The initialization parameters for this servlet, keyed by
188      * parameter name.
189      */

190     protected HashMap JavaDoc parameters = new HashMap JavaDoc();
191
192
193     /**
194      * The security role references for this servlet, keyed by role name
195      * used in the servlet. The corresponding value is the role name of
196      * the web application itself.
197      */

198     protected HashMap JavaDoc references = new HashMap JavaDoc();
199
200
201     /**
202      * The run-as identity for this servlet.
203      */

204     protected String JavaDoc runAs = null;
205
206     /**
207      * The notification sequence number.
208      */

209     protected long sequenceNumber = 0;
210
211     /**
212      * The fully qualified servlet class name for this servlet.
213      */

214     protected String JavaDoc servletClass = null;
215
216
217     /**
218      * Does this servlet implement the SingleThreadModel interface?
219      */

220     protected boolean singleThreadModel = false;
221
222
223     /**
224      * Are we unloading our servlet instance at the moment?
225      */

226     protected boolean unloading = false;
227
228
229     /**
230      * Maximum number of STM instances.
231      */

232     protected int maxInstances = 20;
233
234
235     /**
236      * Number of instances currently loaded for a STM servlet.
237      */

238     protected int nInstances = 0;
239
240
241     /**
242      * Stack containing the STM instances.
243      */

244     protected Stack JavaDoc instancePool = null;
245
246     
247     /**
248      * Wait time for servlet unload in ms.
249      */

250     protected long unloadDelay = 2000;
251     
252
253     /**
254      * True if this StandardWrapper is for the JspServlet
255      */

256     protected boolean isJspServlet;
257
258
259     /**
260      * The ObjectName of the JSP monitoring mbean
261      */

262     protected ObjectName JavaDoc jspMonitorON;
263
264
265     /**
266      * Should we swallow System.out
267      */

268     protected boolean swallowOutput = false;
269
270     // To support jmx attributes
271
protected StandardWrapperValve swValve;
272     protected long loadTime=0;
273     protected int classLoadTime=0;
274     
275     /**
276      * Static class array used when the SecurityManager is turned on and
277      * <code>Servlet.init</code> is invoked.
278      */

279     protected static Class JavaDoc[] classType = new Class JavaDoc[]{ServletConfig JavaDoc.class};
280     
281     
282     /**
283      * Static class array used when the SecurityManager is turned on and
284      * <code>Servlet.service</code> is invoked.
285      */

286     protected static Class JavaDoc[] classTypeUsedInService = new Class JavaDoc[]{
287                                                          ServletRequest JavaDoc.class,
288                                                          ServletResponse JavaDoc.class};
289     
290     /**
291      * Restricted servlets (which can only be loaded by a privileged webapp).
292      */

293     protected static Properties JavaDoc restrictedServlets = null;
294     
295     
296     // ------------------------------------------------------------- Properties
297

298
299     /**
300      * Return the available date/time for this servlet, in milliseconds since
301      * the epoch. If this date/time is Long.MAX_VALUE, it is considered to mean
302      * that unavailability is permanent and any request for this servlet will return
303      * an SC_NOT_FOUND error. If this date/time is in the future, any request for
304      * this servlet will return an SC_SERVICE_UNAVAILABLE error. If it is zero,
305      * the servlet is currently available.
306      */

307     public long getAvailable() {
308
309         return (this.available);
310
311     }
312
313
314     /**
315      * Set the available date/time for this servlet, in milliseconds since the
316      * epoch. If this date/time is Long.MAX_VALUE, it is considered to mean
317      * that unavailability is permanent and any request for this servlet will return
318      * an SC_NOT_FOUND error. If this date/time is in the future, any request for
319      * this servlet will return an SC_SERVICE_UNAVAILABLE error.
320      *
321      * @param available The new available date/time
322      */

323     public void setAvailable(long available) {
324
325         long oldAvailable = this.available;
326         if (available > System.currentTimeMillis())
327             this.available = available;
328         else
329             this.available = 0L;
330         support.firePropertyChange("available", new Long JavaDoc(oldAvailable),
331                                    new Long JavaDoc(this.available));
332
333     }
334
335
336     /**
337      * Return the number of active allocations of this servlet, even if they
338      * are all for the same instance (as will be true for servlets that do
339      * not implement <code>SingleThreadModel</code>.
340      */

341     public int getCountAllocated() {
342
343         return (this.countAllocated);
344
345     }
346
347
348     public String JavaDoc getEngineName() {
349         return ((StandardContext)getParent()).getEngineName();
350     }
351
352
353     /**
354      * Return descriptive information about this Container implementation and
355      * the corresponding version number, in the format
356      * <code>&lt;description&gt;/&lt;version&gt;</code>.
357      */

358     public String JavaDoc getInfo() {
359
360         return (info);
361
362     }
363
364
365     /**
366      * Return the InstanceSupport object for this Wrapper instance.
367      */

368     public InstanceSupport getInstanceSupport() {
369
370         return (this.instanceSupport);
371
372     }
373
374
375     /**
376      * Return the context-relative URI of the JSP file for this servlet.
377      */

378     public String JavaDoc getJspFile() {
379
380         return (this.jspFile);
381
382     }
383
384
385     /**
386      * Set the context-relative URI of the JSP file for this servlet.
387      *
388      * @param jspFile JSP file URI
389      */

390     public void setJspFile(String JavaDoc jspFile) {
391
392         String JavaDoc oldJspFile = this.jspFile;
393         this.jspFile = jspFile;
394         support.firePropertyChange("jspFile", oldJspFile, this.jspFile);
395
396         // Each jsp-file needs to be represented by its own JspServlet and
397
// corresponding JspMonitoring mbean, because it may be initialized
398
// with its own init params
399
isJspServlet = true;
400
401     }
402
403
404     /**
405      * Return the load-on-startup order value (negative value means
406      * load on first call).
407      */

408     public int getLoadOnStartup() {
409
410         if (isJspServlet && loadOnStartup < 0) {
411             /*
412              * JspServlet must always be preloaded, because its instance is
413              * used during registerJMX (when registering the JSP
414              * monitoring mbean)
415              */

416              return Integer.MAX_VALUE;
417         } else {
418             return (this.loadOnStartup);
419         }
420     }
421
422
423     /**
424      * Set the load-on-startup order value (negative value means
425      * load on first call).
426      *
427      * @param value New load-on-startup value
428      */

429     public void setLoadOnStartup(int value) {
430
431         int oldLoadOnStartup = this.loadOnStartup;
432         this.loadOnStartup = value;
433         support.firePropertyChange("loadOnStartup",
434                                    new Integer JavaDoc(oldLoadOnStartup),
435                                    new Integer JavaDoc(this.loadOnStartup));
436
437     }
438
439
440
441     /**
442      * Set the load-on-startup order value from a (possibly null) string.
443      * Per the specification, any missing or non-numeric value is converted
444      * to a zero, so that this servlet will still be loaded at startup
445      * time, but in an arbitrary order.
446      *
447      * @param value New load-on-startup value
448      */

449     public void setLoadOnStartupString(String JavaDoc value) {
450
451         try {
452             setLoadOnStartup(Integer.parseInt(value));
453         } catch (NumberFormatException JavaDoc e) {
454             setLoadOnStartup(0);
455         }
456     }
457
458     public String JavaDoc getLoadOnStartupString() {
459         return Integer.toString( getLoadOnStartup());
460     }
461
462
463     /**
464      * Return maximum number of instances that will be allocated when a single
465      * thread model servlet is used.
466      */

467     public int getMaxInstances() {
468
469         return (this.maxInstances);
470
471     }
472
473
474     /**
475      * Set the maximum number of instances that will be allocated when a single
476      * thread model servlet is used.
477      *
478      * @param maxInstances New value of maxInstances
479      */

480     public void setMaxInstances(int maxInstances) {
481
482         int oldMaxInstances = this.maxInstances;
483         this.maxInstances = maxInstances;
484         support.firePropertyChange("maxInstances", oldMaxInstances,
485                                    this.maxInstances);
486
487     }
488
489
490     /**
491      * Set the parent Container of this Wrapper, but only if it is a Context.
492      *
493      * @param container Proposed parent Container
494      */

495     public void setParent(Container container) {
496
497         if ((container != null) &&
498             !(container instanceof Context JavaDoc))
499             throw new IllegalArgumentException JavaDoc
500                 (sm.getString("standardWrapper.notContext"));
501         if (container instanceof StandardContext) {
502             swallowOutput = ((StandardContext)container).getSwallowOutput();
503             unloadDelay = ((StandardContext)container).getUnloadDelay();
504         }
505         super.setParent(container);
506
507     }
508
509
510     /**
511      * Return the run-as identity for this servlet.
512      */

513     public String JavaDoc getRunAs() {
514
515         return (this.runAs);
516
517     }
518
519
520     /**
521      * Set the run-as identity for this servlet.
522      *
523      * @param runAs New run-as identity value
524      */

525     public void setRunAs(String JavaDoc runAs) {
526
527         String JavaDoc oldRunAs = this.runAs;
528         this.runAs = runAs;
529         support.firePropertyChange("runAs", oldRunAs, this.runAs);
530
531     }
532
533
534     /**
535      * Return the fully qualified servlet class name for this servlet.
536      */

537     public String JavaDoc getServletClass() {
538
539         return (this.servletClass);
540
541     }
542
543
544     /**
545      * Set the fully qualified servlet class name for this servlet.
546      *
547      * @param servletClass Servlet class name
548      */

549     public void setServletClass(String JavaDoc servletClass) {
550
551         String JavaDoc oldServletClass = this.servletClass;
552         this.servletClass = servletClass;
553         support.firePropertyChange("servletClass", oldServletClass,
554                                    this.servletClass);
555         if (Constants.JSP_SERVLET_CLASS.equals(servletClass)) {
556             isJspServlet = true;
557         }
558     }
559
560
561
562     /**
563      * Set the name of this servlet. This is an alias for the normal
564      * <code>Container.setName()</code> method, and complements the
565      * <code>getServletName()</code> method required by the
566      * <code>ServletConfig</code> interface.
567      *
568      * @param name The new name of this servlet
569      */

570     public void setServletName(String JavaDoc name) {
571
572         setName(name);
573
574     }
575
576
577     /**
578      * Return <code>true</code> if the servlet class represented by this
579      * component implements the <code>SingleThreadModel</code> interface.
580      */

581     public boolean isSingleThreadModel() {
582
583         try {
584             loadServlet();
585         } catch (Throwable JavaDoc t) {
586             ;
587         }
588         return (singleThreadModel);
589
590     }
591
592
593     /**
594      * Is this servlet currently unavailable?
595      */

596     public boolean isUnavailable() {
597
598         if (available == 0L)
599             return (false);
600         else if (available <= System.currentTimeMillis()) {
601             available = 0L;
602             return (false);
603         } else
604             return (true);
605
606     }
607
608
609     /**
610      * Gets the names of the methods supported by the underlying servlet.
611      *
612      * This is the same set of methods included in the Allow response header
613      * in response to an OPTIONS request method processed by the underlying
614      * servlet.
615      *
616      * @return Array of names of the methods supported by the underlying
617      * servlet
618      */

619     public String JavaDoc[] getServletMethods() throws ServletException JavaDoc {
620
621         Class JavaDoc servletClazz = loadServlet().getClass();
622         if (!javax.servlet.http.HttpServlet JavaDoc.class.isAssignableFrom(
623                                                         servletClazz)) {
624             return DEFAULT_SERVLET_METHODS;
625         }
626
627         HashSet JavaDoc allow = new HashSet JavaDoc();
628         allow.add("TRACE");
629         allow.add("OPTIONS");
630     
631         Method JavaDoc[] methods = getAllDeclaredMethods(servletClazz);
632         for (int i=0; methods != null && i<methods.length; i++) {
633             Method JavaDoc m = methods[i];
634         
635             if (m.getName().equals("doGet")) {
636                 allow.add("GET");
637                 allow.add("HEAD");
638             } else if (m.getName().equals("doPost")) {
639                 allow.add("POST");
640             } else if (m.getName().equals("doPut")) {
641                 allow.add("PUT");
642             } else if (m.getName().equals("doDelete")) {
643                 allow.add("DELETE");
644             }
645         }
646
647         String JavaDoc[] methodNames = new String JavaDoc[allow.size()];
648         return (String JavaDoc[]) allow.toArray(methodNames);
649
650     }
651
652
653     // --------------------------------------------------------- Public Methods
654

655
656     /**
657      * Execute a periodic task, such as reloading, etc. This method will be
658      * invoked inside the classloading context of this container. Unexpected
659      * throwables will be caught and logged.
660      */

661     public void backgroundProcess() {
662         super.backgroundProcess();
663         
664         if (!started)
665             return;
666         
667         if (getServlet() != null && (getServlet() instanceof PeriodicEventListener)) {
668             ((PeriodicEventListener) getServlet()).periodicEvent();
669         }
670     }
671     
672     
673     /**
674      * Extract the root cause from a servlet exception.
675      *
676      * @param e The servlet exception
677      */

678     public static Throwable JavaDoc getRootCause(ServletException JavaDoc e) {
679         Throwable JavaDoc rootCause = e;
680         Throwable JavaDoc rootCauseCheck = null;
681         // Extra aggressive rootCause finding
682
int loops = 0;
683         do {
684             loops++;
685             rootCauseCheck = rootCause.getCause();
686             if (rootCauseCheck != null)
687                 rootCause = rootCauseCheck;
688         } while (rootCauseCheck != null && (loops < 20));
689         return rootCause;
690     }
691
692
693     /**
694      * Refuse to add a child Container, because Wrappers are the lowest level
695      * of the Container hierarchy.
696      *
697      * @param child Child container to be added
698      */

699     public void addChild(Container child) {
700
701         throw new IllegalStateException JavaDoc
702             (sm.getString("standardWrapper.notChild"));
703
704     }
705
706
707     /**
708      * Add a new servlet initialization parameter for this servlet.
709      *
710      * @param name Name of this initialization parameter to add
711      * @param value Value of this initialization parameter to add
712      */

713     public void addInitParameter(String JavaDoc name, String JavaDoc value) {
714
715         synchronized (parameters) {
716             parameters.put(name, value);
717         }
718         fireContainerEvent("addInitParameter", name);
719
720     }
721
722
723     /**
724      * Add a new listener interested in InstanceEvents.
725      *
726      * @param listener The new listener
727      */

728     public void addInstanceListener(InstanceListener listener) {
729
730         instanceSupport.addInstanceListener(listener);
731
732     }
733
734
735     /**
736      * Add a mapping associated with the Wrapper.
737      *
738      * @param mapping The new wrapper mapping
739      */

740     public void addMapping(String JavaDoc mapping) {
741
742         synchronized (mappings) {
743             mappings.add(mapping);
744         }
745         fireContainerEvent("addMapping", mapping);
746
747     }
748
749
750     /**
751      * Add a new security role reference record to the set of records for
752      * this servlet.
753      *
754      * @param name Role name used within this servlet
755      * @param link Role name used within the web application
756      */

757     public void addSecurityReference(String JavaDoc name, String JavaDoc link) {
758
759         synchronized (references) {
760             references.put(name, link);
761         }
762         fireContainerEvent("addSecurityReference", name);
763
764     }
765
766
767     /**
768      * Return the associated servlet instance.
769      */

770     public Servlet JavaDoc getServlet() {
771         return instance;
772     }
773     
774     
775     /**
776      * Allocate an initialized instance of this Servlet that is ready to have
777      * its <code>service()</code> method called. If the servlet class does
778      * not implement <code>SingleThreadModel</code>, the (only) initialized
779      * instance may be returned immediately. If the servlet class implements
780      * <code>SingleThreadModel</code>, the Wrapper implementation must ensure
781      * that this instance is not allocated again until it is deallocated by a
782      * call to <code>deallocate()</code>.
783      *
784      * @exception ServletException if the servlet init() method threw
785      * an exception
786      * @exception ServletException if a loading error occurs
787      */

788     public Servlet JavaDoc allocate() throws ServletException JavaDoc {
789
790         // If we are currently unloading this servlet, throw an exception
791
if (unloading)
792             throw new ServletException JavaDoc
793               (sm.getString("standardWrapper.unloading", getName()));
794
795         // If not SingleThreadedModel, return the same instance every time
796
if (!singleThreadModel) {
797
798             // Load and initialize our instance if necessary
799
if (instance == null) {
800                 synchronized (this) {
801                     if (instance == null) {
802                         try {
803                             if (log.isDebugEnabled())
804                                 log.debug("Allocating non-STM instance");
805
806                             instance = loadServlet();
807                         } catch (ServletException JavaDoc e) {
808                             throw e;
809                         } catch (Throwable JavaDoc e) {
810                             throw new ServletException JavaDoc
811                                 (sm.getString("standardWrapper.allocate"), e);
812                         }
813                     }
814                 }
815             }
816
817             if (!singleThreadModel) {
818                 if (log.isTraceEnabled())
819                     log.trace(" Returning non-STM instance");
820                 countAllocated++;
821                 return (instance);
822             }
823
824         }
825
826         synchronized (instancePool) {
827
828             while (countAllocated >= nInstances) {
829                 // Allocate a new instance if possible, or else wait
830
if (nInstances < maxInstances) {
831                     try {
832                         instancePool.push(loadServlet());
833                         nInstances++;
834                     } catch (ServletException JavaDoc e) {
835                         throw e;
836                     } catch (Throwable JavaDoc e) {
837                         throw new ServletException JavaDoc
838                             (sm.getString("standardWrapper.allocate"), e);
839                     }
840                 } else {
841                     try {
842                         instancePool.wait();
843                     } catch (InterruptedException JavaDoc e) {
844                         ;
845                     }
846                 }
847             }
848             if (log.isTraceEnabled())
849                 log.trace(" Returning allocated STM instance");
850             countAllocated++;
851             return (Servlet JavaDoc) instancePool.pop();
852
853         }
854
855     }
856
857
858     /**
859      * Return this previously allocated servlet to the pool of available
860      * instances. If this servlet class does not implement SingleThreadModel,
861      * no action is actually required.
862      *
863      * @param servlet The servlet to be returned
864      *
865      * @exception ServletException if a deallocation error occurs
866      */

867     public void deallocate(Servlet JavaDoc servlet) throws ServletException JavaDoc {
868
869         // If not SingleThreadModel, no action is required
870
if (!singleThreadModel) {
871             countAllocated--;
872             return;
873         }
874
875         // Unlock and free this instance
876
synchronized (instancePool) {
877             countAllocated--;
878             instancePool.push(servlet);
879             instancePool.notify();
880         }
881
882     }
883
884
885     /**
886      * Return the value for the specified initialization parameter name,
887      * if any; otherwise return <code>null</code>.
888      *
889      * @param name Name of the requested initialization parameter
890      */

891     public String JavaDoc findInitParameter(String JavaDoc name) {
892
893         synchronized (parameters) {
894             return ((String JavaDoc) parameters.get(name));
895         }
896
897     }
898
899
900     /**
901      * Return the names of all defined initialization parameters for this
902      * servlet.
903      */

904     public String JavaDoc[] findInitParameters() {
905
906         synchronized (parameters) {
907             String JavaDoc results[] = new