/**
* 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.camel.processor;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.camel.AsyncCallback;
import org.apache.camel.AsyncProcessor;
import org.apache.camel.Exchange;
import org.apache.camel.Service;
import org.apache.camel.util.AsyncProcessorHelper;
/**
* A processor that forces async processing of the exchange using a thread pool.
*
* @version $Revision: 659491 $
*/
public class ThreadProcessor implements AsyncProcessor, Service {
private ThreadPoolExecutor executor;
private long stackSize;
private ThreadGroup threadGroup;
private int priority = Thread.NORM_PRIORITY;
private boolean daemon = true;
private String name = "Thread Processor";
private BlockingQueue<Runnable> taskQueue;
private long keepAliveTime;
private int maxSize = 1;
private int coreSize = 1;
private final AtomicBoolean shutdown = new AtomicBoolean(true);
private boolean callerRunsWhenRejected = true;
class ProcessCall implements Runnable {
private final Exchange exchange;
private final AsyncCallback callback;
public ProcessCall(Exchange exchange, AsyncCallback callback) {
this.exchange = exchange;
this.callback = callback;
}
public void run() {
if (shutdown.get()) {
exchange.setException(new RejectedExecutionException());
}
callback.done(false);
}
}
public void process(Exchange exchange) throws Exception {
AsyncProcessorHelper.process(this, exchange);
}
public boolean process(final Exchange exchange, final AsyncCallback callback) {
if (shutdown.get()) {
throw new IllegalStateException("ThreadProcessor is not running.");
}
ProcessCall call = new ProcessCall(exchange, callback);
try {
executor.execute(call);
return false;
} catch (RejectedExecutionException e) {
if (callerRunsWhenRejected) {
if (shutdown.get()) {
exchange.setException(new RejectedExecutionException());
} else {
callback.done(true);
}
} else {
exchange.setException(e);
}
return true;
}
}
public void start() throws Exception {
shutdown.set(false);
getExecutor();
}
public void stop() throws Exception {
shutdown.set(true);
executor.shutdown();
executor.awaitTermination(0, TimeUnit.SECONDS);
}
public long getStackSize() {
return stackSize;
}
public void setStackSize(long stackSize) {
this.stackSize = stackSize;
}
public ThreadGroup getThreadGroup() {
return threadGroup;
}
public void setThreadGroup(ThreadGroup threadGroup) {
this.threadGroup = threadGroup;
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
public boolean isDaemon() {
return daemon;
}
public void setDaemon(boolean daemon) {
this.daemon = daemon;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getKeepAliveTime() {
return keepAliveTime;
}
public void setKeepAliveTime(long keepAliveTime) {
this.keepAliveTime = keepAliveTime;
}
public int getMaxSize() {
return maxSize;
}
public void setMaxSize(int maxSize) {
this.maxSize = maxSize;
}
public int getCoreSize() {
return coreSize;
}
public void setCoreSize(int coreSize) {
this.coreSize = coreSize;
}
public BlockingQueue<Runnable> getTaskQueue() {
if (taskQueue == null) {
taskQueue = new ArrayBlockingQueue<Runnable>(1000);
}
return taskQueue;
}
public void setTaskQueue(BlockingQueue<Runnable> taskQueue) {
this.taskQueue = taskQueue;
}
public ThreadPoolExecutor getExecutor() {
if (executor == null) {
executor = new ThreadPoolExecutor(getCoreSize(), getMaxSize(), getKeepAliveTime(), TimeUnit.MILLISECONDS, getTaskQueue(), new ThreadFactory() {
public Thread newThread(Runnable runnable) {
Thread thread;
if (getStackSize() > 0) {
thread = new Thread(getThreadGroup(), runnable, getName(), getStackSize());
} else {
thread = new Thread(getThreadGroup(), runnable, getName());
}
thread.setDaemon(isDaemon());
thread.setPriority(getPriority());
return thread;
}
});
}
return executor;
}
public void setExecutor(ThreadPoolExecutor executor) {
this.executor = executor;
}
public boolean isCallerRunsWhenRejected() {
return callerRunsWhenRejected;
}
public void setCallerRunsWhenRejected(boolean callerRunsWhenRejected) {
this.callerRunsWhenRejected = callerRunsWhenRejected;
}
}