![JAR search and dependency download from the Maven repository](/logo.png)
org.apache.catalina.core.StandardServer Maven / Gradle / Ivy
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.catalina.core; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.IOException; import java.io.InputStream; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.security.AccessControlException; import java.util.Random; import javax.management.ObjectName; import org.apache.catalina.Context; import org.apache.catalina.LifecycleException; import org.apache.catalina.LifecycleState; import org.apache.catalina.Server; import org.apache.catalina.Service; import org.apache.catalina.deploy.NamingResources; import org.apache.catalina.mbeans.MBeanFactory; import org.apache.catalina.mbeans.MBeanUtils; import org.apache.catalina.startup.Catalina; import org.apache.catalina.util.LifecycleMBeanBase; import org.apache.catalina.util.ServerInfo; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.buf.StringCache; import org.apache.tomcat.util.res.StringManager; /** * Standard implementation of the Server interface, available for use * (but not required) when deploying and starting Catalina. * * @author Craig R. McClanahan * @version $Id: StandardServer.java 1066321 2011-02-02 03:45:05Z kkolinko $ */ public final class StandardServer extends LifecycleMBeanBase implements Server { private static final Log log = LogFactory.getLog(StandardServer.class); // ------------------------------------------------------------ Constructor /** * Construct a default instance of this class. */ public StandardServer() { super(); globalNamingResources = new NamingResources(); globalNamingResources.setContainer(this); if (isUseNaming()) { if (namingContextListener == null) { namingContextListener = new NamingContextListener(); addLifecycleListener(namingContextListener); } } } // ----------------------------------------------------- Instance Variables /** * Global naming resources context. */ private javax.naming.Context globalNamingContext = null; /** * Global naming resources. */ private NamingResources globalNamingResources = null; /** * Descriptive information about this Server implementation. */ private static final String info = "org.apache.catalina.core.StandardServer/1.0"; /** * The naming context listener for this web application. */ private NamingContextListener namingContextListener = null; /** * The port number on which we wait for shutdown commands. */ private int port = 8005; /** * The address on which we wait for shutdown commands. */ private String address = "localhost"; /** * A random number generator that is only used if * the shutdown command string is longer than 1024 characters. */ private Random random = null; /** * The set of Services associated with this Server. */ private Service services[] = new Service[0]; /** * The shutdown command string we are looking for. */ private String shutdown = "SHUTDOWN"; /** * The string manager for this package. */ private static final StringManager sm = StringManager.getManager(Constants.Package); /** * The property change support for this component. */ protected PropertyChangeSupport support = new PropertyChangeSupport(this); private volatile boolean stopAwait = false; private Catalina catalina = null; private ClassLoader parentClassLoader = null; /** * Thread that currently is inside our await() method. */ private volatile Thread awaitThread = null; /** * Server socket that is used to wait for the shutdown command. */ private volatile ServerSocket awaitSocket = null; // ------------------------------------------------------------- Properties /** * Return the global naming resources context. */ public javax.naming.Context getGlobalNamingContext() { return (this.globalNamingContext); } /** * Set the global naming resources context. * * @param globalNamingContext The new global naming resource context */ public void setGlobalNamingContext (javax.naming.Context globalNamingContext) { this.globalNamingContext = globalNamingContext; } /** * Return the global naming resources. */ @Override public NamingResources getGlobalNamingResources() { return (this.globalNamingResources); } /** * Set the global naming resources. * * @param globalNamingResources The new global naming resources */ @Override public void setGlobalNamingResources (NamingResources globalNamingResources) { NamingResources oldGlobalNamingResources = this.globalNamingResources; this.globalNamingResources = globalNamingResources; this.globalNamingResources.setContainer(this); support.firePropertyChange("globalNamingResources", oldGlobalNamingResources, this.globalNamingResources); } /** * Return descriptive information about this Server implementation and * the corresponding version number, in the format *
* out to the server.xml configuration file. * * @exception javax.management.InstanceNotFoundException * if the managed resource object cannot be found * @exception javax.management.MBeanException * if the initializer of the object throws an exception, or * persistence is not supported * @exception javax.management.RuntimeOperationsException * if an exception is reported by the persistence mechanism */ public synchronized void storeConfig() throws Exception { ObjectName sname = new ObjectName("Catalina:type=StoreConfig"); mserver.invoke(sname, "storeConfig", null, null); } /** * Write the configuration information for<description>/<version>
. */ @Override public String getInfo() { return (info); } /** * Report the current Tomcat Server Release number * @return Tomcat release identifier */ public String getServerInfo() { return ServerInfo.getServerInfo(); } /** * Return the port number we listen to for shutdown commands. */ @Override public int getPort() { return (this.port); } /** * Set the port number we listen to for shutdown commands. * * @param port The new port number */ @Override public void setPort(int port) { this.port = port; } /** * Return the address on which we listen to for shutdown commands. */ @Override public String getAddress() { return (this.address); } /** * Set the address on which we listen to for shutdown commands. * * @param address The new address */ @Override public void setAddress(String address) { this.address = address; } /** * Return the shutdown command string we are waiting for. */ @Override public String getShutdown() { return (this.shutdown); } /** * Set the shutdown command we are waiting for. * * @param shutdown The new shutdown command */ @Override public void setShutdown(String shutdown) { this.shutdown = shutdown; } /** * Return the outer Catalina startup/shutdown component if present. */ @Override public Catalina getCatalina() { return catalina; } /** * Set the outer Catalina startup/shutdown component if present. */ @Override public void setCatalina(Catalina catalina) { this.catalina = catalina; } // --------------------------------------------------------- Server Methods /** * Add a new Service to the set of defined Services. * * @param service The Service to be added */ @Override public void addService(Service service) { service.setServer(this); synchronized (services) { Service results[] = new Service[services.length + 1]; System.arraycopy(services, 0, results, 0, services.length); results[services.length] = service; services = results; if (getState().isAvailable()) { try { service.start(); } catch (LifecycleException e) { // Ignore } } // Report this property change to interested listeners support.firePropertyChange("service", null, service); } } public void stopAwait() { stopAwait=true; Thread t = awaitThread; if (t != null) { ServerSocket s = awaitSocket; if (s != null) { awaitSocket = null; try { s.close(); } catch (IOException e) { // Ignored } } t.interrupt(); try { t.join(1000); } catch (InterruptedException e) { // Ignored } } } /** * Wait until a proper shutdown command is received, then return. * This keeps the main thread alive - the thread pool listening for http * connections is daemon threads. */ @Override public void await() { // Negative values - don't wait on port - tomcat is embedded or we just don't like ports if( port == -2 ) { // undocumented yet - for embedding apps that are around, alive. return; } if( port==-1 ) { try { awaitThread = Thread.currentThread(); while(!stopAwait) { try { Thread.sleep( 10000 ); } catch( InterruptedException ex ) { // continue and check the flag } } } finally { awaitThread = null; } return; } // Set up a server socket to wait on try { awaitSocket = new ServerSocket(port, 1, InetAddress.getByName(address)); } catch (IOException e) { log.error("StandardServer.await: create[" + address + ":" + port + "]: ", e); return; } try { awaitThread = Thread.currentThread(); // Loop waiting for a connection and a valid command while (!stopAwait) { ServerSocket serverSocket = awaitSocket; if (serverSocket == null) { break; } // Wait for the next connection Socket socket = null; StringBuilder command = new StringBuilder(); try { InputStream stream; try { socket = serverSocket.accept(); socket.setSoTimeout(10 * 1000); // Ten seconds stream = socket.getInputStream(); } catch (AccessControlException ace) { log.warn("StandardServer.accept security exception: " + ace.getMessage(), ace); continue; } catch (IOException e) { if (stopAwait) { // Wait was aborted with socket.close() break; } log.error("StandardServer.await: accept: ", e); break; } // Read a set of characters from the socket int expected = 1024; // Cut off to avoid DoS attack while (expected < shutdown.length()) { if (random == null) random = new Random(); expected += (random.nextInt() % 1024); } while (expected > 0) { int ch = -1; try { ch = stream.read(); } catch (IOException e) { log.warn("StandardServer.await: read: ", e); ch = -1; } if (ch < 32) // Control character or EOF terminates loop break; command.append((char) ch); expected--; } } finally { // Close the socket now that we are done with it try { if (socket != null) { socket.close(); } } catch (IOException e) { // Ignore } } // Match against our command string boolean match = command.toString().equals(shutdown); if (match) { log.info(sm.getString("standardServer.shutdownViaPort")); break; } else log.warn("StandardServer.await: Invalid command '" + command.toString() + "' received"); } } finally { ServerSocket serverSocket = awaitSocket; awaitThread = null; awaitSocket = null; // Close the server socket and return if (serverSocket != null) { try { serverSocket.close(); } catch (IOException e) { // Ignore } } } } /** * Return the specified Service (if it exists); otherwise return *null
. * * @param name Name of the Service to be returned */ @Override public Service findService(String name) { if (name == null) { return (null); } synchronized (services) { for (int i = 0; i < services.length; i++) { if (name.equals(services[i].getName())) { return (services[i]); } } } return (null); } /** * Return the set of Services defined within this Server. */ @Override public Service[] findServices() { return (services); } /** * Return the JMX service names. */ public ObjectName[] getServiceNames() { ObjectName onames[]=new ObjectName[ services.length ]; for( int i=0; iServer Context
* out to the specified configuration file. * * @exception javax.management.InstanceNotFoundException if the managed resource object * cannot be found * @exception javax.management.MBeanException if the initializer of the object throws * an exception, or persistence is not supported * @exception javax.management.RuntimeOperationsException if an exception is reported * by the persistence mechanism */ public synchronized void storeContext(Context context) throws Exception { ObjectName sname = null; try { sname = new ObjectName("Catalina:type=StoreConfig"); if(mserver.isRegistered(sname)) { mserver.invoke(sname, "store", new Object[] {context}, new String [] { "java.lang.String"}); } else log.error("StoreConfig mbean not registered" + sname); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.error(t); } } /** * Return true if naming should be used. */ private boolean isUseNaming() { boolean useNaming = true; // Reading the "catalina.useNaming" environment variable String useNamingProperty = System.getProperty("catalina.useNaming"); if ((useNamingProperty != null) && (useNamingProperty.equals("false"))) { useNaming = false; } return useNaming; } /** * Start nested components ({@link Service}s) and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}. * * @exception LifecycleException if this component detects a fatal error * that prevents this component from being used */ @Override protected void startInternal() throws LifecycleException { fireLifecycleEvent(CONFIGURE_START_EVENT, null); setState(LifecycleState.STARTING); // Start our defined Services synchronized (services) { for (int i = 0; i < services.length; i++) { services[i].start(); } } } /** * Stop nested components ({@link Service}s) and implement the requirements * of {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. * * @exception LifecycleException if this component detects a fatal error * that needs to be reported */ @Override protected void stopInternal() throws LifecycleException { setState(LifecycleState.STOPPING); fireLifecycleEvent(CONFIGURE_STOP_EVENT, null); // Stop our defined Services for (int i = 0; i < services.length; i++) { services[i].stop(); } stopAwait(); } /** * Invoke a pre-startup initialization. This is used to allow connectors * to bind to restricted ports under Unix operating environments. */ @Override protected void initInternal() throws LifecycleException { super.initInternal(); // Register global String cache // Note although the cache is global, if there are multiple Servers // present in the JVM (may happen when embedding) then the same cache // will be registered under multiple names onameStringCache = register(new StringCache(), "type=StringCache"); // Register the MBeanFactory MBeanFactory factory = new MBeanFactory(); factory.setContainer(this); onameMBeanFactory = register(factory, "type=MBeanFactory"); // Register the naming resources onameNamingResoucres = register(globalNamingResources, "type=NamingResources"); // Initialize our defined Services for (int i = 0; i < services.length; i++) { services[i].init(); } } @Override protected void destroyInternal() throws LifecycleException { // Destroy our defined Services for (int i = 0; i < services.length; i++) { services[i].destroy(); } unregister(onameMBeanFactory); unregister(onameStringCache); unregister(onameNamingResoucres); super.destroyInternal(); } /** * Return the parent class loader for this component. */ @Override public ClassLoader getParentClassLoader() { if (parentClassLoader != null) return (parentClassLoader); if (catalina != null) { return (catalina.getParentClassLoader()); } return (ClassLoader.getSystemClassLoader()); } /** * Set the parent class loader for this server. * * @param parent The new parent class loader */ @Override public void setParentClassLoader(ClassLoader parent) { ClassLoader oldParentClassLoader = this.parentClassLoader; this.parentClassLoader = parent; support.firePropertyChange("parentClassLoader", oldParentClassLoader, this.parentClassLoader); } private ObjectName onameStringCache; private ObjectName onameMBeanFactory; private ObjectName onameNamingResoucres; /** * Obtain the MBean domain for this server. The domain is obtained using * the following search order: **
*/ @Override protected String getDomainInternal() { String domain = null; Service[] services = findServices(); if (services.length > 0) { Service service = services[0]; if (service != null) { domain = MBeanUtils.getDomain(service); } } return domain; } @Override protected final String getObjectNameKeyProperties() { return "type=Server"; } }- Name of first {@link org.apache.catalina.Engine}.
*- Name of first {@link Service}.
*
© 2015 - 2025 Weber Informatics LLC | Privacy Policy