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; 020import java.util.concurrent.ScheduledExecutorService; 021 022import org.apache.camel.AggregationStrategy; 023import org.apache.camel.CamelContextAware; 024import org.apache.camel.Expression; 025import org.apache.camel.Predicate; 026import org.apache.camel.Processor; 027import org.apache.camel.model.AggregateDefinition; 028import org.apache.camel.model.OptimisticLockRetryPolicyDefinition; 029import org.apache.camel.model.ProcessorDefinition; 030import org.apache.camel.model.ProcessorDefinitionHelper; 031import org.apache.camel.processor.CamelInternalProcessor; 032import org.apache.camel.processor.aggregate.AggregateController; 033import org.apache.camel.processor.aggregate.AggregateProcessor; 034import org.apache.camel.processor.aggregate.AggregationStrategyBeanAdapter; 035import org.apache.camel.processor.aggregate.OptimisticLockRetryPolicy; 036import org.apache.camel.spi.AggregationRepository; 037import org.apache.camel.spi.RouteContext; 038import org.apache.camel.util.concurrent.SynchronousExecutorService; 039 040public class AggregateReifier extends ProcessorReifier<AggregateDefinition> { 041 042 public AggregateReifier(ProcessorDefinition<?> definition) { 043 super(AggregateDefinition.class.cast(definition)); 044 } 045 046 @Override 047 public Processor createProcessor(RouteContext routeContext) throws Exception { 048 return createAggregator(routeContext); 049 } 050 051 protected AggregateProcessor createAggregator(RouteContext routeContext) throws Exception { 052 Processor childProcessor = this.createChildProcessor(routeContext, true); 053 054 // wrap the aggregate route in a unit of work processor 055 CamelInternalProcessor internal = new CamelInternalProcessor(childProcessor); 056 internal.addAdvice(new CamelInternalProcessor.UnitOfWorkProcessorAdvice(routeContext)); 057 058 Expression correlation = definition.getExpression().createExpression(routeContext); 059 AggregationStrategy strategy = createAggregationStrategy(routeContext); 060 061 boolean parallel = definition.getParallelProcessing() != null && definition.getParallelProcessing(); 062 boolean shutdownThreadPool = ProcessorDefinitionHelper.willCreateNewThreadPool(routeContext, definition, parallel); 063 ExecutorService threadPool = ProcessorDefinitionHelper.getConfiguredExecutorService(routeContext, "Aggregator", definition, parallel); 064 if (threadPool == null && !parallel) { 065 // executor service is mandatory for the Aggregator 066 // we do not run in parallel mode, but use a synchronous executor, 067 // so we run in current thread 068 threadPool = new SynchronousExecutorService(); 069 shutdownThreadPool = true; 070 } 071 072 AggregateProcessor answer = new AggregateProcessor(routeContext.getCamelContext(), internal, correlation, strategy, threadPool, shutdownThreadPool); 073 074 AggregationRepository repository = createAggregationRepository(routeContext); 075 if (repository != null) { 076 answer.setAggregationRepository(repository); 077 } 078 079 if (definition.getAggregateController() == null && definition.getAggregateControllerRef() != null) { 080 definition.setAggregateController(routeContext.mandatoryLookup(definition.getAggregateControllerRef(), AggregateController.class)); 081 } 082 083 // this EIP supports using a shared timeout checker thread pool or 084 // fallback to create a new thread pool 085 boolean shutdownTimeoutThreadPool = false; 086 ScheduledExecutorService timeoutThreadPool = definition.getTimeoutCheckerExecutorService(); 087 if (timeoutThreadPool == null && definition.getTimeoutCheckerExecutorServiceRef() != null) { 088 // lookup existing thread pool 089 timeoutThreadPool = routeContext.lookup(definition.getTimeoutCheckerExecutorServiceRef(), ScheduledExecutorService.class); 090 if (timeoutThreadPool == null) { 091 // then create a thread pool assuming the ref is a thread pool 092 // profile id 093 timeoutThreadPool = routeContext.getCamelContext().getExecutorServiceManager().newScheduledThreadPool(this, AggregateProcessor.AGGREGATE_TIMEOUT_CHECKER, 094 definition.getTimeoutCheckerExecutorServiceRef()); 095 if (timeoutThreadPool == null) { 096 throw new IllegalArgumentException("ExecutorServiceRef " + definition.getTimeoutCheckerExecutorServiceRef() 097 + " not found in registry (as an ScheduledExecutorService instance) or as a thread pool profile."); 098 } 099 shutdownTimeoutThreadPool = true; 100 } 101 } 102 answer.setTimeoutCheckerExecutorService(timeoutThreadPool); 103 answer.setShutdownTimeoutCheckerExecutorService(shutdownTimeoutThreadPool); 104 105 if (definition.getCompletionFromBatchConsumer() != null && definition.getCompletionFromBatchConsumer() && definition.getDiscardOnAggregationFailure() != null 106 && definition.getDiscardOnAggregationFailure()) { 107 throw new IllegalArgumentException("Cannot use both completionFromBatchConsumer and discardOnAggregationFailure on: " + definition); 108 } 109 110 // set other options 111 answer.setParallelProcessing(parallel); 112 if (definition.getOptimisticLocking() != null) { 113 answer.setOptimisticLocking(definition.getOptimisticLocking()); 114 } 115 if (definition.getCompletionPredicate() != null) { 116 Predicate predicate = definition.getCompletionPredicate().createPredicate(routeContext); 117 answer.setCompletionPredicate(predicate); 118 } else if (strategy instanceof Predicate) { 119 // if aggregation strategy implements predicate and was not 120 // configured then use as fallback 121 log.debug("Using AggregationStrategy as completion predicate: {}", strategy); 122 answer.setCompletionPredicate((Predicate)strategy); 123 } 124 if (definition.getCompletionTimeoutExpression() != null) { 125 Expression expression = definition.getCompletionTimeoutExpression().createExpression(routeContext); 126 answer.setCompletionTimeoutExpression(expression); 127 } 128 if (definition.getCompletionTimeout() != null) { 129 answer.setCompletionTimeout(definition.getCompletionTimeout()); 130 } 131 if (definition.getCompletionInterval() != null) { 132 answer.setCompletionInterval(definition.getCompletionInterval()); 133 } 134 if (definition.getCompletionSizeExpression() != null) { 135 Expression expression = definition.getCompletionSizeExpression().createExpression(routeContext); 136 answer.setCompletionSizeExpression(expression); 137 } 138 if (definition.getCompletionSize() != null) { 139 answer.setCompletionSize(definition.getCompletionSize()); 140 } 141 if (definition.getCompletionFromBatchConsumer() != null) { 142 answer.setCompletionFromBatchConsumer(definition.getCompletionFromBatchConsumer()); 143 } 144 if (definition.getCompletionOnNewCorrelationGroup() != null) { 145 answer.setCompletionOnNewCorrelationGroup(definition.getCompletionOnNewCorrelationGroup()); 146 } 147 if (definition.getEagerCheckCompletion() != null) { 148 answer.setEagerCheckCompletion(definition.getEagerCheckCompletion()); 149 } 150 if (definition.getIgnoreInvalidCorrelationKeys() != null) { 151 answer.setIgnoreInvalidCorrelationKeys(definition.getIgnoreInvalidCorrelationKeys()); 152 } 153 if (definition.getCloseCorrelationKeyOnCompletion() != null) { 154 answer.setCloseCorrelationKeyOnCompletion(definition.getCloseCorrelationKeyOnCompletion()); 155 } 156 if (definition.getDiscardOnCompletionTimeout() != null) { 157 answer.setDiscardOnCompletionTimeout(definition.getDiscardOnCompletionTimeout()); 158 } 159 if (definition.getDiscardOnAggregationFailure() != null) { 160 answer.setDiscardOnAggregationFailure(definition.getDiscardOnAggregationFailure()); 161 } 162 if (definition.getForceCompletionOnStop() != null) { 163 answer.setForceCompletionOnStop(definition.getForceCompletionOnStop()); 164 } 165 if (definition.getCompleteAllOnStop() != null) { 166 answer.setCompleteAllOnStop(definition.getCompleteAllOnStop()); 167 } 168 if (definition.getOptimisticLockRetryPolicy() == null) { 169 if (definition.getOptimisticLockRetryPolicyDefinition() != null) { 170 answer.setOptimisticLockRetryPolicy(createOptimisticLockRetryPolicy(definition.getOptimisticLockRetryPolicyDefinition())); 171 } 172 } else { 173 answer.setOptimisticLockRetryPolicy(definition.getOptimisticLockRetryPolicy()); 174 } 175 if (definition.getAggregateController() != null) { 176 answer.setAggregateController(definition.getAggregateController()); 177 } 178 if (definition.getCompletionTimeoutCheckerInterval() != null) { 179 answer.setCompletionTimeoutCheckerInterval(definition.getCompletionTimeoutCheckerInterval()); 180 } 181 return answer; 182 } 183 184 public static OptimisticLockRetryPolicy createOptimisticLockRetryPolicy(OptimisticLockRetryPolicyDefinition definition) { 185 OptimisticLockRetryPolicy policy = new OptimisticLockRetryPolicy(); 186 if (definition.getMaximumRetries() != null) { 187 policy.setMaximumRetries(definition.getMaximumRetries()); 188 } 189 if (definition.getRetryDelay() != null) { 190 policy.setRetryDelay(definition.getRetryDelay()); 191 } 192 if (definition.getMaximumRetryDelay() != null) { 193 policy.setMaximumRetryDelay(definition.getMaximumRetryDelay()); 194 } 195 if (definition.getExponentialBackOff() != null) { 196 policy.setExponentialBackOff(definition.getExponentialBackOff()); 197 } 198 if (definition.getRandomBackOff() != null) { 199 policy.setRandomBackOff(definition.getRandomBackOff()); 200 } 201 return policy; 202 } 203 204 private AggregationStrategy createAggregationStrategy(RouteContext routeContext) { 205 AggregationStrategy strategy = definition.getAggregationStrategy(); 206 if (strategy == null && definition.getStrategyRef() != null) { 207 Object aggStrategy = routeContext.lookup(definition.getStrategyRef(), Object.class); 208 if (aggStrategy instanceof AggregationStrategy) { 209 strategy = (AggregationStrategy)aggStrategy; 210 } else if (aggStrategy != null) { 211 AggregationStrategyBeanAdapter adapter = new AggregationStrategyBeanAdapter(aggStrategy, definition.getAggregationStrategyMethodName()); 212 if (definition.getStrategyMethodAllowNull() != null) { 213 adapter.setAllowNullNewExchange(definition.getStrategyMethodAllowNull()); 214 adapter.setAllowNullOldExchange(definition.getStrategyMethodAllowNull()); 215 } 216 strategy = adapter; 217 } else { 218 throw new IllegalArgumentException("Cannot find AggregationStrategy in Registry with name: " + definition.getStrategyRef()); 219 } 220 } 221 222 if (strategy == null) { 223 throw new IllegalArgumentException("AggregationStrategy or AggregationStrategyRef must be set on " + this); 224 } 225 226 if (strategy instanceof CamelContextAware) { 227 ((CamelContextAware)strategy).setCamelContext(routeContext.getCamelContext()); 228 } 229 230 return strategy; 231 } 232 233 private AggregationRepository createAggregationRepository(RouteContext routeContext) { 234 AggregationRepository repository = definition.getAggregationRepository(); 235 if (repository == null && definition.getAggregationRepositoryRef() != null) { 236 repository = routeContext.mandatoryLookup(definition.getAggregationRepositoryRef(), AggregationRepository.class); 237 } 238 return repository; 239 } 240 241}