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