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