Added in the Executor skeleton. the executor gets created in the service, so that...
authorfhanik <fhanik@13f79535-47bb-0310-9956-ffa450edef68>
Wed, 21 Mar 2007 18:00:39 +0000 (18:00 +0000)
committerfhanik <fhanik@13f79535-47bb-0310-9956-ffa450edef68>
Wed, 21 Mar 2007 18:00:39 +0000 (18:00 +0000)
Feel free to hack away on improvements or yell at me if this is completely not what was intended and I will pull it out

git-svn-id: https://svn.apache.org/repos/asf/tomcat/tc6.0.x/trunk@520968 13f79535-47bb-0310-9956-ffa450edef68

conf/server.xml
java/org/apache/catalina/Executor.java [new file with mode: 0644]
java/org/apache/catalina/Service.java
java/org/apache/catalina/core/StandardService.java
java/org/apache/catalina/core/StandardThreadExecutor.java [new file with mode: 0644]
java/org/apache/catalina/startup/Catalina.java
java/org/apache/catalina/startup/ConnectorCreateRule.java
java/org/apache/catalina/startup/EngineRuleSet.java
java/org/apache/catalina/startup/SetAllPropertiesRule.java
java/org/apache/tomcat/util/net/NioEndpoint.java

index 08e11f7..3acca4a 100644 (file)
        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
diff --git a/java/org/apache/catalina/Executor.java b/java/org/apache/catalina/Executor.java
new file mode 100644 (file)
index 0000000..3d903ac
--- /dev/null
@@ -0,0 +1,7 @@
+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
index a8e8d6a..455514b 100644 (file)
@@ -5,9 +5,9 @@
  * 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.
@@ -20,7 +20,6 @@ package org.apache.catalina;
 
 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>
@@ -37,7 +36,6 @@ import org.apache.catalina.connector.Connector;
 
 public interface Service {
 
-
     // ------------------------------------------------------------- Properties
 
 
@@ -47,7 +45,6 @@ public interface Service {
      */
     public Container getContainer();
 
-
     /**
      * Set the <code>Container</code> that handles requests for all
      * <code>Connectors</code> associated with this Service.
@@ -56,7 +53,6 @@ public interface Service {
      */
     public void setContainer(Container container);
 
-
     /**
      * Return descriptive information about this Service implementation and
      * the corresponding version number, in the format
@@ -64,13 +60,11 @@ public interface Service {
      */
     public String getInfo();
 
-
     /**
      * Return the name of this Service.
      */
     public String getName();
 
-
     /**
      * Set the name of this Service.
      *
@@ -78,13 +72,11 @@ public interface 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).
      *
@@ -92,7 +84,6 @@ public interface Service {
      */
     public void setServer(Server server);
 
-    
     // --------------------------------------------------------- Public Methods
 
 
@@ -104,13 +95,11 @@ public interface Service {
      */
     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
@@ -126,7 +115,31 @@ public interface Service {
      *
      * @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);
 
 }
index 99415be..0764c1e 100644 (file)
@@ -38,6 +38,8 @@ import org.apache.catalina.util.StringManager;
 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;
 
 
 /**
@@ -103,7 +105,11 @@ public class StandardService
      * 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
@@ -413,6 +419,68 @@ public class StandardService
         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);
+                }
+            }
+        }
+    }
+
 
 
     /**
@@ -457,6 +525,12 @@ public class StandardService
                     ((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);
diff --git a/java/org/apache/catalina/core/StandardThreadExecutor.java b/java/org/apache/catalina/core/StandardThreadExecutor.java
new file mode 100644 (file)
index 0000000..f0f586d
--- /dev/null
@@ -0,0 +1,204 @@
+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
index ae2692b..f2fcb46 100644 (file)
@@ -302,13 +302,27 @@ public class Catalina extends Embedded {
                             "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
index 308b3dd..d4bd869 100644 (file)
@@ -23,6 +23,10 @@ package org.apache.catalina.startup;
 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;
 
 
 /**
@@ -41,7 +45,20 @@ public class ConnectorCreateRule extends Rule {
      * @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});
     }
 
 
index 694b7ce..5c5cd53 100644 (file)
@@ -89,7 +89,7 @@ public class EngineRuleSet extends RuleSetBase {
      *  should be added.
      */
     public void addRuleInstances(Digester digester) {
-
+        
         digester.addObjectCreate(prefix + "Engine",
                                  "org.apache.catalina.core.StandardEngine",
                                  "className");
index 4c99c47..f971b65 100644 (file)
@@ -22,20 +22,26 @@ import org.xml.sax.Attributes;
 
 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
 
@@ -56,7 +62,8 @@ public class SetAllPropertiesRule extends Rule {
                 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);
         }
 
     }
index fb790b0..b96a9cc 100644 (file)
@@ -777,10 +777,13 @@ public class NioEndpoint {
         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;
         }
     }