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.camel.processor;
018
019 import java.util.concurrent.ArrayBlockingQueue;
020 import java.util.concurrent.BlockingQueue;
021 import java.util.concurrent.Executor;
022 import java.util.concurrent.RejectedExecutionException;
023 import java.util.concurrent.ThreadFactory;
024 import java.util.concurrent.ThreadPoolExecutor;
025 import java.util.concurrent.TimeUnit;
026 import java.util.concurrent.atomic.AtomicBoolean;
027
028 import org.apache.camel.AsyncCallback;
029 import org.apache.camel.AsyncProcessor;
030 import org.apache.camel.Exchange;
031 import org.apache.camel.Service;
032 import org.apache.camel.util.AsyncProcessorHelper;
033
034 /**
035 * A processor that forces async processing of the exchange using a thread pool.
036 *
037 * @version $Revision: 723041 $
038 */
039 public class ThreadProcessor implements AsyncProcessor, Service {
040
041 private Executor executor;
042 private long stackSize;
043 private ThreadGroup threadGroup;
044 private int priority = Thread.NORM_PRIORITY;
045 private boolean daemon = true;
046 private String name = "Thread Processor";
047 private BlockingQueue<Runnable> taskQueue;
048 private long keepAliveTime;
049 private int maxSize = 1;
050 private int coreSize = 1;
051 private final AtomicBoolean shutdown = new AtomicBoolean(true);
052 private boolean callerRunsWhenRejected = true;
053
054 class ProcessCall implements Runnable {
055 private final Exchange exchange;
056 private final AsyncCallback callback;
057
058 public ProcessCall(Exchange exchange, AsyncCallback callback) {
059 this.exchange = exchange;
060 this.callback = callback;
061 }
062
063 public void run() {
064 if (shutdown.get()) {
065 exchange.setException(new RejectedExecutionException());
066 }
067 callback.done(false);
068 }
069 }
070
071 public void process(Exchange exchange) throws Exception {
072 AsyncProcessorHelper.process(this, exchange);
073 }
074
075 public boolean process(final Exchange exchange, final AsyncCallback callback) {
076 if (shutdown.get()) {
077 throw new IllegalStateException("ThreadProcessor is not running.");
078 }
079 ProcessCall call = new ProcessCall(exchange, callback);
080 try {
081 executor.execute(call);
082 return false;
083 } catch (RejectedExecutionException e) {
084 if (callerRunsWhenRejected) {
085 if (shutdown.get()) {
086 exchange.setException(new RejectedExecutionException());
087 } else {
088 callback.done(true);
089 }
090 } else {
091 exchange.setException(e);
092 }
093 return true;
094 }
095 }
096
097 public void start() throws Exception {
098 shutdown.set(false);
099 getExecutor();
100 }
101
102 public void stop() throws Exception {
103 shutdown.set(true);
104 if (executor instanceof ThreadPoolExecutor) {
105 ((ThreadPoolExecutor)executor).shutdown();
106 ((ThreadPoolExecutor)executor).awaitTermination(0, TimeUnit.SECONDS);
107 }
108 }
109
110 public long getStackSize() {
111 return stackSize;
112 }
113
114 public void setStackSize(long stackSize) {
115 this.stackSize = stackSize;
116 }
117
118 public ThreadGroup getThreadGroup() {
119 return threadGroup;
120 }
121
122 public void setThreadGroup(ThreadGroup threadGroup) {
123 this.threadGroup = threadGroup;
124 }
125
126 public int getPriority() {
127 return priority;
128 }
129
130 public void setPriority(int priority) {
131 this.priority = priority;
132 }
133
134 public boolean isDaemon() {
135 return daemon;
136 }
137
138 public void setDaemon(boolean daemon) {
139 this.daemon = daemon;
140 }
141
142 public String getName() {
143 return name;
144 }
145
146 public void setName(String name) {
147 this.name = name;
148 }
149
150 public long getKeepAliveTime() {
151 return keepAliveTime;
152 }
153
154 public void setKeepAliveTime(long keepAliveTime) {
155 this.keepAliveTime = keepAliveTime;
156 }
157
158 public int getMaxSize() {
159 return maxSize;
160 }
161
162 public void setMaxSize(int maxSize) {
163 this.maxSize = maxSize;
164 }
165
166 public int getCoreSize() {
167 return coreSize;
168 }
169
170 public void setCoreSize(int coreSize) {
171 this.coreSize = coreSize;
172 }
173
174 public BlockingQueue<Runnable> getTaskQueue() {
175 if (taskQueue == null) {
176 taskQueue = new ArrayBlockingQueue<Runnable>(1000);
177 }
178 return taskQueue;
179 }
180
181 public void setTaskQueue(BlockingQueue<Runnable> taskQueue) {
182 this.taskQueue = taskQueue;
183 }
184
185 public Executor getExecutor() {
186 if (executor == null) {
187 executor = new ThreadPoolExecutor(getCoreSize(), getMaxSize(), getKeepAliveTime(), TimeUnit.MILLISECONDS, getTaskQueue(), new ThreadFactory() {
188 public Thread newThread(Runnable runnable) {
189 Thread thread;
190 if (getStackSize() > 0) {
191 thread = new Thread(getThreadGroup(), runnable, getName(), getStackSize());
192 } else {
193 thread = new Thread(getThreadGroup(), runnable, getName());
194 }
195 thread.setDaemon(isDaemon());
196 thread.setPriority(getPriority());
197 return thread;
198 }
199 });
200 }
201 return executor;
202 }
203
204 public void setExecutor(Executor executor) {
205 this.executor = executor;
206 }
207
208 public boolean isCallerRunsWhenRejected() {
209 return callerRunsWhenRejected;
210 }
211
212 public void setCallerRunsWhenRejected(boolean callerRunsWhenRejected) {
213 this.callerRunsWhenRejected = callerRunsWhenRejected;
214 }
215
216 }