Save This Page
Home » apache-tomcat-6.0.26-src » org.apache » catalina » core » [javadoc | source]
    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;
   22   import java.io.IOException;
   23   import java.io.InputStream;
   24   import java.io.PrintStream;
   25   import java.util.ArrayList;
   26   import java.util.Enumeration;
   27   import java.util.HashMap;
   28   import java.util.HashSet;
   29   import java.util.Properties;
   30   import java.util.Stack;
   31   import java.util.concurrent.atomic.AtomicInteger;
   32   import java.security.AccessController;
   33   import java.security.PrivilegedActionException;
   34   import java.security.PrivilegedExceptionAction;
   35   import javax.servlet.Servlet;
   36   import javax.servlet.ServletConfig;
   37   import javax.servlet.ServletContext;
   38   import javax.servlet.ServletException;
   39   import javax.servlet.ServletRequest;
   40   import javax.servlet.ServletResponse;
   41   import javax.servlet.SingleThreadModel;
   42   import javax.servlet.UnavailableException;
   43   import javax.management.ListenerNotFoundException;
   44   import javax.management.MBeanNotificationInfo;
   45   import javax.management.Notification;
   46   import javax.management.NotificationBroadcasterSupport;
   47   import javax.management.NotificationEmitter;
   48   import javax.management.NotificationFilter;
   49   import javax.management.NotificationListener;
   50   import javax.management.ObjectName;
   51   
   52   import org.apache.PeriodicEventListener;
   53   import org.apache.catalina.Container;
   54   import org.apache.catalina.ContainerServlet;
   55   import org.apache.catalina.Context;
   56   import org.apache.catalina.Globals;
   57   import org.apache.catalina.InstanceEvent;
   58   import org.apache.catalina.InstanceListener;
   59   import org.apache.catalina.LifecycleException;
   60   import org.apache.catalina.Loader;
   61   import org.apache.catalina.Wrapper;
   62   import org.apache.catalina.security.SecurityUtil;
   63   import org.apache.catalina.util.Enumerator;
   64   import org.apache.catalina.util.InstanceSupport;
   65   import org.apache.tomcat.util.log.SystemLogHandler;
   66   import org.apache.tomcat.util.modeler.Registry;
   67   
   68   /**
   69    * Standard implementation of the <b>Wrapper</b> interface that represents
   70    * an individual servlet definition.  No child Containers are allowed, and
   71    * the parent Container must be a Context.
   72    *
   73    * @author Craig R. McClanahan
   74    * @author Remy Maucherat
   75    * @version $Revision: 771014 $ $Date: 2009-05-03 03:33:01 +0200 (Sun, 03 May 2009) $
   76    */
   77   public class StandardWrapper
   78       extends ContainerBase
   79       implements ServletConfig, Wrapper, NotificationEmitter {
   80   
   81       protected static org.apache.juli.logging.Log log=
   82           org.apache.juli.logging.LogFactory.getLog( StandardWrapper.class );
   83   
   84       protected static final String[] DEFAULT_SERVLET_METHODS = new String[] {
   85                                                       "GET", "HEAD", "POST" };
   86   
   87       // ----------------------------------------------------------- Constructors
   88   
   89   
   90       /**
   91        * Create a new StandardWrapper component with the default basic Valve.
   92        */
   93       public StandardWrapper() {
   94   
   95           super();
   96           swValve=new StandardWrapperValve();
   97           pipeline.setBasic(swValve);
   98           broadcaster = new NotificationBroadcasterSupport();
   99   
  100           if (restrictedServlets == null) {
  101               restrictedServlets = new Properties();
  102               try {
  103                   InputStream is = 
  104                       this.getClass().getClassLoader().getResourceAsStream
  105                           ("org/apache/catalina/core/RestrictedServlets.properties");
  106                   if (is != null) {
  107                       restrictedServlets.load(is);
  108                   } else {
  109                       log.error(sm.getString("standardWrapper.restrictedServletsResource"));
  110                   }
  111               } catch (IOException e) {
  112                   log.error(sm.getString("standardWrapper.restrictedServletsResource"), e);
  113               }
  114           }
  115           
  116       }
  117   
  118   
  119       // ----------------------------------------------------- Instance Variables
  120   
  121   
  122       /**
  123        * The date and time at which this servlet will become available (in
  124        * milliseconds since the epoch), or zero if the servlet is available.
  125        * If this value equals Long.MAX_VALUE, the unavailability of this
  126        * servlet is considered permanent.
  127        */
  128       protected long available = 0L;
  129       
  130       /**
  131        * The broadcaster that sends j2ee notifications. 
  132        */
  133       protected NotificationBroadcasterSupport broadcaster = null;
  134       
  135       /**
  136        * The count of allocations that are currently active (even if they
  137        * are for the same instance, as will be true on a non-STM servlet).
  138        */
  139       protected AtomicInteger countAllocated = new AtomicInteger(0);
  140   
  141   
  142       /**
  143        * The facade associated with this wrapper.
  144        */
  145       protected StandardWrapperFacade facade =
  146           new StandardWrapperFacade(this);
  147   
  148   
  149       /**
  150        * The descriptive information string for this implementation.
  151        */
  152       protected static final String info =
  153           "org.apache.catalina.core.StandardWrapper/1.0";
  154   
  155   
  156       /**
  157        * The (single) initialized instance of this servlet.
  158        */
  159       protected Servlet instance = null;
  160   
  161   
  162       /**
  163        * The support object for our instance listeners.
  164        */
  165       protected InstanceSupport instanceSupport = new InstanceSupport(this);
  166   
  167   
  168       /**
  169        * The context-relative URI of the JSP file for this servlet.
  170        */
  171       protected String jspFile = null;
  172   
  173   
  174       /**
  175        * The load-on-startup order value (negative value means load on
  176        * first call) for this servlet.
  177        */
  178       protected int loadOnStartup = -1;
  179   
  180   
  181       /**
  182        * Mappings associated with the wrapper.
  183        */
  184       protected ArrayList mappings = new ArrayList();
  185   
  186   
  187       /**
  188        * The initialization parameters for this servlet, keyed by
  189        * parameter name.
  190        */
  191       protected HashMap parameters = new HashMap();
  192   
  193   
  194       /**
  195        * The security role references for this servlet, keyed by role name
  196        * used in the servlet.  The corresponding value is the role name of
  197        * the web application itself.
  198        */
  199       protected HashMap references = new HashMap();
  200   
  201   
  202       /**
  203        * The run-as identity for this servlet.
  204        */
  205       protected String runAs = null;
  206   
  207       /**
  208        * The notification sequence number.
  209        */
  210       protected long sequenceNumber = 0;
  211   
  212       /**
  213        * The fully qualified servlet class name for this servlet.
  214        */
  215       protected String servletClass = null;
  216   
  217   
  218       /**
  219        * Does this servlet implement the SingleThreadModel interface?
  220        */
  221       protected boolean singleThreadModel = false;
  222   
  223   
  224       /**
  225        * Are we unloading our servlet instance at the moment?
  226        */
  227       protected boolean unloading = false;
  228   
  229   
  230       /**
  231        * Maximum number of STM instances.
  232        */
  233       protected int maxInstances = 20;
  234   
  235   
  236       /**
  237        * Number of instances currently loaded for a STM servlet.
  238        */
  239       protected int nInstances = 0;
  240   
  241   
  242       /**
  243        * Stack containing the STM instances.
  244        */
  245       protected Stack instancePool = null;
  246   
  247       
  248       /**
  249        * Wait time for servlet unload in ms.
  250        */
  251       protected long unloadDelay = 2000;
  252       
  253   
  254       /**
  255        * True if this StandardWrapper is for the JspServlet
  256        */
  257       protected boolean isJspServlet;
  258   
  259   
  260       /**
  261        * The ObjectName of the JSP monitoring mbean
  262        */
  263       protected ObjectName jspMonitorON;
  264   
  265   
  266       /**
  267        * Should we swallow System.out
  268        */
  269       protected boolean swallowOutput = false;
  270   
  271       // To support jmx attributes
  272       protected StandardWrapperValve swValve;
  273       protected long loadTime=0;
  274       protected int classLoadTime=0;
  275       
  276       /**
  277        * Static class array used when the SecurityManager is turned on and 
  278        * <code>Servlet.init</code> is invoked.
  279        */
  280       protected static Class[] classType = new Class[]{ServletConfig.class};
  281       
  282       
  283       /**
  284        * Static class array used when the SecurityManager is turned on and 
  285        * <code>Servlet.service</code>  is invoked.
  286        */                                                 
  287       protected static Class[] classTypeUsedInService = new Class[]{
  288                                                            ServletRequest.class,
  289                                                            ServletResponse.class};
  290       
  291       /**
  292        * Restricted servlets (which can only be loaded by a privileged webapp).
  293        */
  294       protected static Properties restrictedServlets = null;
  295       
  296       
  297       // ------------------------------------------------------------- Properties
  298   
  299   
  300       /**
  301        * Return the available date/time for this servlet, in milliseconds since
  302        * the epoch.  If this date/time is Long.MAX_VALUE, it is considered to mean
  303        * that unavailability is permanent and any request for this servlet will return
  304        * an SC_NOT_FOUND error.  If this date/time is in the future, any request for
  305        * this servlet will return an SC_SERVICE_UNAVAILABLE error.  If it is zero,
  306        * the servlet is currently available.
  307        */
  308       public long getAvailable() {
  309   
  310           return (this.available);
  311   
  312       }
  313   
  314   
  315       /**
  316        * Set the available date/time for this servlet, in milliseconds since the
  317        * epoch.  If this date/time is Long.MAX_VALUE, it is considered to mean
  318        * that unavailability is permanent and any request for this servlet will return
  319        * an SC_NOT_FOUND error. If this date/time is in the future, any request for
  320        * this servlet will return an SC_SERVICE_UNAVAILABLE error.
  321        *
  322        * @param available The new available date/time
  323        */
  324       public void setAvailable(long available) {
  325   
  326           long oldAvailable = this.available;
  327           if (available > System.currentTimeMillis())
  328               this.available = available;
  329           else
  330               this.available = 0L;
  331           support.firePropertyChange("available", new Long(oldAvailable),
  332                                      new Long(this.available));
  333   
  334       }
  335   
  336   
  337       /**
  338        * Return the number of active allocations of this servlet, even if they
  339        * are all for the same instance (as will be true for servlets that do
  340        * not implement <code>SingleThreadModel</code>.
  341        */
  342       public int getCountAllocated() {
  343   
  344           return (this.countAllocated.get());
  345   
  346       }
  347   
  348   
  349       public String getEngineName() {
  350           return ((StandardContext)getParent()).getEngineName();
  351       }
  352   
  353   
  354       /**
  355        * Return descriptive information about this Container implementation and
  356        * the corresponding version number, in the format
  357        * <code>&lt;description&gt;/&lt;version&gt;</code>.
  358        */
  359       public String getInfo() {
  360   
  361           return (info);
  362   
  363       }
  364   
  365   
  366       /**
  367        * Return the InstanceSupport object for this Wrapper instance.
  368        */
  369       public InstanceSupport getInstanceSupport() {
  370   
  371           return (this.instanceSupport);
  372   
  373       }
  374   
  375   
  376       /**
  377        * Return the context-relative URI of the JSP file for this servlet.
  378        */
  379       public String getJspFile() {
  380   
  381           return (this.jspFile);
  382   
  383       }
  384   
  385   
  386       /**
  387        * Set the context-relative URI of the JSP file for this servlet.
  388        *
  389        * @param jspFile JSP file URI
  390        */
  391       public void setJspFile(String jspFile) {
  392   
  393           String oldJspFile = this.jspFile;
  394           this.jspFile = jspFile;
  395           support.firePropertyChange("jspFile", oldJspFile, this.jspFile);
  396   
  397           // Each jsp-file needs to be represented by its own JspServlet and
  398           // corresponding JspMonitoring mbean, because it may be initialized
  399           // with its own init params
  400           isJspServlet = true;
  401   
  402       }
  403   
  404   
  405       /**
  406        * Return the load-on-startup order value (negative value means
  407        * load on first call).
  408        */
  409       public int getLoadOnStartup() {
  410   
  411           if (isJspServlet && loadOnStartup < 0) {
  412               /*
  413                * JspServlet must always be preloaded, because its instance is
  414                * used during registerJMX (when registering the JSP
  415                * monitoring mbean)
  416                */
  417                return Integer.MAX_VALUE;
  418           } else {
  419               return (this.loadOnStartup);
  420           }
  421       }
  422   
  423   
  424       /**
  425        * Set the load-on-startup order value (negative value means
  426        * load on first call).
  427        *
  428        * @param value New load-on-startup value
  429        */
  430       public void setLoadOnStartup(int value) {
  431   
  432           int oldLoadOnStartup = this.loadOnStartup;
  433           this.loadOnStartup = value;
  434           support.firePropertyChange("loadOnStartup",
  435                                      new Integer(oldLoadOnStartup),
  436                                      new Integer(this.loadOnStartup));
  437   
  438       }
  439   
  440   
  441   
  442       /**
  443        * Set the load-on-startup order value from a (possibly null) string.
  444        * Per the specification, any missing or non-numeric value is converted
  445        * to a zero, so that this servlet will still be loaded at startup
  446        * time, but in an arbitrary order.
  447        *
  448        * @param value New load-on-startup value
  449        */
  450       public void setLoadOnStartupString(String value) {
  451   
  452           try {
  453               setLoadOnStartup(Integer.parseInt(value));
  454           } catch (NumberFormatException e) {
  455               setLoadOnStartup(0);
  456           }
  457       }
  458   
  459       public String getLoadOnStartupString() {
  460           return Integer.toString( getLoadOnStartup());
  461       }
  462   
  463   
  464       /**
  465        * Return maximum number of instances that will be allocated when a single
  466        * thread model servlet is used.
  467        */
  468       public int getMaxInstances() {
  469   
  470           return (this.maxInstances);
  471   
  472       }
  473   
  474   
  475       /**
  476        * Set the maximum number of instances that will be allocated when a single
  477        * thread model servlet is used.
  478        *
  479        * @param maxInstances New value of maxInstances
  480        */
  481       public void setMaxInstances(int maxInstances) {
  482   
  483           int oldMaxInstances = this.maxInstances;
  484           this.maxInstances = maxInstances;
  485           support.firePropertyChange("maxInstances", oldMaxInstances,
  486                                      this.maxInstances);
  487   
  488       }
  489   
  490   
  491       /**
  492        * Set the parent Container of this Wrapper, but only if it is a Context.
  493        *
  494        * @param container Proposed parent Container
  495        */
  496       public void setParent(Container container) {
  497   
  498           if ((container != null) &&
  499               !(container instanceof Context))
  500               throw new IllegalArgumentException
  501                   (sm.getString("standardWrapper.notContext"));
  502           if (container instanceof StandardContext) {
  503               swallowOutput = ((StandardContext)container).getSwallowOutput();
  504               unloadDelay = ((StandardContext)container).getUnloadDelay();
  505           }
  506           super.setParent(container);
  507   
  508       }
  509   
  510   
  511       /**
  512        * Return the run-as identity for this servlet.
  513        */
  514       public String getRunAs() {
  515   
  516           return (this.runAs);
  517   
  518       }
  519   
  520   
  521       /**
  522        * Set the run-as identity for this servlet.
  523        *
  524        * @param runAs New run-as identity value
  525        */
  526       public void setRunAs(String runAs) {
  527   
  528           String oldRunAs = this.runAs;
  529           this.runAs = runAs;
  530           support.firePropertyChange("runAs", oldRunAs, this.runAs);
  531   
  532       }
  533   
  534   
  535       /**
  536        * Return the fully qualified servlet class name for this servlet.
  537        */
  538       public String getServletClass() {
  539   
  540           return (this.servletClass);
  541   
  542       }
  543   
  544   
  545       /**
  546        * Set the fully qualified servlet class name for this servlet.
  547        *
  548        * @param servletClass Servlet class name
  549        */
  550       public void setServletClass(String servletClass) {
  551   
  552           String oldServletClass = this.servletClass;
  553           this.servletClass = servletClass;
  554           support.firePropertyChange("servletClass", oldServletClass,
  555                                      this.servletClass);
  556           if (Constants.JSP_SERVLET_CLASS.equals(servletClass)) {
  557               isJspServlet = true;
  558           }
  559       }
  560   
  561   
  562   
  563       /**
  564        * Set the name of this servlet.  This is an alias for the normal
  565        * <code>Container.setName()</code> method, and complements the
  566        * <code>getServletName()</code> method required by the
  567        * <code>ServletConfig</code> interface.
  568        *
  569        * @param name The new name of this servlet
  570        */
  571       public void setServletName(String name) {
  572   
  573           setName(name);
  574   
  575       }
  576   
  577   
  578       /**
  579        * Return <code>true</code> if the servlet class represented by this
  580        * component implements the <code>SingleThreadModel</code> interface.
  581        */
  582       public boolean isSingleThreadModel() {
  583   
  584           try {
  585               loadServlet();
  586           } catch (Throwable t) {
  587               ;
  588           }
  589           return (singleThreadModel);
  590   
  591       }
  592   
  593   
  594       /**
  595        * Is this servlet currently unavailable?
  596        */
  597       public boolean isUnavailable() {
  598   
  599           if (available == 0L)
  600               return (false);
  601           else if (available <= System.currentTimeMillis()) {
  602               available = 0L;
  603               return (false);
  604           } else
  605               return (true);
  606   
  607       }
  608   
  609   
  610       /**
  611        * Gets the names of the methods supported by the underlying servlet.
  612        *
  613        * This is the same set of methods included in the Allow response header
  614        * in response to an OPTIONS request method processed by the underlying
  615        * servlet.
  616        *
  617        * @return Array of names of the methods supported by the underlying
  618        * servlet
  619        */
  620       public String[] getServletMethods() throws ServletException {
  621   
  622           Class servletClazz = loadServlet().getClass();
  623           if (!javax.servlet.http.HttpServlet.class.isAssignableFrom(
  624                                                           servletClazz)) {
  625               return DEFAULT_SERVLET_METHODS;
  626           }
  627   
  628           HashSet allow = new HashSet();
  629           allow.add("TRACE");
  630           allow.add("OPTIONS");
  631   	
  632           Method[] methods = getAllDeclaredMethods(servletClazz);
  633           for (int i=0; methods != null && i<methods.length; i++) {
  634               Method m = methods[i];
  635   	    
  636               if (m.getName().equals("doGet")) {
  637                   allow.add("GET");
  638                   allow.add("HEAD");
  639               } else if (m.getName().equals("doPost")) {
  640                   allow.add("POST");
  641               } else if (m.getName().equals("doPut")) {
  642                   allow.add("PUT");
  643               } else if (m.getName().equals("doDelete")) {
  644                   allow.add("DELETE");
  645               }
  646           }
  647   
  648           String[] methodNames = new String[allow.size()];
  649           return (String[]) allow.toArray(methodNames);
  650   
  651       }
  652   
  653   
  654       // --------------------------------------------------------- Public Methods
  655   
  656   
  657       /**
  658        * Execute a periodic task, such as reloading, etc. This method will be
  659        * invoked inside the classloading context of this container. Unexpected
  660        * throwables will be caught and logged.
  661        */
  662       public void backgroundProcess() {
  663           super.backgroundProcess();
  664           
  665           if (!started)
  666               return;
  667           
  668           if (getServlet() != null && (getServlet() instanceof PeriodicEventListener)) {
  669               ((PeriodicEventListener) getServlet()).periodicEvent();
  670           }
  671       }
  672       
  673       
  674       /**
  675        * Extract the root cause from a servlet exception.
  676        * 
  677        * @param e The servlet exception
  678        */
  679       public static Throwable getRootCause(ServletException e) {
  680           Throwable rootCause = e;
  681           Throwable rootCauseCheck = null;
  682           // Extra aggressive rootCause finding
  683           int loops = 0;
  684           do {
  685               loops++;
  686               rootCauseCheck = rootCause.getCause();
  687               if (rootCauseCheck != null)
  688                   rootCause = rootCauseCheck;
  689           } while (rootCauseCheck != null && (loops < 20));
  690           return rootCause;
  691       }
  692   
  693   
  694       /**
  695        * Refuse to add a child Container, because Wrappers are the lowest level
  696        * of the Container hierarchy.
  697        *
  698        * @param child Child container to be added
  699        */
  700       public void addChild(Container child) {
  701   
  702           throw new IllegalStateException
  703               (sm.getString("standardWrapper.notChild"));
  704   
  705       }
  706   
  707   
  708       /**
  709        * Add a new servlet initialization parameter for this servlet.
  710        *
  711        * @param name Name of this initialization parameter to add
  712        * @param value Value of this initialization parameter to add
  713        */
  714       public void addInitParameter(String name, String value) {
  715   
  716           synchronized (parameters) {
  717               parameters.put(name, value);
  718           }
  719           fireContainerEvent("addInitParameter", name);
  720   
  721       }
  722   
  723   
  724       /**
  725        * Add a new listener interested in InstanceEvents.
  726        *
  727        * @param listener The new listener
  728        */
  729       public void addInstanceListener(InstanceListener listener) {
  730   
  731           instanceSupport.addInstanceListener(listener);
  732   
  733       }
  734   
  735   
  736       /**
  737        * Add a mapping associated with the Wrapper.
  738        *
  739        * @param mapping The new wrapper mapping
  740        */
  741       public void addMapping(String mapping) {
  742   
  743           synchronized (mappings) {
  744               mappings.add(mapping);
  745           }
  746           fireContainerEvent("addMapping", mapping);
  747   
  748       }
  749   
  750   
  751       /**
  752        * Add a new security role reference record to the set of records for
  753        * this servlet.
  754        *
  755        * @param name Role name used within this servlet
  756        * @param link Role name used within the web application
  757        */
  758       public void addSecurityReference(String name, String link) {
  759   
  760           synchronized (references) {
  761               references.put(name, link);
  762           }
  763           fireContainerEvent("addSecurityReference", name);
  764   
  765       }
  766   
  767   
  768       /**
  769        * Return the associated servlet instance.
  770        */
  771       public Servlet getServlet() {
  772           return instance;
  773       }
  774       
  775       
  776       /**
  777        * Allocate an initialized instance of this Servlet that is ready to have
  778        * its <code>service()</code> method called.  If the servlet class does
  779        * not implement <code>SingleThreadModel</code>, the (only) initialized
  780        * instance may be returned immediately.  If the servlet class implements
  781        * <code>SingleThreadModel</code>, the Wrapper implementation must ensure
  782        * that this instance is not allocated again until it is deallocated by a
  783        * call to <code>deallocate()</code>.
  784        *
  785        * @exception ServletException if the servlet init() method threw
  786        *  an exception
  787        * @exception ServletException if a loading error occurs
  788        */
  789       public Servlet allocate() throws ServletException {
  790   
  791           // If we are currently unloading this servlet, throw an exception
  792           if (unloading)
  793               throw new ServletException
  794                 (sm.getString("standardWrapper.unloading", getName()));
  795   
  796           boolean newInstance = false;
  797           
  798           // If not SingleThreadedModel, return the same instance every time
  799           if (!singleThreadModel) {
  800   
  801               // Load and initialize our instance if necessary
  802               if (instance == null) {
  803                   synchronized (this) {
  804                       if (instance == null) {
  805                           try {
  806                               if (log.isDebugEnabled())
  807                                   log.debug("Allocating non-STM instance");
  808   
  809                               instance = loadServlet();
  810                               // For non-STM, increment here to prevent a race
  811                               // condition with unload. Bug 43683, test case #3
  812                               if (!singleThreadModel) {
  813                                   newInstance = true;
  814                                   countAllocated.incrementAndGet();
  815                               }
  816                           } catch (ServletException e) {
  817                               throw e;
  818                           } catch (Throwable e) {
  819                               throw new ServletException
  820                                   (sm.getString("standardWrapper.allocate"), e);
  821                           }
  822                       }
  823                   }
  824               }
  825   
  826               if (!singleThreadModel) {
  827                   if (log.isTraceEnabled())
  828                       log.trace("  Returning non-STM instance");
  829                   // For new instances, count will have been incremented at the
  830                   // time of creation
  831                   if (!newInstance) {
  832                       countAllocated.incrementAndGet();
  833                   }
  834                   return (instance);
  835               }
  836           }
  837   
  838           synchronized (instancePool) {
  839   
  840               while (countAllocated.get() >= nInstances) {
  841                   // Allocate a new instance if possible, or else wait
  842                   if (nInstances < maxInstances) {
  843                       try {
  844                           instancePool.push(loadServlet());
  845                           nInstances++;
  846                       } catch (ServletException e) {
  847                           throw e;
  848                       } catch (Throwable e) {
  849                           throw new ServletException
  850                               (sm.getString("standardWrapper.allocate"), e);
  851                       }
  852                   } else {
  853                       try {
  854                           instancePool.wait();
  855                       } catch (InterruptedException e) {
  856                           ;
  857                       }
  858                   }
  859               }
  860               if (log.isTraceEnabled())
  861                   log.trace("  Returning allocated STM instance");
  862               countAllocated.incrementAndGet();
  863               return (Servlet) instancePool.pop();
  864   
  865           }
  866   
  867       }
  868   
  869   
  870       /**
  871        * Return this previously allocated servlet to the pool of available
  872        * instances.  If this servlet class does not implement SingleThreadModel,
  873        * no action is actually required.
  874        *
  875        * @param servlet The servlet to be returned
  876        *
  877        * @exception ServletException if a deallocation error occurs
  878        */
  879       public void deallocate(Servlet servlet) throws ServletException {
  880   
  881           // If not SingleThreadModel, no action is required
  882           if (!singleThreadModel) {
  883               countAllocated.decrementAndGet();
  884               return;
  885           }
  886   
  887           // Unlock and free this instance
  888           synchronized (instancePool) {
  889               countAllocated.decrementAndGet();
  890               instancePool.push(servlet);
  891               instancePool.notify();
  892           }
  893   
  894       }
  895   
  896   
  897       /**
  898        * Return the value for the specified initialization parameter name,
  899        * if any; otherwise return <code>null</code>.
  900        *
  901        * @param name Name of the requested initialization parameter
  902        */
  903       public String findInitParameter(String name) {
  904   
  905           synchronized (parameters) {
  906               return ((String) parameters.get(name));
  907           }
  908   
  909       }
  910   
  911   
  912       /**
  913        * Return the names of all defined initialization parameters for this
  914        * servlet.
  915        */
  916       public String[] findInitParameters() {
  917   
  918           synchronized (parameters) {
  919               String results[] = new String[parameters.size()];
  920               return ((String[]) parameters.keySet().toArray(results));
  921           }
  922   
  923       }
  924   
  925   
  926       /**
  927        * Return the mappings associated with this wrapper.
  928        */
  929       public String[] findMappings() {
  930   
  931           synchronized (mappings) {
  932               return (String[]) mappings.toArray(new String[mappings.size()]);
  933           }
  934   
  935       }
  936   
  937   
  938       /**
  939        * Return the security role link for the specified security role
  940        * reference name, if any; otherwise return <code>null</code>.
  941        *
  942        * @param name Security role reference used within this servlet
  943        */
  944       public String findSecurityReference(String name) {
  945   
  946           synchronized (references) {
  947               return ((String) references.get(name));
  948           }
  949   
  950       }
  951   
  952   
  953       /**
  954        * Return the set of security role reference names associated with
  955        * this servlet, if any; otherwise return a zero-length array.
  956        */
  957       public String[] findSecurityReferences() {
  958   
  959           synchronized (references) {
  960               String results[] = new String[references.size()];
  961               return ((String[]) references.keySet().toArray(results));
  962           }
  963   
  964       }
  965   
  966   
  967       /**
  968        * FIXME: Fooling introspection ...
  969        */
  970       public Wrapper findMappingObject() {
  971           return (Wrapper) getMappingObject();
  972       }
  973   
  974   
  975       /**
  976        * Load and initialize an instance of this servlet, if there is not already
  977        * at least one initialized instance.  This can be used, for example, to
  978        * load servlets that are marked in the deployment descriptor to be loaded
  979        * at server startup time.
  980        * <p>
  981        * <b>IMPLEMENTATION NOTE</b>:  Servlets whose classnames begin with
  982        * <code>org.apache.catalina.</code> (so-called "container" servlets)
  983        * are loaded by the same classloader that loaded this class, rather than
  984        * the classloader for the current web application.
  985        * This gives such classes access to Catalina internals, which are
  986        * prevented for classes loaded for web applications.
  987        *
  988        * @exception ServletException if the servlet init() method threw
  989        *  an exception
  990        * @exception ServletException if some other loading problem occurs
  991        */
  992       public synchronized void load() throws ServletException {
  993           instance = loadServlet();
  994       }
  995   
  996   
  997       /**
  998        * Load and initialize an instance of this servlet, if there is not already
  999        * at least one initialized instance.  This can be used, for example, to
 1000        * load servlets that are marked in the deployment descriptor to be loaded
 1001        * at server startup time.
 1002        */
 1003       public synchronized Servlet loadServlet() throws ServletException {
 1004   
 1005           // Nothing to do if we already have an instance or an instance pool
 1006           if (!singleThreadModel && (instance != null))
 1007               return instance;
 1008   
 1009           PrintStream out = System.out;
 1010           if (swallowOutput) {
 1011               SystemLogHandler.startCapture();
 1012           }
 1013   
 1014           Servlet servlet;
 1015           try {
 1016               long t1=System.currentTimeMillis();
 1017               // If this "servlet" is really a JSP file, get the right class.
 1018               // HOLD YOUR NOSE - this is a kludge that avoids having to do special
 1019               // case Catalina-specific code in Jasper - it also requires that the
 1020               // servlet path be replaced by the <jsp-file> element content in
 1021               // order to be completely effective
 1022               String actualClass = servletClass;
 1023               if ((actualClass == null) && (jspFile != null)) {
 1024                   Wrapper jspWrapper = (Wrapper)
 1025                       ((Context) getParent()).findChild(Constants.JSP_SERVLET_NAME);
 1026                   if (jspWrapper != null) {
 1027                       actualClass = jspWrapper.getServletClass();
 1028                       // Merge init parameters
 1029                       String paramNames[] = jspWrapper.findInitParameters();
 1030                       for (int i = 0; i < paramNames.length; i++) {
 1031                           if (parameters.get(paramNames[i]) == null) {
 1032                               parameters.put
 1033                                   (paramNames[i], 
 1034                                    jspWrapper.findInitParameter(paramNames[i]));
 1035                           }
 1036                       }
 1037                   }
 1038               }
 1039   
 1040               // Complain if no servlet class has been specified
 1041               if (actualClass == null) {
 1042                   unavailable(null);
 1043                   throw new ServletException
 1044                       (sm.getString("standardWrapper.notClass", getName()));
 1045               }
 1046   
 1047               // Acquire an instance of the class loader to be used
 1048               Loader loader = getLoader();
 1049               if (loader == null) {
 1050                   unavailable(null);
 1051                   throw new ServletException
 1052                       (sm.getString("standardWrapper.missingLoader", getName()));
 1053               }
 1054   
 1055               ClassLoader classLoader = loader.getClassLoader();
 1056   
 1057               // Special case class loader for a container provided servlet
 1058               //  
 1059               if (isContainerProvidedServlet(actualClass) && 
 1060                       ! ((Context)getParent()).getPrivileged() ) {
 1061                   // If it is a priviledged context - using its own
 1062                   // class loader will work, since it's a child of the container
 1063                   // loader
 1064                   classLoader = this.getClass().getClassLoader();
 1065               }
 1066   
 1067               // Load the specified servlet class from the appropriate class loader
 1068               Class classClass = null;
 1069               try {
 1070                   if (SecurityUtil.isPackageProtectionEnabled()){
 1071                       final ClassLoader fclassLoader = classLoader;
 1072                       final String factualClass = actualClass;
 1073                       try{
 1074                           classClass = (Class)AccessController.doPrivileged(
 1075                                   new PrivilegedExceptionAction(){
 1076                                       public Object run() throws Exception{
 1077                                           if (fclassLoader != null) {
 1078                                               return fclassLoader.loadClass(factualClass);
 1079                                           } else {
 1080                                               return Class.forName(factualClass);
 1081                                           }
 1082                                       }
 1083                           });
 1084                       } catch(PrivilegedActionException pax){
 1085                           Exception ex = pax.getException();
 1086                           if (ex instanceof ClassNotFoundException){
 1087                               throw (ClassNotFoundException)ex;
 1088                           } else {
 1089                               getServletContext().log( "Error loading "
 1090                                   + fclassLoader + " " + factualClass, ex );
 1091                           }
 1092                       }
 1093                   } else {
 1094                       if (classLoader != null) {
 1095                           classClass = classLoader.loadClass(actualClass);
 1096                       } else {
 1097                           classClass = Class.forName(actualClass);
 1098                       }
 1099                   }
 1100               } catch (ClassNotFoundException e) {
 1101                   unavailable(null);
 1102                   getServletContext().log( "Error loading " + classLoader + " " + actualClass, e );
 1103                   throw new ServletException
 1104                       (sm.getString("standardWrapper.missingClass", actualClass),
 1105                        e);
 1106               }
 1107   
 1108               if (classClass == null) {
 1109                   unavailable(null);
 1110                   throw new ServletException
 1111                       (sm.getString("standardWrapper.missingClass", actualClass));
 1112               }
 1113   
 1114               // Instantiate and initialize an instance of the servlet class itself
 1115               try {
 1116                   servlet = (Servlet) classClass.newInstance();
 1117                   // Annotation processing
 1118                   if (!((Context) getParent()).getIgnoreAnnotations()) {
 1119                       if (getParent() instanceof StandardContext) {
 1120                          ((StandardContext)getParent()).getAnnotationProcessor().processAnnotations(servlet);
 1121                          ((StandardContext)getParent()).getAnnotationProcessor().postConstruct(servlet);
 1122                       }
 1123                   }
 1124               } catch (ClassCastException e) {
 1125                   unavailable(null);
 1126                   // Restore the context ClassLoader
 1127                   throw new ServletException
 1128                       (sm.getString("standardWrapper.notServlet", actualClass), e);
 1129               } catch (Throwable e) {
 1130                   unavailable(null);
 1131                 
 1132                   // Added extra log statement for Bugzilla 36630:
 1133                   // http://issues.apache.org/bugzilla/show_bug.cgi?id=36630
 1134                   if(log.isDebugEnabled()) {
 1135                       log.debug(sm.getString("standardWrapper.instantiate", actualClass), e);
 1136                   }
 1137   
 1138                   // Restore the context ClassLoader
 1139                   throw new ServletException
 1140                       (sm.getString("standardWrapper.instantiate", actualClass), e);
 1141               }
 1142   
 1143               // Check if loading the servlet in this web application should be
 1144               // allowed
 1145               if (!isServletAllowed(servlet)) {
 1146                   throw new SecurityException
 1147                       (sm.getString("standardWrapper.privilegedServlet",
 1148                                     actualClass));
 1149               }
 1150   
 1151               // Special handling for ContainerServlet instances
 1152               if ((servlet instanceof ContainerServlet) &&
 1153                     (isContainerProvidedServlet(actualClass) ||
 1154                       ((Context)getParent()).getPrivileged() )) {
 1155                   ((ContainerServlet) servlet).setWrapper(this);
 1156               }
 1157   
 1158               classLoadTime=(int) (System.currentTimeMillis() -t1);
 1159               // Call the initialization method of this servlet
 1160               try {
 1161                   instanceSupport.fireInstanceEvent(InstanceEvent.BEFORE_INIT_EVENT,
 1162                                                     servlet);
 1163   
 1164                   if( Globals.IS_SECURITY_ENABLED) {
 1165   
 1166                       Object[] args = new Object[]{((ServletConfig)facade)};
 1167                       SecurityUtil.doAsPrivilege("init",
 1168                                                  servlet,
 1169                                                  classType,
 1170                                                  args);
 1171                       args = null;
 1172                   } else {
 1173                       servlet.init(facade);
 1174                   }
 1175   
 1176                   // Invoke jspInit on JSP pages
 1177                   if ((loadOnStartup >= 0) && (jspFile != null)) {
 1178                       // Invoking jspInit
 1179                       DummyRequest req = new DummyRequest();
 1180                       req.setServletPath(jspFile);
 1181                       req.setQueryString(Constants.PRECOMPILE + "=true");
 1182                       DummyResponse res = new DummyResponse();
 1183   
 1184                       if( Globals.IS_SECURITY_ENABLED) {
 1185                           Object[] args = new Object[]{req, res};
 1186                           SecurityUtil.doAsPrivilege("service",
 1187                                                      servlet,
 1188                                                      classTypeUsedInService,
 1189                                                      args);
 1190                           args = null;
 1191                       } else {
 1192                           servlet.service(req, res);
 1193                       }
 1194                   }
 1195                   instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT,
 1196                                                     servlet);
 1197               } catch (UnavailableException f) {
 1198                   instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT,
 1199                                                     servlet, f);
 1200                   unavailable(f);
 1201                   throw f;
 1202               } catch (ServletException f) {
 1203                   instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT,
 1204                                                     servlet, f);
 1205                   // If the servlet wanted to be unavailable it would have
 1206                   // said so, so do not call unavailable(null).
 1207                   throw f;
 1208               } catch (Throwable f) {
 1209                   getServletContext().log("StandardWrapper.Throwable", f );
 1210                   instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT,
 1211                                                     servlet, f);
 1212                   // If the servlet wanted to be unavailable it would have
 1213                   // said so, so do not call unavailable(null).
 1214                   throw new ServletException
 1215                       (sm.getString("standardWrapper.initException", getName()), f);
 1216               }
 1217   
 1218               // Register our newly initialized instance
 1219               singleThreadModel = servlet instanceof SingleThreadModel;
 1220               if (singleThreadModel) {
 1221                   if (instancePool == null)
 1222                       instancePool = new Stack();
 1223               }
 1224               fireContainerEvent("load", this);
 1225   
 1226               loadTime=System.currentTimeMillis() -t1;
 1227           } finally {
 1228               if (swallowOutput) {
 1229                   String log = SystemLogHandler.stopCapture();
 1230                   if (log != null && log.length() > 0) {
 1231                       if (getServletContext() != null) {
 1232                           getServletContext().log(log);
 1233                       } else {
 1234                           out.println(log);
 1235                       }
 1236                   }
 1237               }
 1238           }
 1239           return servlet;
 1240   
 1241       }
 1242   
 1243   
 1244       /**
 1245        * Remove the specified initialization parameter from this servlet.
 1246        *
 1247        * @param name Name of the initialization parameter to remove
 1248        */
 1249       public void removeInitParameter(String name) {
 1250   
 1251           synchronized (parameters) {
 1252               parameters.remove(name);
 1253           }
 1254           fireContainerEvent("removeInitParameter", name);
 1255   
 1256       }
 1257   
 1258   
 1259       /**
 1260        * Remove a listener no longer interested in InstanceEvents.
 1261        *
 1262        * @param listener The listener to remove
 1263        */
 1264       public void removeInstanceListener(InstanceListener listener) {
 1265   
 1266           instanceSupport.removeInstanceListener(listener);
 1267   
 1268       }
 1269   
 1270   
 1271       /**
 1272        * Remove a mapping associated with the wrapper.
 1273        *
 1274        * @param mapping The pattern to remove
 1275        */
 1276       public void removeMapping(String mapping) {
 1277   
 1278           synchronized (mappings) {
 1279               mappings.remove(mapping);
 1280           }
 1281           fireContainerEvent("removeMapping", mapping);
 1282   
 1283       }
 1284   
 1285   
 1286       /**
 1287        * Remove any security role reference for the specified role name.
 1288        *
 1289        * @param name Security role used within this servlet to be removed
 1290        */
 1291       public void removeSecurityReference(String name) {
 1292   
 1293           synchronized (references) {
 1294               references.remove(name);
 1295           }
 1296           fireContainerEvent("removeSecurityReference", name);
 1297   
 1298       }
 1299   
 1300   
 1301       /**
 1302        * Return a String representation of this component.
 1303        */
 1304       public String toString() {
 1305   
 1306           StringBuffer sb = new StringBuffer();
 1307           if (getParent() != null) {
 1308               sb.append(getParent().toString());
 1309               sb.append(".");
 1310           }
 1311           sb.append("StandardWrapper[");
 1312           sb.append(getName());
 1313           sb.append("]");
 1314           return (sb.toString());
 1315   
 1316       }
 1317   
 1318   
 1319       /**
 1320        * Process an UnavailableException, marking this servlet as unavailable
 1321        * for the specified amount of time.
 1322        *
 1323        * @param unavailable The exception that occurred, or <code>null</code>
 1324        *  to mark this servlet as permanently unavailable
 1325        */
 1326       public void unavailable(UnavailableException unavailable) {
 1327           getServletContext().log(sm.getString("standardWrapper.unavailable", getName()));
 1328           if (unavailable == null)
 1329               setAvailable(Long.MAX_VALUE);
 1330           else if (unavailable.isPermanent())
 1331               setAvailable(Long.MAX_VALUE);
 1332           else {
 1333               int unavailableSeconds = unavailable.getUnavailableSeconds();
 1334               if (unavailableSeconds <= 0)
 1335                   unavailableSeconds = 60;        // Arbitrary default
 1336               setAvailable(System.currentTimeMillis() +
 1337                            (unavailableSeconds * 1000L));
 1338           }
 1339   
 1340       }
 1341   
 1342   
 1343       /**
 1344        * Unload all initialized instances of this servlet, after calling the
 1345        * <code>destroy()</code> method for each instance.  This can be used,
 1346        * for example, prior to shutting down the entire servlet engine, or
 1347        * prior to reloading all of the classes from the Loader associated with
 1348        * our Loader's repository.
 1349        *
 1350        * @exception ServletException if an exception is thrown by the
 1351        *  destroy() method
 1352        */
 1353       public synchronized void unload() throws ServletException {
 1354   
 1355           // Nothing to do if we have never loaded the instance
 1356           if (!singleThreadModel && (instance == null))
 1357               return;
 1358           unloading = true;
 1359   
 1360           // Loaf a while if the current instance is allocated
 1361           // (possibly more than once if non-STM)
 1362           if (countAllocated.get() > 0) {
 1363               int nRetries = 0;
 1364               long delay = unloadDelay / 20;
 1365               while ((nRetries < 21) && (countAllocated.get() > 0)) {
 1366                   if ((nRetries % 10) == 0) {
 1367                       log.info(sm.getString("standardWrapper.waiting",
 1368                                             countAllocated.toString()));
 1369                   }
 1370                   try {
 1371                       Thread.sleep(delay);
 1372                   } catch (InterruptedException e) {
 1373                       ;
 1374                   }
 1375                   nRetries++;
 1376               }
 1377           }
 1378   
 1379           PrintStream out = System.out;
 1380           if (swallowOutput) {
 1381               SystemLogHandler.startCapture();
 1382           }
 1383   
 1384           // Call the servlet destroy() method
 1385           try {
 1386               instanceSupport.fireInstanceEvent
 1387                 (InstanceEvent.BEFORE_DESTROY_EVENT, instance);
 1388   
 1389               if( Globals.IS_SECURITY_ENABLED) {
 1390                   SecurityUtil.doAsPrivilege("destroy",
 1391                                              instance);
 1392                   SecurityUtil.remove(instance);                           
 1393               } else {
 1394                   instance.destroy();
 1395               }
 1396               
 1397               instanceSupport.fireInstanceEvent
 1398                 (InstanceEvent.AFTER_DESTROY_EVENT, instance);
 1399   
 1400               // Annotation processing
 1401               if (!((Context) getParent()).getIgnoreAnnotations()) {
 1402                  ((StandardContext)getParent()).getAnnotationProcessor().preDestroy(instance);
 1403               }
 1404   
 1405           } catch (Throwable t) {
 1406               instanceSupport.fireInstanceEvent
 1407                 (InstanceEvent.AFTER_DESTROY_EVENT, instance, t);
 1408               instance = null;
 1409               instancePool = null;
 1410               nInstances = 0;
 1411               fireContainerEvent("unload", this);
 1412               unloading = false;
 1413               throw new ServletException
 1414                   (sm.getString("standardWrapper.destroyException", getName()),
 1415                    t);
 1416           } finally {
 1417               // Write captured output
 1418               if (swallowOutput) {
 1419                   String log = SystemLogHandler.stopCapture();
 1420                   if (log != null && log.length() > 0) {
 1421                       if (getServletContext() != null) {
 1422                           getServletContext().log(log);
 1423                       } else {
 1424                           out.println(log);
 1425                       }
 1426                   }
 1427               }
 1428           }
 1429   
 1430           // Deregister the destroyed instance
 1431           instance = null;
 1432   
 1433           if (singleThreadModel && (instancePool != null)) {
 1434               try {
 1435                   while (!instancePool.isEmpty()) {
 1436                       Servlet s = (Servlet) instancePool.pop();
 1437                       if (Globals.IS_SECURITY_ENABLED) {
 1438                           SecurityUtil.doAsPrivilege("destroy", s);
 1439                           SecurityUtil.remove(instance);                           
 1440                       } else {
 1441                           s.destroy();
 1442                       }
 1443                       // Annotation processing
 1444                       if (!((Context) getParent()).getIgnoreAnnotations()) {
 1445                          ((StandardContext)getParent()).getAnnotationProcessor().preDestroy(s);
 1446                       }
 1447                   }
 1448               } catch (Throwable t) {
 1449                   instancePool = null;
 1450                   nInstances = 0;
 1451                   unloading = false;
 1452                   fireContainerEvent("unload", this);
 1453                   throw new ServletException
 1454                       (sm.getString("standardWrapper.destroyException",
 1455                                     getName()), t);
 1456               }
 1457               instancePool = null;
 1458               nInstances = 0;
 1459           }
 1460   
 1461           singleThreadModel = false;
 1462   
 1463           unloading = false;
 1464           fireContainerEvent("unload", this);
 1465   
 1466       }
 1467   
 1468   
 1469       // -------------------------------------------------- ServletConfig Methods
 1470   
 1471   
 1472       /**
 1473        * Return the initialization parameter value for the specified name,
 1474        * if any; otherwise return <code>null</code>.
 1475        *
 1476        * @param name Name of the initialization parameter to retrieve
 1477        */
 1478       public String getInitParameter(String name) {
 1479   
 1480           return (findInitParameter(name));
 1481   
 1482       }
 1483   
 1484   
 1485       /**
 1486        * Return the set of initialization parameter names defined for this
 1487        * servlet.  If none are defined, an empty Enumeration is returned.
 1488        */
 1489       public Enumeration getInitParameterNames() {
 1490   
 1491           synchronized (parameters) {
 1492               return (new Enumerator(parameters.keySet()));
 1493           }
 1494   
 1495       }
 1496   
 1497   
 1498       /**
 1499        * Return the servlet context with which this servlet is associated.
 1500        */
 1501       public ServletContext getServletContext() {
 1502   
 1503           if (parent == null)
 1504               return (null);
 1505           else if (!(parent instanceof Context))
 1506               return (null);
 1507           else
 1508               return (((Context) parent).getServletContext());
 1509   
 1510       }
 1511   
 1512   
 1513       /**
 1514        * Return the name of this servlet.
 1515        */
 1516       public String getServletName() {
 1517   
 1518           return (getName());
 1519   
 1520       }
 1521   
 1522       public long getProcessingTime() {
 1523           return swValve.getProcessingTime();
 1524       }
 1525   
 1526       public void setProcessingTime(long processingTime) {
 1527           swValve.setProcessingTime(processingTime);
 1528       }
 1529   
 1530       public long getMaxTime() {
 1531           return swValve.getMaxTime();
 1532       }
 1533   
 1534       public void setMaxTime(long maxTime) {
 1535           swValve.setMaxTime(maxTime);
 1536       }
 1537   
 1538       public long getMinTime() {
 1539           return swValve.getMinTime();
 1540       }
 1541   
 1542       public void setMinTime(long minTime) {
 1543           swValve.setMinTime(minTime);
 1544       }
 1545   
 1546       public int getRequestCount() {
 1547           return swValve.getRequestCount();
 1548       }
 1549   
 1550       public void setRequestCount(int requestCount) {
 1551           swValve.setRequestCount(requestCount);
 1552       }
 1553   
 1554       public int getErrorCount() {
 1555           return swValve.getErrorCount();
 1556       }
 1557   
 1558       public void setErrorCount(int errorCount) {
 1559              swValve.setErrorCount(errorCount);
 1560       }
 1561   
 1562       /**
 1563        * Increment the error count used for monitoring.
 1564        */
 1565       public void incrementErrorCount(){
 1566           swValve.setErrorCount(swValve.getErrorCount() + 1);
 1567       }
 1568   
 1569       public long getLoadTime() {
 1570           return loadTime;
 1571       }
 1572   
 1573       public void setLoadTime(long loadTime) {
 1574           this.loadTime = loadTime;
 1575       }
 1576   
 1577       public int getClassLoadTime() {
 1578           return classLoadTime;
 1579       }
 1580   
 1581       // -------------------------------------------------------- Package Methods
 1582   
 1583   
 1584       // -------------------------------------------------------- protected Methods
 1585   
 1586   
 1587       /**
 1588        * Add a default Mapper implementation if none have been configured
 1589        * explicitly.
 1590        *
 1591        * @param mapperClass Java class name of the default Mapper
 1592        */
 1593       protected void addDefaultMapper(String mapperClass) {
 1594   
 1595           ;       // No need for a default Mapper on a Wrapper
 1596   
 1597       }
 1598   
 1599   
 1600       /**
 1601        * Return <code>true</code> if the specified class name represents a
 1602        * container provided servlet class that should be loaded by the
 1603        * server class loader.
 1604        *
 1605        * @param classname Name of the class to be checked
 1606        */
 1607       protected boolean isContainerProvidedServlet(String classname) {
 1608   
 1609           if (classname.startsWith("org.apache.catalina.")) {
 1610               return (true);
 1611           }
 1612           try {
 1613               Class clazz =
 1614                   this.getClass().getClassLoader().loadClass(classname);
 1615               return (ContainerServlet.class.isAssignableFrom(clazz));
 1616           } catch (Throwable t) {
 1617               return (false);
 1618           }
 1619   
 1620       }
 1621   
 1622   
 1623       /**
 1624        * Return <code>true</code> if loading this servlet is allowed.
 1625        */
 1626       protected boolean isServletAllowed(Object servlet) {
 1627   
 1628           // Privileged webapps may load all servlets without restriction
 1629           if (((Context) getParent()).getPrivileged()) {
 1630               return true;
 1631           }
 1632           
 1633           if (servlet instanceof ContainerServlet) {
 1634               return (false);
 1635           }
 1636   
 1637           Class clazz = servlet.getClass();
 1638           while (clazz != null && !clazz.getName().equals("javax.servlet.http.HttpServlet")) {
 1639               if ("restricted".equals(restrictedServlets.getProperty(clazz.getName()))) {
 1640                   return (false);
 1641               }
 1642               clazz = clazz.getSuperclass();
 1643           }
 1644           
 1645           return (true);
 1646   
 1647       }
 1648   
 1649   
 1650       protected Method[] getAllDeclaredMethods(Class c) {
 1651   
 1652           if (c.equals(javax.servlet.http.HttpServlet.class)) {
 1653               return null;
 1654           }
 1655   
 1656           Method[] parentMethods = getAllDeclaredMethods(c.getSuperclass());
 1657   
 1658           Method[] thisMethods = c.getDeclaredMethods();
 1659           if (thisMethods == null) {
 1660               return parentMethods;
 1661           }
 1662   
 1663           if ((parentMethods != null) && (parentMethods.length > 0)) {
 1664               Method[] allMethods =
 1665                   new Method[parentMethods.length + thisMethods.length];
 1666   	    System.arraycopy(parentMethods, 0, allMethods, 0,
 1667                                parentMethods.length);
 1668   	    System.arraycopy(thisMethods, 0, allMethods, parentMethods.length,
 1669                                thisMethods.length);
 1670   
 1671   	    thisMethods = allMethods;
 1672   	}
 1673   
 1674   	return thisMethods;
 1675       }
 1676   
 1677   
 1678       // ------------------------------------------------------ Lifecycle Methods
 1679   
 1680   
 1681       /**
 1682        * Start this component, pre-loading the servlet if the load-on-startup
 1683        * value is set appropriately.
 1684        *
 1685        * @exception LifecycleException if a fatal error occurs during startup
 1686        */
 1687       public void start() throws LifecycleException {
 1688       
 1689           // Send j2ee.state.starting notification 
 1690           if (this.getObjectName() != null) {
 1691               Notification notification = new Notification("j2ee.state.starting", 
 1692                                                           this.getObjectName(), 
 1693                                                           sequenceNumber++);
 1694               broadcaster.sendNotification(notification);
 1695           }
 1696           
 1697           // Start up this component
 1698           super.start();
 1699   
 1700           if( oname != null )
 1701               registerJMX((StandardContext)getParent());
 1702           
 1703           // Load and initialize an instance of this servlet if requested
 1704           // MOVED TO StandardContext START() METHOD
 1705   
 1706           setAvailable(0L);
 1707           
 1708           // Send j2ee.state.running notification 
 1709           if (this.getObjectName() != null) {
 1710               Notification notification = 
 1711                   new Notification("j2ee.state.running", this.getObjectName(), 
 1712                                   sequenceNumber++);
 1713               broadcaster.sendNotification(notification);
 1714           }
 1715   
 1716       }
 1717   
 1718   
 1719       /**
 1720        * Stop this component, gracefully shutting down the servlet if it has
 1721        * been initialized.
 1722        *
 1723        * @exception LifecycleException if a fatal error occurs during shutdown
 1724        */
 1725       public void stop() throws LifecycleException {
 1726   
 1727           setAvailable(Long.MAX_VALUE);
 1728           
 1729           // Send j2ee.state.stopping notification 
 1730           if (this.getObjectName() != null) {
 1731               Notification notification = 
 1732                   new Notification("j2ee.state.stopping", this.getObjectName(), 
 1733                                   sequenceNumber++);
 1734               broadcaster.sendNotification(notification);
 1735           }
 1736           
 1737           // Shut down our servlet instance (if it has been initialized)
 1738           try {
 1739               unload();
 1740           } catch (ServletException e) {
 1741               getServletContext().log(sm.getString
 1742                         ("standardWrapper.unloadException", getName()), e);
 1743           }
 1744   
 1745           // Shut down this component
 1746           super.stop();
 1747   
 1748           // Send j2ee.state.stoppped notification 
 1749           if (this.getObjectName() != null) {
 1750               Notification notification = 
 1751                   new Notification("j2ee.state.stopped", this.getObjectName(), 
 1752                                   sequenceNumber++);
 1753               broadcaster.sendNotification(notification);
 1754           }
 1755           
 1756           if( oname != null ) {
 1757               Registry.getRegistry(null, null).unregisterComponent(oname);
 1758               
 1759               // Send j2ee.object.deleted notification 
 1760               Notification notification = 
 1761                   new Notification("j2ee.object.deleted", this.getObjectName(), 
 1762                                   sequenceNumber++);
 1763               broadcaster.sendNotification(notification);
 1764           }
 1765   
 1766           if (isJspServlet && jspMonitorON != null ) {
 1767               Registry.getRegistry(null, null).unregisterComponent(jspMonitorON);
 1768           }
 1769   
 1770       }
 1771   
 1772       protected void registerJMX(StandardContext ctx) {
 1773   
 1774           String parentName = ctx.getName();
 1775           parentName = ("".equals(parentName)) ? "/" : parentName;
 1776   
 1777           String hostName = ctx.getParent().getName();
 1778           hostName = (hostName==null) ? "DEFAULT" : hostName;
 1779   
 1780           String domain = ctx.getDomain();
 1781   
 1782           String webMod= "//" + hostName + parentName;
 1783           String onameStr = domain + ":j2eeType=Servlet,name=" + getName() +
 1784                             ",WebModule=" + webMod + ",J2EEApplication=" +
 1785                             ctx.getJ2EEApplication() + ",J2EEServer=" +
 1786                             ctx.getJ2EEServer();
 1787           try {
 1788               oname=new ObjectName(onameStr);
 1789               controller=oname;
 1790               Registry.getRegistry(null, null)
 1791                   .registerComponent(this, oname, null );
 1792               
 1793               // Send j2ee.object.created notification 
 1794               if (this.getObjectName() != null) {
 1795                   Notification notification = new Notification(
 1796                                                   "j2ee.object.created", 
 1797                                                   this.getObjectName(), 
 1798                                                   sequenceNumber++);
 1799                   broadcaster.sendNotification(notification);
 1800               }
 1801           } catch( Exception ex ) {
 1802               log.info("Error registering servlet with jmx " + this, ex);
 1803           }
 1804   
 1805           if (isJspServlet) {
 1806               // Register JSP monitoring mbean
 1807               onameStr = domain + ":type=JspMonitor,name=" + getName()
 1808                          + ",WebModule=" + webMod
 1809                          + ",J2EEApplication=" + ctx.getJ2EEApplication()
 1810                          + ",J2EEServer=" + ctx.getJ2EEServer();
 1811               try {
 1812                   jspMonitorON = new ObjectName(onameStr);
 1813                   Registry.getRegistry(null, null)
 1814                       .registerComponent(instance, jspMonitorON, null);
 1815               } catch( Exception ex ) {
 1816                   log.info("Error registering JSP monitoring with jmx " +
 1817                            instance, ex);
 1818               }
 1819           }
 1820       }
 1821       
 1822   
 1823       /* Remove a JMX notficationListener 
 1824        * @see javax.management.NotificationEmitter#removeNotificationListener(javax.management.NotificationListener, javax.management.NotificationFilter, java.lang.Object)
 1825        */
 1826       public void removeNotificationListener(NotificationListener listener, 
 1827       		NotificationFilter filter, Object object) throws ListenerNotFoundException {
 1828       	broadcaster.removeNotificationListener(listener,filter,object);
 1829       	
 1830       }
 1831       
 1832       protected MBeanNotificationInfo[] notificationInfo;
 1833       
 1834       /* Get JMX Broadcaster Info
 1835        * @TODO use StringManager for international support!
 1836        * @TODO This two events we not send j2ee.state.failed and j2ee.attribute.changed!
 1837        * @see javax.management.NotificationBroadcaster#getNotificationInfo()
 1838        */
 1839       public MBeanNotificationInfo[] getNotificationInfo() {
 1840       	
 1841       	if(notificationInfo == null) {
 1842       		notificationInfo = new MBeanNotificationInfo[]{
 1843       				new MBeanNotificationInfo(new String[] {
 1844       				"j2ee.object.created"},
 1845   					Notification.class.getName(),
 1846   					"servlet is created"
 1847       				), 
 1848   					new MBeanNotificationInfo(new String[] {
 1849   					"j2ee.state.starting"},
 1850   					Notification.class.getName(),
 1851   					"servlet is starting"
 1852   					),
 1853   					new MBeanNotificationInfo(new String[] {
 1854   					"j2ee.state.running"},
 1855   					Notification.class.getName(),
 1856   					"servlet is running"
 1857   					),
 1858   					new MBeanNotificationInfo(new String[] {
 1859   					"j2ee.state.stopped"},
 1860   					Notification.class.getName(),
 1861   					"servlet start to stopped"
 1862   					),
 1863   					new MBeanNotificationInfo(new String[] {
 1864   					"j2ee.object.stopped"},
 1865   					Notification.class.getName(),
 1866   					"servlet is stopped"
 1867   					),
 1868   					new MBeanNotificationInfo(new String[] {
 1869   					"j2ee.object.deleted"},
 1870   					Notification.class.getName(),
 1871   					"servlet is deleted"
 1872   					)
 1873       		};
 1874       		
 1875       	}
 1876       	
 1877       	return notificationInfo;
 1878       }
 1879       
 1880       
 1881       /* Add a JMX-NotificationListener
 1882        * @see javax.management.NotificationBroadcaster#addNotificationListener(javax.management.NotificationListener, javax.management.NotificationFilter, java.lang.Object)
 1883        */
 1884       public void addNotificationListener(NotificationListener listener, 
 1885               NotificationFilter filter, Object object) throws IllegalArgumentException {
 1886       	broadcaster.addNotificationListener(listener,filter,object);
 1887       }
 1888       
 1889       
 1890       /**
 1891        * Remove a JMX-NotificationListener 
 1892        * @see javax.management.NotificationBroadcaster#removeNotificationListener(javax.management.NotificationListener)
 1893        */
 1894       public void removeNotificationListener(NotificationListener listener) 
 1895           throws ListenerNotFoundException {
 1896       	broadcaster.removeNotificationListener(listener);
 1897       }
 1898       
 1899       
 1900        // ------------------------------------------------------------- Attributes
 1901           
 1902           
 1903       public boolean isEventProvider() {
 1904           return false;
 1905       }
 1906       
 1907       public boolean isStateManageable() {
 1908           return false;
 1909       }
 1910       
 1911       public boolean isStatisticsProvider() {
 1912           return false;
 1913       }
 1914           
 1915           
 1916   }

Save This Page
Home » apache-tomcat-6.0.26-src » org.apache » catalina » core » [javadoc | source]