Documentation at /docs/config/service.html
-->
<Service name="Catalina">
-
+
+ <!--The connectors can use a shared executor, you can define one or more named thread pools-->
+ <!--
+ <Executor name="tomcatThreadPool" namePrefix="catalina-exec-" maxThreads="1000" minSpareThreads="4"/>
+ -->
+
+
<!-- A "Connector" represents an endpoint by which requests are received
and responses are returned. Documentation at :
Java HTTP Connector: /docs/config/http.html (blocking & non-blocking)
Define a non-SSL HTTP/1.1 Connector on port 8080
-->
<Connector port="8080" protocol="HTTP/1.1"
- maxThreads="150" connectionTimeout="20000"
+ connectionTimeout="20000"
redirectPort="8443" />
-
+ <!-- A "Connector" using the shared thread pool-->
+ <!--
+ <Connector executor="tomcatThreadPool"
+ port="8080" protocol="HTTP/1.1"
+ connectionTimeout="20000"
+ redirectPort="8443" />
+ -->
<!-- Define a SSL HTTP/1.1 Connector on port 8443
This connector uses the JSSE configuration, when using APR, the
connector should be using the OpenSSL style configuration
--- /dev/null
+package org.apache.catalina;\r
+\r
+\r
+\r
+public interface Executor extends java.util.concurrent.Executor, Lifecycle {\r
+ public String getName();\r
+}
\ No newline at end of file
* 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.
import org.apache.catalina.connector.Connector;
-
/**
* A <strong>Service</strong> is a group of one or more
* <strong>Connectors</strong> that share a single <strong>Container</strong>
public interface Service {
-
// ------------------------------------------------------------- Properties
*/
public Container getContainer();
-
/**
* Set the <code>Container</code> that handles requests for all
* <code>Connectors</code> associated with this Service.
*/
public void setContainer(Container container);
-
/**
* Return descriptive information about this Service implementation and
* the corresponding version number, in the format
*/
public String getInfo();
-
/**
* Return the name of this Service.
*/
public String getName();
-
/**
* Set the name of this Service.
*
*/
public void setName(String name);
-
/**
* Return the <code>Server</code> with which we are associated (if any).
*/
public Server getServer();
-
/**
* Set the <code>Server</code> with which we are associated (if any).
*
*/
public void setServer(Server server);
-
// --------------------------------------------------------- Public Methods
*/
public void addConnector(Connector connector);
-
/**
* Find and return the set of Connectors associated with this Service.
*/
public Connector[] findConnectors();
-
/**
* Remove the specified Connector from the set associated from this
* Service. The removed Connector will also be disassociated from our
*
* @exception LifecycleException If this server was already initialized.
*/
- public void initialize()
- throws LifecycleException;
+ public void initialize() throws LifecycleException;
+
+ /**
+ * Adds a named executor to the service
+ * @param ex Executor
+ */
+ public void addExecutor(Executor ex);
+
+ /**
+ * Retrieves all executors
+ * @return Executor[]
+ */
+ public Executor[] findExecutors();
+
+ /**
+ * Retrieves executor by name, null if not found
+ * @param name String
+ * @return Executor
+ */
+ public Executor getExecutor(String name);
+
+ /**
+ * Removes an executor from the service
+ * @param ex Executor
+ */
+ public void removeExecutor(Executor ex);
}
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.modeler.Registry;
+import java.util.ArrayList;
+import org.apache.catalina.Executor;
/**
* The set of Connectors associated with this Service.
*/
protected Connector connectors[] = new Connector[0];
-
+
+ /**
+ *
+ */
+ protected ArrayList<Executor> executors = new ArrayList<Executor>();
/**
* The Container associated with this Service. (In the case of the
lifecycle.removeLifecycleListener(listener);
}
+
+ /**
+ * Adds a named executor to the service
+ * @param ex Executor
+ */
+ public void addExecutor(Executor ex) {
+ synchronized (executors) {
+ if (!executors.contains(ex)) {
+ executors.add(ex);
+ if (started)
+ try {
+ ex.start();
+ } catch (LifecycleException x) {
+ log.error("Executor.start", x);
+ }
+ }
+ }
+ }
+
+ /**
+ * Retrieves all executors
+ * @return Executor[]
+ */
+ public Executor[] findExecutors() {
+ synchronized (executors) {
+ Executor[] arr = new Executor[executors.size()];
+ executors.toArray(arr);
+ return arr;
+ }
+ }
+
+ /**
+ * Retrieves executor by name, null if not found
+ * @param name String
+ * @return Executor
+ */
+ public Executor getExecutor(String name) {
+ synchronized (executors) {
+ for (int i = 0; i < executors.size(); i++) {
+ if (name.equals(executors.get(i).getName()))
+ return executors.get(i);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Removes an executor from the service
+ * @param ex Executor
+ */
+ public void removeExecutor(Executor ex) {
+ synchronized (executors) {
+ if ( executors.remove(ex) && started ) {
+ try {
+ ex.stop();
+ } catch (LifecycleException e) {
+ log.error("Executor.stop", e);
+ }
+ }
+ }
+ }
+
/**
((Lifecycle) connectors[i]).start();
}
}
+
+ synchronized (executors) {
+ for ( int i=0; i<executors.size(); i++ ) {
+ executors.get(i).start();
+ }
+ }
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
--- /dev/null
+package org.apache.catalina.core;\r
+\r
+import java.util.Collection;\r
+import java.util.concurrent.LinkedBlockingQueue;\r
+import java.util.concurrent.ThreadFactory;\r
+import java.util.concurrent.ThreadPoolExecutor;\r
+import java.util.concurrent.TimeUnit;\r
+import java.util.concurrent.atomic.AtomicInteger;\r
+\r
+import org.apache.catalina.Executor;\r
+import org.apache.catalina.LifecycleException;\r
+import org.apache.catalina.LifecycleListener;\r
+import org.apache.catalina.util.LifecycleSupport;\r
+\r
+public class StandardThreadExecutor implements Executor {\r
+ \r
+ // ---------------------------------------------- Properties\r
+ protected int threadPriority = Thread.NORM_PRIORITY;\r
+\r
+ protected boolean daemon = true;\r
+ \r
+ protected String namePrefix = "tomcat-exec-";\r
+ \r
+ protected int maxThreads = 200;\r
+ \r
+ protected int minSpareThreads = 25;\r
+ \r
+ protected int maxIdleTime = 60000;\r
+ \r
+ protected ThreadPoolExecutor executor = null;\r
+ \r
+ protected String name;\r
+ \r
+ private LifecycleSupport lifecycle = new LifecycleSupport(this);\r
+ // ---------------------------------------------- Constructors\r
+ public StandardThreadExecutor() {\r
+ //empty constructor for the digester\r
+ }\r
+ \r
+\r
+ \r
+ // ---------------------------------------------- Public Methods\r
+ public void start() throws LifecycleException {\r
+ lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);\r
+ TaskQueue taskqueue = new TaskQueue();\r
+ TaskThreadFactory tf = new TaskThreadFactory(namePrefix);\r
+ lifecycle.fireLifecycleEvent(START_EVENT, null);\r
+ executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), maxIdleTime, TimeUnit.MILLISECONDS,taskqueue, tf);\r
+ taskqueue.setParent( (ThreadPoolExecutor) executor);\r
+ lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);\r
+ }\r
+ \r
+ public void stop() throws LifecycleException{\r
+ lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);\r
+ lifecycle.fireLifecycleEvent(STOP_EVENT, null);\r
+ if ( executor != null ) executor.shutdown();\r
+ executor = null;\r
+ lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);\r
+ }\r
+ \r
+ public void execute(Runnable command) {\r
+ if ( executor != null ) executor.execute(command);\r
+ else throw new IllegalStateException("StandardThreadPool not started.");\r
+ }\r
+\r
+ public int getThreadPriority() {\r
+ return threadPriority;\r
+ }\r
+\r
+ public boolean isDaemon() {\r
+\r
+ return daemon;\r
+ }\r
+\r
+ public String getNamePrefix() {\r
+ return namePrefix;\r
+ }\r
+\r
+ public int getMaxIdleTime() {\r
+ return maxIdleTime;\r
+ }\r
+\r
+ public int getMaxThreads() {\r
+ return maxThreads;\r
+ }\r
+\r
+ public int getMinSpareThreads() {\r
+ return minSpareThreads;\r
+ }\r
+\r
+ public String getName() {\r
+ return name;\r
+ }\r
+\r
+ public void setThreadPriority(int threadPriority) {\r
+ this.threadPriority = threadPriority;\r
+ }\r
+\r
+ public void setDaemon(boolean daemon) {\r
+ this.daemon = daemon;\r
+ }\r
+\r
+ public void setNamePrefix(String namePrefix) {\r
+ this.namePrefix = namePrefix;\r
+ }\r
+\r
+ public void setMaxIdleTime(int maxIdleTime) {\r
+ this.maxIdleTime = maxIdleTime;\r
+ }\r
+\r
+ public void setMaxThreads(int maxThreads) {\r
+ this.maxThreads = maxThreads;\r
+ }\r
+\r
+ public void setMinSpareThreads(int minSpareThreads) {\r
+ this.minSpareThreads = minSpareThreads;\r
+ }\r
+\r
+ public void setName(String name) {\r
+ this.name = name;\r
+ }\r
+ \r
+ /**\r
+ * Add a LifecycleEvent listener to this component.\r
+ *\r
+ * @param listener The listener to add\r
+ */\r
+ public void addLifecycleListener(LifecycleListener listener) {\r
+ lifecycle.addLifecycleListener(listener);\r
+ }\r
+\r
+\r
+ /**\r
+ * Get the lifecycle listeners associated with this lifecycle. If this \r
+ * Lifecycle has no listeners registered, a zero-length array is returned.\r
+ */\r
+ public LifecycleListener[] findLifecycleListeners() {\r
+ return lifecycle.findLifecycleListeners();\r
+ }\r
+\r
+\r
+ /**\r
+ * Remove a LifecycleEvent listener from this component.\r
+ *\r
+ * @param listener The listener to remove\r
+ */\r
+ public void removeLifecycleListener(LifecycleListener listener) {\r
+ lifecycle.removeLifecycleListener(listener);\r
+ }\r
+\r
+\r
+ \r
+\r
+\r
+ // ---------------------------------------------- TaskQueue Inner Class\r
+ class TaskQueue extends LinkedBlockingQueue<Runnable> {\r
+ ThreadPoolExecutor parent = null;\r
+\r
+ public TaskQueue() {\r
+ super();\r
+ }\r
+\r
+ public TaskQueue(int initialCapacity) {\r
+ super(initialCapacity);\r
+ }\r
+\r
+ public TaskQueue(Collection<? extends Runnable> c) {\r
+ super(c);\r
+ }\r
+\r
+ public void setParent(ThreadPoolExecutor tp) {\r
+ parent = tp;\r
+ }\r
+\r
+ public boolean offer(Runnable o) {\r
+ if (parent != null && parent.getPoolSize() < parent.getMaximumPoolSize())\r
+ return false; //force creation of new threads\r
+ else\r
+ return super.offer(o);\r
+ }\r
+ }\r
+\r
+ // ---------------------------------------------- ThreadFactory Inner Class\r
+ class TaskThreadFactory implements ThreadFactory {\r
+ final ThreadGroup group;\r
+ final AtomicInteger threadNumber = new AtomicInteger(1);\r
+ final String namePrefix;\r
+\r
+ TaskThreadFactory(String namePrefix) {\r
+ SecurityManager s = System.getSecurityManager();\r
+ group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();\r
+ this.namePrefix = namePrefix;\r
+ }\r
+\r
+ public Thread newThread(Runnable r) {\r
+ Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement());\r
+ t.setDaemon(daemon);\r
+ t.setPriority(getThreadPriority());\r
+ return t;\r
+ }\r
+ }\r
+\r
+\r
+}
\ No newline at end of file
"addLifecycleListener",
"org.apache.catalina.LifecycleListener");
+ //Executor
+ digester.addObjectCreate("Server/Service/Executor",
+ "org.apache.catalina.core.StandardThreadExecutor",
+ "className");
+ digester.addSetProperties("Server/Service/Executor");
+
+ digester.addSetNext("Server/Service/Executor",
+ "addExecutor",
+ "org.apache.catalina.Executor");
+
+
digester.addRule("Server/Service/Connector",
new ConnectorCreateRule());
digester.addRule("Server/Service/Connector",
- new SetAllPropertiesRule());
+ new SetAllPropertiesRule(new String[]{"executor"}));
digester.addSetNext("Server/Service/Connector",
"addConnector",
"org.apache.catalina.connector.Connector");
+
+
+
digester.addObjectCreate("Server/Service/Connector/Listener",
null, // MUST be specified in the element
import org.apache.catalina.connector.Connector;
import org.apache.tomcat.util.digester.Rule;
import org.xml.sax.Attributes;
+import org.apache.catalina.Service;
+import org.apache.catalina.Executor;
+import org.apache.tomcat.util.IntrospectionUtils;
+import java.lang.reflect.Method;
/**
* @param attributes The attribute list of this element
*/
public void begin(Attributes attributes) throws Exception {
- digester.push(new Connector(attributes.getValue("protocol")));
+ Service svc = (Service)digester.peek();
+ Executor ex = null;
+ if ( attributes.getValue("executor")!=null ) {
+ ex = svc.getExecutor(attributes.getValue("executor"));
+ }
+ Connector con = new Connector(attributes.getValue("protocol"));
+ if ( ex != null ) _setExecutor(con,ex);
+
+ digester.push(con);
+ }
+
+ public void _setExecutor(Connector con, Executor ex) throws Exception {
+ Method m = IntrospectionUtils.findMethod(con.getProtocolHandler().getClass(),"setExecutor",new Class[] {java.util.concurrent.Executor.class});
+ m.invoke(con.getProtocolHandler(),new Object[] {ex});
}
* should be added.
*/
public void addRuleInstances(Digester digester) {
-
+
digester.addObjectCreate(prefix + "Engine",
"org.apache.catalina.core.StandardEngine",
"className");
import org.apache.tomcat.util.IntrospectionUtils;
import org.apache.tomcat.util.digester.Rule;
+import java.util.HashMap;
/**
* Rule that uses the introspection utils to set properties.
*
* @author Remy Maucherat
+ * @author Filip Hanik
*/
public class SetAllPropertiesRule extends Rule {
-
+
// ----------------------------------------------------------- Constructors
-
+ public SetAllPropertiesRule() {}
+
+ public SetAllPropertiesRule(String[] exclude) {
+ for (int i=0; i<exclude.length; i++ ) if (exclude[i]!=null) this.excludes.put(exclude[i],exclude[i]);
+ }
// ----------------------------------------------------- Instance Variables
-
+ protected HashMap<String,String> excludes = new HashMap<String,String>();
// --------------------------------------------------------- Public Methods
name = attributes.getQName(i);
}
String value = attributes.getValue(i);
- IntrospectionUtils.setProperty(digester.peek(), name, value);
+ if ( !excludes.containsKey(name))
+ IntrospectionUtils.setProperty(digester.peek(), name, value);
}
}
nioChannels.clear();
processorCache.clear();
if ( executor!=null ) {
- ThreadPoolExecutor tpe = (ThreadPoolExecutor)executor;
- tpe.shutdown();
- TaskQueue queue = (TaskQueue)tpe.getQueue();
- queue.setParent(null);
+ if ( executor instanceof ThreadPoolExecutor ) {
+ //this is our internal one, so we need to shut it down
+ ThreadPoolExecutor tpe = (ThreadPoolExecutor) executor;
+ tpe.shutdown();
+ TaskQueue queue = (TaskQueue) tpe.getQueue();
+ queue.setParent(null);
+ }
executor = null;
}
}