/* * 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.tomcat.util.net; import java.net.InetAddress; import java.util.concurrent.Executor; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.res.StringManager; /** * APR tailored thread pool, providing the following services: * <ul> * <li>Socket acceptor thread</li> * <li>Socket poller thread</li> * <li>Sendfile thread</li> * <li>Worker threads pool</li> * </ul> * * When switching to Java 5, there's an opportunity to use the virtual * machine's thread pool. * * @author Mladen Turk * @author Remy Maucherat */ public abstract class BaseEndpoint { // -------------------------------------------------------------- Constants protected static Log log = LogFactory.getLog(BaseEndpoint.class); protected static StringManager sm = StringManager.getManager("org.apache.tomcat.util.net.res"); /** * The Request attribute key for the cipher suite. */ public static final String CIPHER_SUITE_KEY = "javax.servlet.request.cipher_suite"; /** * The Request attribute key for the key size. */ public static final String KEY_SIZE_KEY = "javax.servlet.request.key_size"; /** * The Request attribute key for the client certificate chain. */ public static final String CERTIFICATE_KEY = "javax.servlet.request.X509Certificate"; /** * The Request attribute key for the session id. * This one is a Tomcat extension to the Servlet spec. */ public static final String SESSION_ID_KEY = "javax.servlet.request.ssl_session"; // ----------------------------------------------------------------- Fields /** * Running state of the endpoint. */ protected volatile boolean running = false; /** * Will be set to true whenever the endpoint is paused. */ protected volatile boolean paused = false; /** * Track the initialization state of the endpoint. */ protected boolean initialized = false; /** * Current worker threads busy count. */ protected int curThreadsBusy = 0; /** * Current worker threads count. */ protected int curThreads = 0; /** * Sequence number used to generate thread names. */ protected int sequence = 0; // ------------------------------------------------------------- Properties /** * External Executor based thread pool. */ protected Executor executor = null; public void setExecutor(Executor executor) { this.executor = executor; } public Executor getExecutor() { return executor; } /** * Maximum amount of worker threads. */ protected int maxThreads = 200; public void setMaxThreads(int maxThreads) { this.maxThreads = maxThreads; } public int getMaxThreads() { return maxThreads; } /** * Priority of the acceptor and poller threads. */ protected int threadPriority = Thread.NORM_PRIORITY; public void setThreadPriority(int threadPriority) { this.threadPriority = threadPriority; } public int getThreadPriority() { return threadPriority; } /** * Server socket port. */ protected int port; public int getPort() { return port; } public void setPort(int port ) { this.port=port; } /** * Address for the server socket. */ protected InetAddress address; public InetAddress getAddress() { return address; } public void setAddress(InetAddress address) { this.address = address; } /** * Allows the server developer to specify the backlog that * should be used for server sockets. By default, this value * is 100. */ protected int backlog = 100; public void setBacklog(int backlog) { if (backlog > 0) this.backlog = backlog; } public int getBacklog() { return backlog; } /** * Socket TCP no delay. */ protected boolean tcpNoDelay = false; public boolean getTcpNoDelay() { return tcpNoDelay; } public void setTcpNoDelay(boolean tcpNoDelay) { this.tcpNoDelay = tcpNoDelay; } /** * Socket linger. */ protected int soLinger = 100; public int getSoLinger() { return soLinger; } public void setSoLinger(int soLinger) { this.soLinger = soLinger; } /** * Socket timeout. */ protected int soTimeout = -1; public int getSoTimeout() { return soTimeout; } public void setSoTimeout(int soTimeout) { this.soTimeout = soTimeout; } /** * The default is true - the created threads will be * in daemon mode. If set to false, the control thread * will not be daemon - and will keep the process alive. */ protected boolean daemon = true; public void setDaemon(boolean b) { daemon = b; } public boolean getDaemon() { return daemon; } /** * Name of the thread pool, which will be used for naming child threads. */ protected String name = "TP"; public void setName(String name) { this.name = name; } public String getName() { return name; } /** * Dummy maxSpareThreads property. */ public int getMaxSpareThreads() { return 0; } /** * Dummy minSpareThreads property. */ public int getMinSpareThreads() { return 0; } // --------------------------------------------------------- Public Methods /** * Return the amount of threads that are managed by the pool. * * @return the amount of threads that are managed by the pool */ public int getCurrentThreadCount() { return curThreads; } /** * Return the amount of threads currently busy. * * @return the amount of threads currently busy */ public int getCurrentThreadsBusy() { return curThreadsBusy; } /** * Return the state of the endpoint. * * @return true if the endpoint is running, false otherwise */ public boolean isRunning() { return running; } /** * Return the state of the endpoint. * * @return true if the endpoint is paused, false otherwise */ public boolean isPaused() { return paused; } // ----------------------------------------------- Public Lifecycle Methods /** * Initialize the endpoint. */ public abstract void init() throws Exception; /** * Start the APR endpoint, creating acceptor, poller and sendfile threads. */ public abstract void start() throws Exception; /** * Pause the endpoint, which will make it stop accepting new sockets. */ public void pause() { if (running && !paused) { paused = true; unlockAccept(); } } /** * Resume the endpoint, which will make it start accepting new sockets * again. */ public void resume() { if (running) { paused = false; } } /** * Stop the endpoint. This will cause all processing threads to stop. */ public abstract void stop(); /** * Deallocate APR memory pools, and close server socket. */ public abstract void destroy() throws Exception; // ------------------------------------------------------ Protected Methods /** * Get a sequence number used for thread naming. */ protected int getSequence() { return sequence++; } /** * Unlock the server socket accept using a bugus connection. */ protected void unlockAccept() { java.net.Socket s = null; try { // Need to create a connection to unlock the accept(); if (address == null) { s = new java.net.Socket(InetAddress.getByName("localhost").getHostAddress(), port); } else { s = new java.net.Socket(address, port); // setting soLinger to a small value will help shutdown the // connection quicker s.setSoLinger(true, 0); } } catch(Exception e) { if (log.isDebugEnabled()) { log.debug(sm.getString("endpoint.debug.unlock", "" + port), e); } } finally { if (s != null) { try { s.close(); } catch (Exception e) { // Ignore } } } } }