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.ArrayList;
020import java.util.List;
021import java.util.concurrent.ExecutorService;
022
023import org.apache.camel.AggregationStrategy;
024import org.apache.camel.CamelContextAware;
025import org.apache.camel.Expression;
026import org.apache.camel.Processor;
027import org.apache.camel.model.ProcessorDefinition;
028import org.apache.camel.model.ProcessorDefinitionHelper;
029import org.apache.camel.model.RecipientListDefinition;
030import org.apache.camel.processor.EvaluateExpressionProcessor;
031import org.apache.camel.processor.Pipeline;
032import org.apache.camel.processor.RecipientList;
033import org.apache.camel.processor.aggregate.AggregationStrategyBeanAdapter;
034import org.apache.camel.processor.aggregate.ShareUnitOfWorkAggregationStrategy;
035import org.apache.camel.processor.aggregate.UseLatestAggregationStrategy;
036import org.apache.camel.spi.RouteContext;
037import org.apache.camel.support.CamelContextHelper;
038
039public class RecipientListReifier extends ProcessorReifier<RecipientListDefinition<?>> {
040
041    public RecipientListReifier(ProcessorDefinition<?> definition) {
042        super((RecipientListDefinition<?>)definition);
043    }
044
045    @Override
046    public Processor createProcessor(RouteContext routeContext) throws Exception {
047        final Expression expression = definition.getExpression().createExpression(routeContext);
048
049        boolean isParallelProcessing = definition.getParallelProcessing() != null && definition.getParallelProcessing();
050        boolean isStreaming = definition.getStreaming() != null && definition.getStreaming();
051        boolean isParallelAggregate = definition.getParallelAggregate() != null && definition.getParallelAggregate();
052        boolean isShareUnitOfWork = definition.getShareUnitOfWork() != null && definition.getShareUnitOfWork();
053        boolean isStopOnException = definition.getStopOnException() != null && definition.getStopOnException();
054        boolean isIgnoreInvalidEndpoints = definition.getIgnoreInvalidEndpoints() != null && definition.getIgnoreInvalidEndpoints();
055        boolean isStopOnAggregateException = definition.getStopOnAggregateException() != null && definition.getStopOnAggregateException();
056
057        RecipientList answer;
058        if (definition.getDelimiter() != null) {
059            answer = new RecipientList(routeContext.getCamelContext(), expression, definition.getDelimiter());
060        } else {
061            answer = new RecipientList(routeContext.getCamelContext(), expression);
062        }
063        answer.setAggregationStrategy(createAggregationStrategy(routeContext));
064        answer.setParallelProcessing(isParallelProcessing);
065        answer.setParallelAggregate(isParallelAggregate);
066        answer.setStreaming(isStreaming);
067        answer.setShareUnitOfWork(isShareUnitOfWork);
068        answer.setStopOnException(isStopOnException);
069        answer.setIgnoreInvalidEndpoints(isIgnoreInvalidEndpoints);
070        answer.setStopOnAggregateException(isStopOnAggregateException);
071        if (definition.getCacheSize() != null) {
072            answer.setCacheSize(definition.getCacheSize());
073        }
074        if (definition.getOnPrepareRef() != null) {
075            definition.setOnPrepare(CamelContextHelper.mandatoryLookup(routeContext.getCamelContext(), definition.getOnPrepareRef(), Processor.class));
076        }
077        if (definition.getOnPrepare() != null) {
078            answer.setOnPrepare(definition.getOnPrepare());
079        }
080        if (definition.getTimeout() != null) {
081            answer.setTimeout(definition.getTimeout());
082        }
083
084        boolean shutdownThreadPool = ProcessorDefinitionHelper.willCreateNewThreadPool(routeContext, definition, isParallelProcessing);
085        ExecutorService threadPool = ProcessorDefinitionHelper.getConfiguredExecutorService(routeContext, "RecipientList", definition, isParallelProcessing);
086        answer.setExecutorService(threadPool);
087        answer.setShutdownExecutorService(shutdownThreadPool);
088        long timeout = definition.getTimeout() != null ? definition.getTimeout() : 0;
089        if (timeout > 0 && !isParallelProcessing) {
090            throw new IllegalArgumentException("Timeout is used but ParallelProcessing has not been enabled.");
091        }
092
093        // create a pipeline with two processors
094        // the first is the eval processor which evaluates the expression to use
095        // the second is the recipient list
096        List<Processor> pipe = new ArrayList<>(2);
097
098        // the eval processor must be wrapped in error handler, so in case there
099        // was an
100        // error during evaluation, the error handler can deal with it
101        // the recipient list is not in error handler, as its has its own
102        // special error handling
103        // when sending to the recipients individually
104        Processor evalProcessor = new EvaluateExpressionProcessor(expression);
105        evalProcessor = super.wrapInErrorHandler(routeContext, evalProcessor);
106
107        pipe.add(evalProcessor);
108        pipe.add(answer);
109
110        // wrap in nested pipeline so this appears as one processor
111        // (threads definition does this as well)
112        return new Pipeline(routeContext.getCamelContext(), pipe) {
113            @Override
114            public String toString() {
115                return "RecipientList[" + expression + "]";
116            }
117        };
118    }
119
120    private AggregationStrategy createAggregationStrategy(RouteContext routeContext) {
121        AggregationStrategy strategy = definition.getAggregationStrategy();
122        if (strategy == null && definition.getStrategyRef() != null) {
123            Object aggStrategy = routeContext.lookup(definition.getStrategyRef(), Object.class);
124            if (aggStrategy instanceof AggregationStrategy) {
125                strategy = (AggregationStrategy)aggStrategy;
126            } else if (aggStrategy != null) {
127                AggregationStrategyBeanAdapter adapter = new AggregationStrategyBeanAdapter(aggStrategy, definition.getStrategyMethodName());
128                if (definition.getStrategyMethodAllowNull() != null) {
129                    adapter.setAllowNullNewExchange(definition.getStrategyMethodAllowNull());
130                    adapter.setAllowNullOldExchange(definition.getStrategyMethodAllowNull());
131                }
132                strategy = adapter;
133            } else {
134                throw new IllegalArgumentException("Cannot find AggregationStrategy in Registry with name: " + definition.getStrategyRef());
135            }
136        }
137
138        if (strategy == null) {
139            // default to use latest aggregation strategy
140            strategy = new UseLatestAggregationStrategy();
141        }
142
143        if (strategy instanceof CamelContextAware) {
144            ((CamelContextAware)strategy).setCamelContext(routeContext.getCamelContext());
145        }
146
147        if (definition.getShareUnitOfWork() != null && definition.getShareUnitOfWork()) {
148            // wrap strategy in share unit of work
149            strategy = new ShareUnitOfWorkAggregationStrategy(strategy);
150        }
151
152        return strategy;
153    }
154
155}