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 */
017package org.apache.camel.reifier;
018
019import java.util.concurrent.ExecutorService;
020
021import org.apache.camel.Processor;
022import org.apache.camel.builder.ThreadPoolProfileBuilder;
023import org.apache.camel.model.ProcessorDefinition;
024import org.apache.camel.model.ProcessorDefinitionHelper;
025import org.apache.camel.model.ThreadsDefinition;
026import org.apache.camel.processor.ThreadsProcessor;
027import org.apache.camel.spi.ExecutorServiceManager;
028import org.apache.camel.spi.RouteContext;
029import org.apache.camel.spi.ThreadPoolProfile;
030import org.apache.camel.util.concurrent.ThreadPoolRejectedPolicy;
031
032public class ThreadsReifier extends ProcessorReifier<ThreadsDefinition> {
033
034    public ThreadsReifier(ProcessorDefinition<?> definition) {
035        super((ThreadsDefinition)definition);
036    }
037
038    @Override
039    public Processor createProcessor(RouteContext routeContext) throws Exception {
040        // the threads name
041        String name = definition.getThreadName() != null ? definition.getThreadName() : "Threads";
042        // prefer any explicit configured executor service
043        boolean shutdownThreadPool = ProcessorDefinitionHelper.willCreateNewThreadPool(routeContext, definition, true);
044        ExecutorService threadPool = ProcessorDefinitionHelper.getConfiguredExecutorService(routeContext, name, definition, false);
045
046        // resolve what rejected policy to use
047        ThreadPoolRejectedPolicy policy = resolveRejectedPolicy(routeContext);
048        if (policy == null) {
049            if (definition.getCallerRunsWhenRejected() == null || definition.getCallerRunsWhenRejected()) {
050                // should use caller runs by default if not configured
051                policy = ThreadPoolRejectedPolicy.CallerRuns;
052            } else {
053                policy = ThreadPoolRejectedPolicy.Abort;
054            }
055        }
056        log.debug("Using ThreadPoolRejectedPolicy: {}", policy);
057
058        // if no explicit then create from the options
059        if (threadPool == null) {
060            ExecutorServiceManager manager = routeContext.getCamelContext().getExecutorServiceManager();
061            // create the thread pool using a builder
062            ThreadPoolProfile profile = new ThreadPoolProfileBuilder(name).poolSize(definition.getPoolSize()).maxPoolSize(definition.getMaxPoolSize())
063                .keepAliveTime(definition.getKeepAliveTime(), definition.getTimeUnit()).maxQueueSize(definition.getMaxQueueSize()).rejectedPolicy(policy)
064                .allowCoreThreadTimeOut(definition.getAllowCoreThreadTimeOut()).build();
065            threadPool = manager.newThreadPool(definition, name, profile);
066            shutdownThreadPool = true;
067        } else {
068            if (definition.getThreadName() != null && !definition.getThreadName().equals("Threads")) {
069                throw new IllegalArgumentException("ThreadName and executorServiceRef options cannot be used together.");
070            }
071            if (definition.getPoolSize() != null) {
072                throw new IllegalArgumentException("PoolSize and executorServiceRef options cannot be used together.");
073            }
074            if (definition.getMaxPoolSize() != null) {
075                throw new IllegalArgumentException("MaxPoolSize and executorServiceRef options cannot be used together.");
076            }
077            if (definition.getKeepAliveTime() != null) {
078                throw new IllegalArgumentException("KeepAliveTime and executorServiceRef options cannot be used together.");
079            }
080            if (definition.getTimeUnit() != null) {
081                throw new IllegalArgumentException("TimeUnit and executorServiceRef options cannot be used together.");
082            }
083            if (definition.getMaxQueueSize() != null) {
084                throw new IllegalArgumentException("MaxQueueSize and executorServiceRef options cannot be used together.");
085            }
086            if (definition.getRejectedPolicy() != null) {
087                throw new IllegalArgumentException("RejectedPolicy and executorServiceRef options cannot be used together.");
088            }
089            if (definition.getAllowCoreThreadTimeOut() != null) {
090                throw new IllegalArgumentException("AllowCoreThreadTimeOut and executorServiceRef options cannot be used together.");
091            }
092        }
093
094        return new ThreadsProcessor(routeContext.getCamelContext(), threadPool, shutdownThreadPool, policy);
095    }
096
097    protected ThreadPoolRejectedPolicy resolveRejectedPolicy(RouteContext routeContext) {
098        if (definition.getExecutorServiceRef() != null && definition.getRejectedPolicy() == null) {
099            ThreadPoolProfile threadPoolProfile = routeContext.getCamelContext().getExecutorServiceManager().getThreadPoolProfile(definition.getExecutorServiceRef());
100            if (threadPoolProfile != null) {
101                return threadPoolProfile.getRejectedPolicy();
102            }
103        }
104        return definition.getRejectedPolicy();
105    }
106
107}