Save This Page
Home » apache-tomcat-6.0.16-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   
   22   import java.beans.PropertyChangeListener;
   23   import java.beans.PropertyChangeSupport;
   24   import javax.management.MBeanRegistration;
   25   import javax.management.MBeanServer;
   26   import javax.management.ObjectName;
   27   import org.apache.catalina.Container;
   28   import org.apache.catalina.Engine;
   29   import org.apache.catalina.Lifecycle;
   30   import org.apache.catalina.LifecycleException;
   31   import org.apache.catalina.LifecycleListener;
   32   import org.apache.catalina.Server;
   33   import org.apache.catalina.Service;
   34   import org.apache.catalina.ServerFactory;
   35   import org.apache.catalina.connector.Connector;
   36   import org.apache.catalina.util.LifecycleSupport;
   37   import org.apache.catalina.util.StringManager;
   38   import org.apache.juli.logging.Log;
   39   import org.apache.juli.logging.LogFactory;
   40   import org.apache.tomcat.util.modeler.Registry;
   41   import java.util.ArrayList;
   42   import org.apache.catalina.Executor;
   43   
   44   
   45   /**
   46    * Standard implementation of the <code>Service</code> interface.  The
   47    * associated Container is generally an instance of Engine, but this is
   48    * not required.
   49    *
   50    * @author Craig R. McClanahan
   51    */
   52   
   53   public class StandardService
   54           implements Lifecycle, Service, MBeanRegistration 
   55    {
   56       private static Log log = LogFactory.getLog(StandardService.class);
   57      
   58   
   59       // ----------------------------------------------------- Instance Variables
   60   
   61   
   62       /**
   63        * Descriptive information about this component implementation.
   64        */
   65       private static final String info =
   66           "org.apache.catalina.core.StandardService/1.0";
   67   
   68   
   69       /**
   70        * The name of this service.
   71        */
   72       private String name = null;
   73   
   74   
   75       /**
   76        * The lifecycle event support for this component.
   77        */
   78       private LifecycleSupport lifecycle = new LifecycleSupport(this);
   79   
   80   
   81       /**
   82        * The string manager for this package.
   83        */
   84       private static final StringManager sm =
   85           StringManager.getManager(Constants.Package);
   86   
   87       /**
   88        * The <code>Server</code> that owns this Service, if any.
   89        */
   90       private Server server = null;
   91   
   92       /**
   93        * Has this component been started?
   94        */
   95       private boolean started = false;
   96   
   97   
   98       /**
   99        * The property change support for this component.
  100        */
  101       protected PropertyChangeSupport support = new PropertyChangeSupport(this);
  102   
  103   
  104       /**
  105        * The set of Connectors associated with this Service.
  106        */
  107       protected Connector connectors[] = new Connector[0];
  108       
  109       /**
  110        * 
  111        */
  112       protected ArrayList<Executor> executors = new ArrayList<Executor>();
  113   
  114       /**
  115        * The Container associated with this Service. (In the case of the
  116        * org.apache.catalina.startup.Embedded subclass, this holds the most
  117        * recently added Engine.)
  118        */
  119       protected Container container = null;
  120   
  121   
  122       /**
  123        * Has this component been initialized?
  124        */
  125       protected boolean initialized = false;
  126   
  127   
  128       // ------------------------------------------------------------- Properties
  129   
  130   
  131       /**
  132        * Return the <code>Container</code> that handles requests for all
  133        * <code>Connectors</code> associated with this Service.
  134        */
  135       public Container getContainer() {
  136   
  137           return (this.container);
  138   
  139       }
  140   
  141   
  142       /**
  143        * Set the <code>Container</code> that handles requests for all
  144        * <code>Connectors</code> associated with this Service.
  145        *
  146        * @param container The new Container
  147        */
  148       public void setContainer(Container container) {
  149   
  150           Container oldContainer = this.container;
  151           if ((oldContainer != null) && (oldContainer instanceof Engine))
  152               ((Engine) oldContainer).setService(null);
  153           this.container = container;
  154           if ((this.container != null) && (this.container instanceof Engine))
  155               ((Engine) this.container).setService(this);
  156           if (started && (this.container != null) &&
  157               (this.container instanceof Lifecycle)) {
  158               try {
  159                   ((Lifecycle) this.container).start();
  160               } catch (LifecycleException e) {
  161                   ;
  162               }
  163           }
  164           synchronized (connectors) {
  165               for (int i = 0; i < connectors.length; i++)
  166                   connectors[i].setContainer(this.container);
  167           }
  168           if (started && (oldContainer != null) &&
  169               (oldContainer instanceof Lifecycle)) {
  170               try {
  171                   ((Lifecycle) oldContainer).stop();
  172               } catch (LifecycleException e) {
  173                   ;
  174               }
  175           }
  176   
  177           // Report this property change to interested listeners
  178           support.firePropertyChange("container", oldContainer, this.container);
  179   
  180       }
  181   
  182       public ObjectName getContainerName() {
  183           if( container instanceof ContainerBase ) {
  184               return ((ContainerBase)container).getJmxName();
  185           }
  186           return null;
  187       }
  188   
  189   
  190       /**
  191        * Return descriptive information about this Service implementation and
  192        * the corresponding version number, in the format
  193        * <code>&lt;description&gt;/&lt;version&gt;</code>.
  194        */
  195       public String getInfo() {
  196   
  197           return (info);
  198   
  199       }
  200   
  201   
  202       /**
  203        * Return the name of this Service.
  204        */
  205       public String getName() {
  206   
  207           return (this.name);
  208   
  209       }
  210   
  211   
  212       /**
  213        * Set the name of this Service.
  214        *
  215        * @param name The new service name
  216        */
  217       public void setName(String name) {
  218   
  219           this.name = name;
  220   
  221       }
  222   
  223   
  224       /**
  225        * Return the <code>Server</code> with which we are associated (if any).
  226        */
  227       public Server getServer() {
  228   
  229           return (this.server);
  230   
  231       }
  232   
  233   
  234       /**
  235        * Set the <code>Server</code> with which we are associated (if any).
  236        *
  237        * @param server The server that owns this Service
  238        */
  239       public void setServer(Server server) {
  240   
  241           this.server = server;
  242   
  243       }
  244   
  245   
  246       // --------------------------------------------------------- Public Methods
  247   
  248   
  249       /**
  250        * Add a new Connector to the set of defined Connectors, and associate it
  251        * with this Service's Container.
  252        *
  253        * @param connector The Connector to be added
  254        */
  255       public void addConnector(Connector connector) {
  256   
  257           synchronized (connectors) {
  258               connector.setContainer(this.container);
  259               connector.setService(this);
  260               Connector results[] = new Connector[connectors.length + 1];
  261               System.arraycopy(connectors, 0, results, 0, connectors.length);
  262               results[connectors.length] = connector;
  263               connectors = results;
  264   
  265               if (initialized) {
  266                   try {
  267                       connector.initialize();
  268                   } catch (LifecycleException e) {
  269                       log.error("Connector.initialize", e);
  270                   }
  271               }
  272   
  273               if (started && (connector instanceof Lifecycle)) {
  274                   try {
  275                       ((Lifecycle) connector).start();
  276                   } catch (LifecycleException e) {
  277                       log.error("Connector.start", e);
  278                   }
  279               }
  280   
  281               // Report this property change to interested listeners
  282               support.firePropertyChange("connector", null, connector);
  283           }
  284   
  285       }
  286   
  287       public ObjectName[] getConnectorNames() {
  288           ObjectName results[] = new ObjectName[connectors.length];
  289           for (int i=0; i<results.length; i++) {
  290               results[i] = connectors[i].getObjectName();
  291           }
  292           return results;
  293       }
  294   
  295   
  296       /**
  297        * Add a property change listener to this component.
  298        *
  299        * @param listener The listener to add
  300        */
  301       public void addPropertyChangeListener(PropertyChangeListener listener) {
  302   
  303           support.addPropertyChangeListener(listener);
  304   
  305       }
  306   
  307   
  308       /**
  309        * Find and return the set of Connectors associated with this Service.
  310        */
  311       public Connector[] findConnectors() {
  312   
  313           return (connectors);
  314   
  315       }
  316   
  317   
  318       /**
  319        * Remove the specified Connector from the set associated from this
  320        * Service.  The removed Connector will also be disassociated from our
  321        * Container.
  322        *
  323        * @param connector The Connector to be removed
  324        */
  325       public void removeConnector(Connector connector) {
  326   
  327           synchronized (connectors) {
  328               int j = -1;
  329               for (int i = 0; i < connectors.length; i++) {
  330                   if (connector == connectors[i]) {
  331                       j = i;
  332                       break;
  333                   }
  334               }
  335               if (j < 0)
  336                   return;
  337               if (started && (connectors[j] instanceof Lifecycle)) {
  338                   try {
  339                       ((Lifecycle) connectors[j]).stop();
  340                   } catch (LifecycleException e) {
  341                       log.error("Connector.stop", e);
  342                   }
  343               }
  344               connectors[j].setContainer(null);
  345               connector.setService(null);
  346               int k = 0;
  347               Connector results[] = new Connector[connectors.length - 1];
  348               for (int i = 0; i < connectors.length; i++) {
  349                   if (i != j)
  350                       results[k++] = connectors[i];
  351               }
  352               connectors = results;
  353   
  354               // Report this property change to interested listeners
  355               support.firePropertyChange("connector", connector, null);
  356           }
  357   
  358       }
  359   
  360   
  361       /**
  362        * Remove a property change listener from this component.
  363        *
  364        * @param listener The listener to remove
  365        */
  366       public void removePropertyChangeListener(PropertyChangeListener listener) {
  367   
  368           support.removePropertyChangeListener(listener);
  369   
  370       }
  371   
  372   
  373       /**
  374        * Return a String representation of this component.
  375        */
  376       public String toString() {
  377   
  378           StringBuffer sb = new StringBuffer("StandardService[");
  379           sb.append(getName());
  380           sb.append("]");
  381           return (sb.toString());
  382   
  383       }
  384   
  385   
  386       // ------------------------------------------------------ Lifecycle Methods
  387   
  388   
  389       /**
  390        * Add a LifecycleEvent listener to this component.
  391        *
  392        * @param listener The listener to add
  393        */
  394       public void addLifecycleListener(LifecycleListener listener) {
  395   
  396           lifecycle.addLifecycleListener(listener);
  397   
  398       }
  399   
  400   
  401       /**
  402        * Get the lifecycle listeners associated with this lifecycle. If this 
  403        * Lifecycle has no listeners registered, a zero-length array is returned.
  404        */
  405       public LifecycleListener[] findLifecycleListeners() {
  406   
  407           return lifecycle.findLifecycleListeners();
  408   
  409       }
  410   
  411   
  412       /**
  413        * Remove a LifecycleEvent listener from this component.
  414        *
  415        * @param listener The listener to remove
  416        */
  417       public void removeLifecycleListener(LifecycleListener listener) {
  418   
  419           lifecycle.removeLifecycleListener(listener);
  420   
  421       }
  422       
  423       /**
  424        * Adds a named executor to the service
  425        * @param ex Executor
  426        */
  427       public void addExecutor(Executor ex) {
  428           synchronized (executors) {
  429               if (!executors.contains(ex)) {
  430                   executors.add(ex);
  431                   if (started)
  432                       try {
  433                           ex.start();
  434                       } catch (LifecycleException x) {
  435                           log.error("Executor.start", x);
  436                       }
  437               }
  438           }
  439       }
  440   
  441       /**
  442        * Retrieves all executors
  443        * @return Executor[]
  444        */
  445       public Executor[] findExecutors() {
  446           synchronized (executors) {
  447               Executor[] arr = new Executor[executors.size()];
  448               executors.toArray(arr);
  449               return arr;
  450           }
  451       }
  452   
  453       /**
  454        * Retrieves executor by name, null if not found
  455        * @param name String
  456        * @return Executor
  457        */
  458       public Executor getExecutor(String name) {
  459           synchronized (executors) {
  460               for (int i = 0; i < executors.size(); i++) {
  461                   if (name.equals(executors.get(i).getName()))
  462                       return executors.get(i);
  463               }
  464           }
  465           return null;
  466       }
  467   
  468       /**
  469        * Removes an executor from the service
  470        * @param ex Executor
  471        */
  472       public void removeExecutor(Executor ex) {
  473           synchronized (executors) {
  474               if ( executors.remove(ex) && started ) {
  475                   try {
  476                       ex.stop();
  477                   } catch (LifecycleException e) {
  478                       log.error("Executor.stop", e);
  479                   }
  480               }
  481           }
  482       }
  483   
  484   
  485   
  486       /**
  487        * Prepare for the beginning of active use of the public methods of this
  488        * component.  This method should be called before any of the public
  489        * methods of this component are utilized.  It should also send a
  490        * LifecycleEvent of type START_EVENT to any registered listeners.
  491        *
  492        * @exception LifecycleException if this component detects a fatal error
  493        *  that prevents this component from being used
  494        */
  495       public void start() throws LifecycleException {
  496   
  497           // Validate and update our current component state
  498           if (log.isInfoEnabled() && started) {
  499               log.info(sm.getString("standardService.start.started"));
  500           }
  501           
  502           if( ! initialized )
  503               init(); 
  504   
  505           // Notify our interested LifecycleListeners
  506           lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
  507           if(log.isInfoEnabled())
  508               log.info(sm.getString("standardService.start.name", this.name));
  509           lifecycle.fireLifecycleEvent(START_EVENT, null);
  510           started = true;
  511   
  512           // Start our defined Container first
  513           if (container != null) {
  514               synchronized (container) {
  515                   if (container instanceof Lifecycle) {
  516                       ((Lifecycle) container).start();
  517                   }
  518               }
  519           }
  520   
  521           synchronized (executors) {
  522               for ( int i=0; i<executors.size(); i++ ) {
  523                   executors.get(i).start();
  524               }
  525           }
  526   
  527           // Start our defined Connectors second
  528           synchronized (connectors) {
  529               for (int i = 0; i < connectors.length; i++) {
  530                   if (connectors[i] instanceof Lifecycle)
  531                       ((Lifecycle) connectors[i]).start();
  532               }
  533           }
  534           
  535           // Notify our interested LifecycleListeners
  536           lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
  537   
  538       }
  539   
  540   
  541       /**
  542        * Gracefully terminate the active use of the public methods of this
  543        * component.  This method should be the last one called on a given
  544        * instance of this component.  It should also send a LifecycleEvent
  545        * of type STOP_EVENT to any registered listeners.
  546        *
  547        * @exception LifecycleException if this component detects a fatal error
  548        *  that needs to be reported
  549        */
  550       public void stop() throws LifecycleException {
  551   
  552           // Validate and update our current component state
  553           if (!started) {
  554               return;
  555           }
  556   
  557           // Notify our interested LifecycleListeners
  558           lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);
  559   
  560           // Stop our defined Connectors first
  561           synchronized (connectors) {
  562               for (int i = 0; i < connectors.length; i++) {
  563                   connectors[i].pause();
  564               }
  565           }
  566   
  567           // Heuristic: Sleep for a while to ensure pause of the connector
  568           try {
  569               Thread.sleep(1000);
  570           } catch (InterruptedException e) {
  571               // Ignore
  572           }
  573   
  574           lifecycle.fireLifecycleEvent(STOP_EVENT, null);
  575           if(log.isInfoEnabled())
  576               log.info
  577                   (sm.getString("standardService.stop.name", this.name));
  578           started = false;
  579   
  580           // Stop our defined Container second
  581           if (container != null) {
  582               synchronized (container) {
  583                   if (container instanceof Lifecycle) {
  584                       ((Lifecycle) container).stop();
  585                   }
  586               }
  587           }
  588           // FIXME pero -- Why container stop first? KeepAlive connetions can send request! 
  589           // Stop our defined Connectors first
  590           synchronized (connectors) {
  591               for (int i = 0; i < connectors.length; i++) {
  592                   if (connectors[i] instanceof Lifecycle)
  593                       ((Lifecycle) connectors[i]).stop();
  594               }
  595           }
  596   
  597           synchronized (executors) {
  598               for ( int i=0; i<executors.size(); i++ ) {
  599                   executors.get(i).stop();
  600               }
  601           }
  602   
  603           if( oname==controller ) {
  604               // we registered ourself on init().
  605               // That should be the typical case - this object is just for
  606               // backward compat, nobody should bother to load it explicitely
  607               Registry.getRegistry(null, null).unregisterComponent(oname);
  608               Executor[] executors = findExecutors();
  609               for (int i = 0; i < executors.length; i++) {
  610                   try {
  611                       ObjectName executorObjectName = 
  612                           new ObjectName(domain + ":type=Executor,name=" + executors[i].getName());
  613                       Registry.getRegistry(null, null).unregisterComponent(executorObjectName);
  614                   } catch (Exception e) {
  615                       // Ignore (invalid ON, which cannot happen)
  616                   }
  617               }
  618           }
  619           
  620   
  621           // Notify our interested LifecycleListeners
  622           lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
  623   
  624       }
  625   
  626   
  627       /**
  628        * Invoke a pre-startup initialization. This is used to allow connectors
  629        * to bind to restricted ports under Unix operating environments.
  630        */
  631       public void initialize()
  632               throws LifecycleException
  633       {
  634           // Service shouldn't be used with embeded, so it doesn't matter
  635           if (initialized) {
  636               if(log.isInfoEnabled())
  637                   log.info(sm.getString("standardService.initialize.initialized"));
  638               return;
  639           }
  640           initialized = true;
  641   
  642           if( oname==null ) {
  643               try {
  644                   // Hack - Server should be deprecated...
  645                   Container engine=this.getContainer();
  646                   domain=engine.getName();
  647                   oname=new ObjectName(domain + ":type=Service,serviceName="+name);
  648                   this.controller=oname;
  649                   Registry.getRegistry(null, null)
  650                       .registerComponent(this, oname, null);
  651                   
  652                   Executor[] executors = findExecutors();
  653                   for (int i = 0; i < executors.length; i++) {
  654                       ObjectName executorObjectName = 
  655                           new ObjectName(domain + ":type=Executor,name=" + executors[i].getName());
  656                       Registry.getRegistry(null, null)
  657                           .registerComponent(executors[i], executorObjectName, null);
  658                   }
  659                   
  660               } catch (Exception e) {
  661                   log.error(sm.getString("standardService.register.failed",domain),e);
  662               }
  663               
  664               
  665           }
  666           if( server==null ) {
  667               // Register with the server 
  668               // HACK: ServerFactory should be removed...
  669               
  670               ServerFactory.getServer().addService(this);
  671           }
  672                  
  673   
  674           // Initialize our defined Connectors
  675           synchronized (connectors) {
  676                   for (int i = 0; i < connectors.length; i++) {
  677                       connectors[i].initialize();
  678                   }
  679           }
  680       }
  681       
  682       public void destroy() throws LifecycleException {
  683           if( started ) stop();
  684           // FIXME unregister should be here probably -- stop doing that ?
  685       }
  686   
  687       public void init() {
  688           try {
  689               initialize();
  690           } catch( Throwable t ) {
  691               log.error(sm.getString("standardService.initialize.failed",domain),t);
  692           }
  693       }
  694   
  695       protected String type;
  696       protected String domain;
  697       protected String suffix;
  698       protected ObjectName oname;
  699       protected ObjectName controller;
  700       protected MBeanServer mserver;
  701   
  702       public ObjectName getObjectName() {
  703           return oname;
  704       }
  705   
  706       public String getDomain() {
  707           return domain;
  708       }
  709   
  710       public ObjectName preRegister(MBeanServer server,
  711                                     ObjectName name) throws Exception {
  712           oname=name;
  713           mserver=server;
  714           domain=name.getDomain();
  715           return name;
  716       }
  717   
  718       public void postRegister(Boolean registrationDone) {
  719       }
  720   
  721       public void preDeregister() throws Exception {
  722       }
  723   
  724       public void postDeregister() {
  725       }
  726   
  727   }

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