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   
   22   import java.beans.PropertyChangeListener;
   23   import java.beans.PropertyChangeSupport;
   24   import java.io.IOException;
   25   import java.io.InputStream;
   26   import java.net.InetAddress;
   27   import java.net.ServerSocket;
   28   import java.net.Socket;
   29   import java.security.AccessControlException;
   30   import java.util.Random;
   31   
   32   import javax.management.MBeanRegistration;
   33   import javax.management.MBeanServer;
   34   import javax.management.ObjectName;
   35   
   36   import org.apache.catalina.Context;
   37   import org.apache.catalina.Lifecycle;
   38   import org.apache.catalina.LifecycleException;
   39   import org.apache.catalina.LifecycleListener;
   40   import org.apache.catalina.Server;
   41   import org.apache.catalina.ServerFactory;
   42   import org.apache.catalina.Service;
   43   import org.apache.catalina.deploy.NamingResources;
   44   import org.apache.catalina.util.LifecycleSupport;
   45   import org.apache.catalina.util.StringManager;
   46   import org.apache.catalina.util.ServerInfo;
   47   import org.apache.juli.logging.Log;
   48   import org.apache.juli.logging.LogFactory;
   49   import org.apache.tomcat.util.buf.StringCache;
   50   import org.apache.tomcat.util.modeler.Registry;
   51   
   52   
   53   
   54   /**
   55    * Standard implementation of the <b>Server</b> interface, available for use
   56    * (but not required) when deploying and starting Catalina.
   57    *
   58    * @author Craig R. McClanahan
   59    * @version $Revision: 762911 $ $Date: 2009-04-07 21:15:16 +0200 (Tue, 07 Apr 2009) $
   60    */
   61   public final class StandardServer
   62       implements Lifecycle, Server, MBeanRegistration 
   63    {
   64       private static Log log = LogFactory.getLog(StandardServer.class);
   65      
   66   
   67       // -------------------------------------------------------------- Constants
   68   
   69   
   70       /**
   71        * ServerLifecycleListener classname.
   72        */
   73       private static String SERVER_LISTENER_CLASS_NAME =
   74           "org.apache.catalina.mbeans.ServerLifecycleListener";
   75   
   76   
   77       // ------------------------------------------------------------ Constructor
   78   
   79   
   80       /**
   81        * Construct a default instance of this class.
   82        */
   83       public StandardServer() {
   84   
   85           super();
   86           ServerFactory.setServer(this);
   87   
   88           globalNamingResources = new NamingResources();
   89           globalNamingResources.setContainer(this);
   90   
   91           if (isUseNaming()) {
   92               if (namingContextListener == null) {
   93                   namingContextListener = new NamingContextListener();
   94                   addLifecycleListener(namingContextListener);
   95               }
   96           }
   97   
   98       }
   99   
  100   
  101       // ----------------------------------------------------- Instance Variables
  102   
  103   
  104       /**
  105        * Global naming resources context.
  106        */
  107       private javax.naming.Context globalNamingContext = null;
  108   
  109   
  110       /**
  111        * Global naming resources.
  112        */
  113       private NamingResources globalNamingResources = null;
  114   
  115   
  116       /**
  117        * Descriptive information about this Server implementation.
  118        */
  119       private static final String info =
  120           "org.apache.catalina.core.StandardServer/1.0";
  121   
  122   
  123       /**
  124        * The lifecycle event support for this component.
  125        */
  126       private LifecycleSupport lifecycle = new LifecycleSupport(this);
  127   
  128   
  129       /**
  130        * The naming context listener for this web application.
  131        */
  132       private NamingContextListener namingContextListener = null;
  133   
  134   
  135       /**
  136        * The port number on which we wait for shutdown commands.
  137        */
  138       private int port = 8005;
  139   
  140   
  141       /**
  142        * A random number generator that is <strong>only</strong> used if
  143        * the shutdown command string is longer than 1024 characters.
  144        */
  145       private Random random = null;
  146   
  147   
  148       /**
  149        * The set of Services associated with this Server.
  150        */
  151       private Service services[] = new Service[0];
  152   
  153   
  154       /**
  155        * The shutdown command string we are looking for.
  156        */
  157       private String shutdown = "SHUTDOWN";
  158   
  159   
  160       /**
  161        * The string manager for this package.
  162        */
  163       private static final StringManager sm =
  164           StringManager.getManager(Constants.Package);
  165   
  166   
  167       /**
  168        * Has this component been started?
  169        */
  170       private boolean started = false;
  171   
  172   
  173       /**
  174        * Has this component been initialized?
  175        */
  176       private boolean initialized = false;
  177   
  178   
  179       /**
  180        * The property change support for this component.
  181        */
  182       protected PropertyChangeSupport support = new PropertyChangeSupport(this);
  183   
  184       private boolean stopAwait = false;
  185   
  186       // ------------------------------------------------------------- Properties
  187   
  188   
  189       /**
  190        * Return the global naming resources context.
  191        */
  192       public javax.naming.Context getGlobalNamingContext() {
  193   
  194           return (this.globalNamingContext);
  195   
  196       }
  197   
  198   
  199       /**
  200        * Set the global naming resources context.
  201        *
  202        * @param globalNamingContext The new global naming resource context
  203        */
  204       public void setGlobalNamingContext
  205           (javax.naming.Context globalNamingContext) {
  206   
  207           this.globalNamingContext = globalNamingContext;
  208   
  209       }
  210   
  211   
  212       /**
  213        * Return the global naming resources.
  214        */
  215       public NamingResources getGlobalNamingResources() {
  216   
  217           return (this.globalNamingResources);
  218   
  219       }
  220   
  221   
  222       /**
  223        * Set the global naming resources.
  224        *
  225        * @param globalNamingResources The new global naming resources
  226        */
  227       public void setGlobalNamingResources
  228           (NamingResources globalNamingResources) {
  229   
  230           NamingResources oldGlobalNamingResources =
  231               this.globalNamingResources;
  232           this.globalNamingResources = globalNamingResources;
  233           this.globalNamingResources.setContainer(this);
  234           support.firePropertyChange("globalNamingResources",
  235                                      oldGlobalNamingResources,
  236                                      this.globalNamingResources);
  237   
  238       }
  239   
  240   
  241       /**
  242        * Return descriptive information about this Server implementation and
  243        * the corresponding version number, in the format
  244        * <code>&lt;description&gt;/&lt;version&gt;</code>.
  245        */
  246       public String getInfo() {
  247   
  248           return (info);
  249   
  250       }
  251   
  252       /**
  253        * Report the current Tomcat Server Release number
  254        * @return Tomcat release identifier
  255        */
  256       public String getServerInfo() {
  257   
  258           return ServerInfo.getServerInfo();
  259       }
  260   
  261       /**
  262        * Return the port number we listen to for shutdown commands.
  263        */
  264       public int getPort() {
  265   
  266           return (this.port);
  267   
  268       }
  269   
  270   
  271       /**
  272        * Set the port number we listen to for shutdown commands.
  273        *
  274        * @param port The new port number
  275        */
  276       public void setPort(int port) {
  277   
  278           this.port = port;
  279   
  280       }
  281   
  282   
  283       /**
  284        * Return the shutdown command string we are waiting for.
  285        */
  286       public String getShutdown() {
  287   
  288           return (this.shutdown);
  289   
  290       }
  291   
  292   
  293       /**
  294        * Set the shutdown command we are waiting for.
  295        *
  296        * @param shutdown The new shutdown command
  297        */
  298       public void setShutdown(String shutdown) {
  299   
  300           this.shutdown = shutdown;
  301   
  302       }
  303   
  304   
  305       // --------------------------------------------------------- Server Methods
  306   
  307   
  308       /**
  309        * Add a new Service to the set of defined Services.
  310        *
  311        * @param service The Service to be added
  312        */
  313       public void addService(Service service) {
  314   
  315           service.setServer(this);
  316   
  317           synchronized (services) {
  318               Service results[] = new Service[services.length + 1];
  319               System.arraycopy(services, 0, results, 0, services.length);
  320               results[services.length] = service;
  321               services = results;
  322   
  323               if (initialized) {
  324                   try {
  325                       service.initialize();
  326                   } catch (LifecycleException e) {
  327                       log.error(e);
  328                   }
  329               }
  330   
  331               if (started && (service instanceof Lifecycle)) {
  332                   try {
  333                       ((Lifecycle) service).start();
  334                   } catch (LifecycleException e) {
  335                       ;
  336                   }
  337               }
  338   
  339               // Report this property change to interested listeners
  340               support.firePropertyChange("service", null, service);
  341           }
  342   
  343       }
  344   
  345       public void stopAwait() {
  346           stopAwait=true;
  347       }
  348   
  349       /**
  350        * Wait until a proper shutdown command is received, then return.
  351        * This keeps the main thread alive - the thread pool listening for http 
  352        * connections is daemon threads.
  353        */
  354       public void await() {
  355           // Negative values - don't wait on port - tomcat is embedded or we just don't like ports
  356           if( port == -2 ) {
  357               // undocumented yet - for embedding apps that are around, alive.
  358               return;
  359           }
  360           if( port==-1 ) {
  361               while( true ) {
  362                   try {
  363                       Thread.sleep( 10000 );
  364                   } catch( InterruptedException ex ) {
  365                   }
  366                   if( stopAwait ) return;
  367               }
  368           }
  369           
  370           // Set up a server socket to wait on
  371           ServerSocket serverSocket = null;
  372           try {
  373               serverSocket =
  374                   new ServerSocket(port, 1,
  375                                    InetAddress.getByName("localhost"));
  376           } catch (IOException e) {
  377               log.error("StandardServer.await: create[" + port
  378                                  + "]: ", e);
  379               System.exit(1);
  380           }
  381   
  382           // Loop waiting for a connection and a valid command
  383           while (true) {
  384   
  385               // Wait for the next connection
  386               Socket socket = null;
  387               InputStream stream = null;
  388               try {
  389                   socket = serverSocket.accept();
  390                   socket.setSoTimeout(10 * 1000);  // Ten seconds
  391                   stream = socket.getInputStream();
  392               } catch (AccessControlException ace) {
  393                   log.warn("StandardServer.accept security exception: "
  394                                      + ace.getMessage(), ace);
  395                   continue;
  396               } catch (IOException e) {
  397                   log.error("StandardServer.await: accept: ", e);
  398                   System.exit(1);
  399               }
  400   
  401               // Read a set of characters from the socket
  402               StringBuffer command = new StringBuffer();
  403               int expected = 1024; // Cut off to avoid DoS attack
  404               while (expected < shutdown.length()) {
  405                   if (random == null)
  406                       random = new Random();
  407                   expected += (random.nextInt() % 1024);
  408               }
  409               while (expected > 0) {
  410                   int ch = -1;
  411                   try {
  412                       ch = stream.read();
  413                   } catch (IOException e) {
  414                       log.warn("StandardServer.await: read: ", e);
  415                       ch = -1;
  416                   }
  417                   if (ch < 32)  // Control character or EOF terminates loop
  418                       break;
  419                   command.append((char) ch);
  420                   expected--;
  421               }
  422   
  423               // Close the socket now that we are done with it
  424               try {
  425                   socket.close();
  426               } catch (IOException e) {
  427                   ;
  428               }
  429   
  430               // Match against our command string
  431               boolean match = command.toString().equals(shutdown);
  432               if (match) {
  433                   break;
  434               } else
  435                   log.warn("StandardServer.await: Invalid command '" +
  436                                      command.toString() + "' received");
  437   
  438           }
  439   
  440           // Close the server socket and return
  441           try {
  442               serverSocket.close();
  443           } catch (IOException e) {
  444               ;
  445           }
  446   
  447       }
  448   
  449   
  450       /**
  451        * Return the specified Service (if it exists); otherwise return
  452        * <code>null</code>.
  453        *
  454        * @param name Name of the Service to be returned
  455        */
  456       public Service findService(String name) {
  457   
  458           if (name == null) {
  459               return (null);
  460           }
  461           synchronized (services) {
  462               for (int i = 0; i < services.length; i++) {
  463                   if (name.equals(services[i].getName())) {
  464                       return (services[i]);
  465                   }
  466               }
  467           }
  468           return (null);
  469   
  470       }
  471   
  472   
  473       /**
  474        * Return the set of Services defined within this Server.
  475        */
  476       public Service[] findServices() {
  477   
  478           return (services);
  479   
  480       }
  481       
  482       /** 
  483        * Return the JMX service names.
  484        */
  485       public ObjectName[] getServiceNames() {
  486           ObjectName onames[]=new ObjectName[ services.length ];
  487           for( int i=0; i<services.length; i++ ) {
  488               onames[i]=((StandardService)services[i]).getObjectName();
  489           }
  490           return onames;
  491       }
  492   
  493   
  494       /**
  495        * Remove the specified Service from the set associated from this
  496        * Server.
  497        *
  498        * @param service The Service to be removed
  499        */
  500       public void removeService(Service service) {
  501   
  502           synchronized (services) {
  503               int j = -1;
  504               for (int i = 0; i < services.length; i++) {
  505                   if (service == services[i]) {
  506                       j = i;
  507                       break;
  508                   }
  509               }
  510               if (j < 0)
  511                   return;
  512               if (services[j] instanceof Lifecycle) {
  513                   try {
  514                       ((Lifecycle) services[j]).stop();
  515                   } catch (LifecycleException e) {
  516                       ;
  517                   }
  518               }
  519               int k = 0;
  520               Service results[] = new Service[services.length - 1];
  521               for (int i = 0; i < services.length; i++) {
  522                   if (i != j)
  523                       results[k++] = services[i];
  524               }
  525               services = results;
  526   
  527               // Report this property change to interested listeners
  528               support.firePropertyChange("service", service, null);
  529           }
  530   
  531       }
  532   
  533   
  534       // --------------------------------------------------------- Public Methods
  535   
  536   
  537       /**
  538        * Add a property change listener to this component.
  539        *
  540        * @param listener The listener to add
  541        */
  542       public void addPropertyChangeListener(PropertyChangeListener listener) {
  543   
  544           support.addPropertyChangeListener(listener);
  545   
  546       }
  547   
  548   
  549       /**
  550        * Remove a property change listener from this component.
  551        *
  552        * @param listener The listener to remove
  553        */
  554       public void removePropertyChangeListener(PropertyChangeListener listener) {
  555   
  556           support.removePropertyChangeListener(listener);
  557   
  558       }
  559   
  560   
  561       /**
  562        * Return a String representation of this component.
  563        */
  564       public String toString() {
  565   
  566           StringBuffer sb = new StringBuffer("StandardServer[");
  567           sb.append(getPort());
  568           sb.append("]");
  569           return (sb.toString());
  570   
  571       }
  572   
  573   
  574       /**
  575        * Write the configuration information for this entire <code>Server</code>
  576        * out to the server.xml configuration file.
  577        *
  578        * @exception javax.management.InstanceNotFoundException if the managed resource object
  579        *  cannot be found
  580        * @exception javax.management.MBeanException if the initializer of the object throws
  581        *  an exception, or persistence is not supported
  582        * @exception javax.management.RuntimeOperationsException if an exception is reported
  583        *  by the persistence mechanism
  584        */
  585       public synchronized void storeConfig() throws Exception {
  586   
  587           ObjectName sname = null;    
  588           try {
  589              sname = new ObjectName("Catalina:type=StoreConfig");
  590              if(mserver.isRegistered(sname)) {
  591                  mserver.invoke(sname, "storeConfig", null, null);            
  592              } else
  593                  log.error("StoreConfig mbean not registered" + sname);
  594           } catch (Throwable t) {
  595               log.error(t);
  596           }
  597   
  598       }
  599   
  600   
  601       /**
  602        * Write the configuration information for <code>Context</code>
  603        * out to the specified configuration file.
  604        *
  605        * @exception javax.management.InstanceNotFoundException if the managed resource object
  606        *  cannot be found
  607        * @exception javax.management.MBeanException if the initializer of the object throws
  608        *  an exception, or persistence is not supported
  609        * @exception javax.management.RuntimeOperationsException if an exception is reported
  610        *  by the persistence mechanism
  611        */
  612       public synchronized void storeContext(Context context) throws Exception {
  613           
  614           ObjectName sname = null;    
  615           try {
  616              sname = new ObjectName("Catalina:type=StoreConfig");
  617              if(mserver.isRegistered(sname)) {
  618                  mserver.invoke(sname, "store",
  619                      new Object[] {context}, 
  620                      new String [] { "java.lang.String"});
  621              } else
  622                  log.error("StoreConfig mbean not registered" + sname);
  623           } catch (Throwable t) {
  624               log.error(t);
  625           }
  626    
  627       }
  628   
  629   
  630       /**
  631        * Return true if naming should be used.
  632        */
  633       private boolean isUseNaming() {
  634           boolean useNaming = true;
  635           // Reading the "catalina.useNaming" environment variable
  636           String useNamingProperty = System.getProperty("catalina.useNaming");
  637           if ((useNamingProperty != null)
  638               && (useNamingProperty.equals("false"))) {
  639               useNaming = false;
  640           }
  641           return useNaming;
  642       }
  643   
  644   
  645       // ------------------------------------------------------ Lifecycle Methods
  646   
  647   
  648       /**
  649        * Add a LifecycleEvent listener to this component.
  650        *
  651        * @param listener The listener to add
  652        */
  653       public void addLifecycleListener(LifecycleListener listener) {
  654   
  655           lifecycle.addLifecycleListener(listener);
  656   
  657       }
  658   
  659   
  660       /**
  661        * Get the lifecycle listeners associated with this lifecycle. If this
  662        * Lifecycle has no listeners registered, a zero-length array is returned.
  663        */
  664       public LifecycleListener[] findLifecycleListeners() {
  665   
  666           return lifecycle.findLifecycleListeners();
  667   
  668       }
  669   
  670   
  671       /**
  672        * Remove a LifecycleEvent listener from this component.
  673        *
  674        * @param listener The listener to remove
  675        */
  676       public void removeLifecycleListener(LifecycleListener listener) {
  677   
  678           lifecycle.removeLifecycleListener(listener);
  679   
  680       }
  681   
  682   
  683       /**
  684        * Prepare for the beginning of active use of the public methods of this
  685        * component.  This method should be called before any of the public
  686        * methods of this component are utilized.  It should also send a
  687        * LifecycleEvent of type START_EVENT to any registered listeners.
  688        *
  689        * @exception LifecycleException if this component detects a fatal error
  690        *  that prevents this component from being used
  691        */
  692       public void start() throws LifecycleException {
  693   
  694           // Validate and update our current component state
  695           if (started) {
  696               log.debug(sm.getString("standardServer.start.started"));
  697               return;
  698           }
  699   
  700           // Notify our interested LifecycleListeners
  701           lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
  702   
  703           lifecycle.fireLifecycleEvent(START_EVENT, null);
  704           started = true;
  705   
  706           // Start our defined Services
  707           synchronized (services) {
  708               for (int i = 0; i < services.length; i++) {
  709                   if (services[i] instanceof Lifecycle)
  710                       ((Lifecycle) services[i]).start();
  711               }
  712           }
  713   
  714           // Notify our interested LifecycleListeners
  715           lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
  716   
  717       }
  718   
  719   
  720       /**
  721        * Gracefully terminate the active use of the public methods of this
  722        * component.  This method should be the last one called on a given
  723        * instance of this component.  It should also send a LifecycleEvent
  724        * of type STOP_EVENT to any registered listeners.
  725        *
  726        * @exception LifecycleException if this component detects a fatal error
  727        *  that needs to be reported
  728        */
  729       public void stop() throws LifecycleException {
  730   
  731           // Validate and update our current component state
  732           if (!started)
  733               return;
  734   
  735           // Notify our interested LifecycleListeners
  736           lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);
  737   
  738           lifecycle.fireLifecycleEvent(STOP_EVENT, null);
  739           started = false;
  740   
  741           // Stop our defined Services
  742           for (int i = 0; i < services.length; i++) {
  743               if (services[i] instanceof Lifecycle)
  744                   ((Lifecycle) services[i]).stop();
  745           }
  746   
  747           // Notify our interested LifecycleListeners
  748           lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
  749   
  750           if (port == -1)
  751               stopAwait();
  752   
  753       }
  754   
  755       public void init() throws Exception {
  756           initialize();
  757       }
  758       
  759       /**
  760        * Invoke a pre-startup initialization. This is used to allow connectors
  761        * to bind to restricted ports under Unix operating environments.
  762        */
  763       public void initialize()
  764           throws LifecycleException 
  765       {
  766           if (initialized) {
  767                   log.info(sm.getString("standardServer.initialize.initialized"));
  768               return;
  769           }
  770           lifecycle.fireLifecycleEvent(INIT_EVENT, null);
  771           initialized = true;
  772   
  773           if( oname==null ) {
  774               try {
  775                   oname=new ObjectName( "Catalina:type=Server");
  776                   Registry.getRegistry(null, null)
  777                       .registerComponent(this, oname, null );
  778               } catch (Exception e) {
  779                   log.error("Error registering ",e);
  780               }
  781           }
  782           
  783           // Register global String cache
  784           try {
  785               ObjectName oname2 = 
  786                   new ObjectName(oname.getDomain() + ":type=StringCache");
  787               Registry.getRegistry(null, null)
  788                   .registerComponent(new StringCache(), oname2, null );
  789           } catch (Exception e) {
  790               log.error("Error registering ",e);
  791           }
  792   
  793           // Initialize our defined Services
  794           for (int i = 0; i < services.length; i++) {
  795               services[i].initialize();
  796           }
  797       }
  798       
  799       protected String type;
  800       protected String domain;
  801       protected String suffix;
  802       protected ObjectName oname;
  803       protected MBeanServer mserver;
  804   
  805       public ObjectName getObjectName() {
  806           return oname;
  807       }
  808   
  809       public String getDomain() {
  810           return domain;
  811       }
  812   
  813       public ObjectName preRegister(MBeanServer server,
  814                                     ObjectName name) throws Exception {
  815           oname=name;
  816           mserver=server;
  817           domain=name.getDomain();
  818           return name;
  819       }
  820   
  821       public void postRegister(Boolean registrationDone) {
  822       }
  823   
  824       public void preDeregister() throws Exception {
  825       }
  826   
  827       public void postDeregister() {
  828       }
  829       
  830   }

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