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