001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.servicemix.executors.impl;
018
019 import java.lang.reflect.Method;
020 import java.util.HashMap;
021 import java.util.Map;
022 import java.util.concurrent.ArrayBlockingQueue;
023 import java.util.concurrent.BlockingQueue;
024 import java.util.concurrent.LinkedBlockingQueue;
025 import java.util.concurrent.RejectedExecutionHandler;
026 import java.util.concurrent.SynchronousQueue;
027 import java.util.concurrent.ThreadFactory;
028 import java.util.concurrent.ThreadPoolExecutor;
029 import java.util.concurrent.TimeUnit;
030 import java.util.concurrent.atomic.AtomicInteger;
031
032 import org.apache.servicemix.executors.Executor;
033 import org.apache.servicemix.executors.ExecutorFactory;
034
035 /**
036 * Default implementation of the ExecutorFactory.
037 *
038 * Configuration can be done hierachically.
039 * When an executor is created with an id of <code>foo.bar</code>,
040 * the factory will look for a configuration in the following
041 * way:
042 * <ul>
043 * <li>configs.get("foo.bar")</li>
044 * <li>configs.get("foo")</li>
045 * <li>defaultConfig</li>
046 * </ul>
047 *
048 * @author <a href="mailto:gnodet [at] gmail.com">Guillaume Nodet</a>
049 */
050 public class ExecutorFactoryImpl implements ExecutorFactory {
051
052 private ExecutorConfig defaultConfig = new ExecutorConfig();
053
054 private Map<String, ExecutorConfig> configs = new HashMap<String, ExecutorConfig>();
055
056 public Executor createExecutor(String id) {
057 ExecutorConfig config = getConfig(id);
058 return new ExecutorImpl(createService(id, config), config.getShutdownDelay());
059 }
060
061 protected ExecutorConfig getConfig(String id) {
062 ExecutorConfig config = null;
063 if (configs != null) {
064 config = configs.get(id);
065 while (config == null && id.indexOf('.') > 0) {
066 id = id.substring(0, id.lastIndexOf('.'));
067 config = configs.get(id);
068 }
069 }
070 if (config == null) {
071 config = defaultConfig;
072 }
073 return config;
074 }
075
076 protected ThreadPoolExecutor createService(String id, ExecutorConfig config) {
077 if (config.getQueueSize() != 0 && config.getCorePoolSize() == 0) {
078 throw new IllegalArgumentException("CorePoolSize must be > 0 when using a capacity queue");
079 }
080 BlockingQueue<Runnable> queue;
081 if (config.getQueueSize() == 0) {
082 queue = new SynchronousQueue<Runnable>();
083 } else if (config.getQueueSize() < 0 || config.getQueueSize() == Integer.MAX_VALUE) {
084 queue = new LinkedBlockingQueue<Runnable>();
085 } else {
086 queue = new ArrayBlockingQueue<Runnable>(config.getQueueSize());
087 }
088 ThreadFactory factory = new DefaultThreadFactory(id, config.isThreadDaemon(), config.getThreadPriority());
089 RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();
090 ThreadPoolExecutor service = new ThreadPoolExecutor(config.getCorePoolSize(),
091 config.getMaximumPoolSize() < 0 ? Integer.MAX_VALUE : config.getMaximumPoolSize(), config
092 .getKeepAliveTime(), TimeUnit.MILLISECONDS, queue, factory, handler);
093 if (config.isAllowCoreThreadsTimeout()) {
094 try {
095 Method mth = service.getClass().getMethod("allowCoreThreadTimeOut", new Class[] {boolean.class });
096 mth.invoke(service, new Object[] {Boolean.TRUE });
097 } catch (Throwable t) {
098 // Do nothing
099 }
100 }
101 return service;
102 }
103
104 /**
105 * The default thread factory
106 */
107 static class DefaultThreadFactory implements ThreadFactory {
108 final ThreadGroup group;
109
110 final AtomicInteger threadNumber = new AtomicInteger(1);
111
112 final String namePrefix;
113
114 final boolean daemon;
115
116 final int priority;
117
118 DefaultThreadFactory(String id, boolean daemon, int priority) {
119 SecurityManager s = System.getSecurityManager();
120 group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
121 namePrefix = "pool-" + id + "-thread-";
122 this.daemon = daemon;
123 this.priority = priority;
124 }
125
126 public Thread newThread(Runnable r) {
127 Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
128 if (t.isDaemon() != daemon) {
129 t.setDaemon(daemon);
130 }
131 if (t.getPriority() != priority) {
132 t.setPriority(priority);
133 }
134 return t;
135 }
136 }
137
138 /**
139 * @return the configs
140 */
141 public Map<String, ExecutorConfig> getConfigs() {
142 return configs;
143 }
144
145 /**
146 * @param configs the configs to set
147 */
148 public void setConfigs(Map<String, ExecutorConfig> configs) {
149 this.configs = configs;
150 }
151
152 /**
153 * @return the defaultConfig
154 */
155 public ExecutorConfig getDefaultConfig() {
156 return defaultConfig;
157 }
158
159 /**
160 * @param defaultConfig the defaultConfig to set
161 */
162 public void setDefaultConfig(ExecutorConfig defaultConfig) {
163 this.defaultConfig = defaultConfig;
164 }
165
166 }