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.Collection; 021import java.util.HashMap; 022import java.util.List; 023import java.util.Map; 024import java.util.concurrent.ExecutorService; 025import java.util.concurrent.ScheduledExecutorService; 026import java.util.function.BiFunction; 027 028import org.apache.camel.CamelContext; 029import org.apache.camel.Channel; 030import org.apache.camel.ErrorHandlerFactory; 031import org.apache.camel.ExtendedCamelContext; 032import org.apache.camel.Processor; 033import org.apache.camel.Route; 034import org.apache.camel.model.AggregateDefinition; 035import org.apache.camel.model.BeanDefinition; 036import org.apache.camel.model.CatchDefinition; 037import org.apache.camel.model.ChoiceDefinition; 038import org.apache.camel.model.CircuitBreakerDefinition; 039import org.apache.camel.model.ClaimCheckDefinition; 040import org.apache.camel.model.ConvertBodyDefinition; 041import org.apache.camel.model.DelayDefinition; 042import org.apache.camel.model.DynamicRouterDefinition; 043import org.apache.camel.model.EnrichDefinition; 044import org.apache.camel.model.ExecutorServiceAwareDefinition; 045import org.apache.camel.model.FilterDefinition; 046import org.apache.camel.model.FinallyDefinition; 047import org.apache.camel.model.IdempotentConsumerDefinition; 048import org.apache.camel.model.InOnlyDefinition; 049import org.apache.camel.model.InOutDefinition; 050import org.apache.camel.model.InterceptDefinition; 051import org.apache.camel.model.InterceptFromDefinition; 052import org.apache.camel.model.InterceptSendToEndpointDefinition; 053import org.apache.camel.model.LoadBalanceDefinition; 054import org.apache.camel.model.LogDefinition; 055import org.apache.camel.model.LoopDefinition; 056import org.apache.camel.model.MarshalDefinition; 057import org.apache.camel.model.MulticastDefinition; 058import org.apache.camel.model.OnCompletionDefinition; 059import org.apache.camel.model.OnExceptionDefinition; 060import org.apache.camel.model.OnFallbackDefinition; 061import org.apache.camel.model.OptionalIdentifiedDefinition; 062import org.apache.camel.model.OtherwiseDefinition; 063import org.apache.camel.model.PipelineDefinition; 064import org.apache.camel.model.PolicyDefinition; 065import org.apache.camel.model.PollEnrichDefinition; 066import org.apache.camel.model.ProcessDefinition; 067import org.apache.camel.model.ProcessorDefinition; 068import org.apache.camel.model.ProcessorDefinitionHelper; 069import org.apache.camel.model.RecipientListDefinition; 070import org.apache.camel.model.RemoveHeaderDefinition; 071import org.apache.camel.model.RemoveHeadersDefinition; 072import org.apache.camel.model.RemovePropertiesDefinition; 073import org.apache.camel.model.RemovePropertyDefinition; 074import org.apache.camel.model.ResequenceDefinition; 075import org.apache.camel.model.RollbackDefinition; 076import org.apache.camel.model.RouteDefinition; 077import org.apache.camel.model.RouteDefinitionHelper; 078import org.apache.camel.model.RoutingSlipDefinition; 079import org.apache.camel.model.SagaDefinition; 080import org.apache.camel.model.SamplingDefinition; 081import org.apache.camel.model.ScriptDefinition; 082import org.apache.camel.model.SetBodyDefinition; 083import org.apache.camel.model.SetExchangePatternDefinition; 084import org.apache.camel.model.SetHeaderDefinition; 085import org.apache.camel.model.SetPropertyDefinition; 086import org.apache.camel.model.SortDefinition; 087import org.apache.camel.model.SplitDefinition; 088import org.apache.camel.model.StepDefinition; 089import org.apache.camel.model.StopDefinition; 090import org.apache.camel.model.ThreadsDefinition; 091import org.apache.camel.model.ThrottleDefinition; 092import org.apache.camel.model.ThrowExceptionDefinition; 093import org.apache.camel.model.ToDefinition; 094import org.apache.camel.model.ToDynamicDefinition; 095import org.apache.camel.model.TransactedDefinition; 096import org.apache.camel.model.TransformDefinition; 097import org.apache.camel.model.TryDefinition; 098import org.apache.camel.model.UnmarshalDefinition; 099import org.apache.camel.model.ValidateDefinition; 100import org.apache.camel.model.WhenDefinition; 101import org.apache.camel.model.WhenSkipSendToEndpointDefinition; 102import org.apache.camel.model.WireTapDefinition; 103import org.apache.camel.model.cloud.ServiceCallDefinition; 104import org.apache.camel.processor.InterceptEndpointProcessor; 105import org.apache.camel.processor.Pipeline; 106import org.apache.camel.processor.channel.DefaultChannel; 107import org.apache.camel.reifier.errorhandler.ErrorHandlerReifier; 108import org.apache.camel.spi.ExecutorServiceManager; 109import org.apache.camel.spi.IdAware; 110import org.apache.camel.spi.InterceptStrategy; 111import org.apache.camel.spi.LifecycleStrategy; 112import org.apache.camel.spi.ReifierStrategy; 113import org.apache.camel.spi.RouteIdAware; 114import org.apache.camel.util.ObjectHelper; 115import org.slf4j.Logger; 116import org.slf4j.LoggerFactory; 117 118public abstract class ProcessorReifier<T extends ProcessorDefinition<?>> extends AbstractReifier { 119 120 private static final Map<Class<?>, BiFunction<Route, ProcessorDefinition<?>, ProcessorReifier<? extends ProcessorDefinition<?>>>> PROCESSORS; 121 static { 122 // NOTE: if adding a new class then update the initial capacity of the 123 // HashMap 124 Map<Class<?>, BiFunction<Route, ProcessorDefinition<?>, ProcessorReifier<? extends ProcessorDefinition<?>>>> map = new HashMap<>(65); 125 map.put(AggregateDefinition.class, AggregateReifier::new); 126 map.put(BeanDefinition.class, BeanReifier::new); 127 map.put(CatchDefinition.class, CatchReifier::new); 128 map.put(ChoiceDefinition.class, ChoiceReifier::new); 129 map.put(CircuitBreakerDefinition.class, CircuitBreakerReifier::new); 130 map.put(ClaimCheckDefinition.class, ClaimCheckReifier::new); 131 map.put(ConvertBodyDefinition.class, ConvertBodyReifier::new); 132 map.put(DelayDefinition.class, DelayReifier::new); 133 map.put(DynamicRouterDefinition.class, DynamicRouterReifier::new); 134 map.put(EnrichDefinition.class, EnrichReifier::new); 135 map.put(FilterDefinition.class, FilterReifier::new); 136 map.put(FinallyDefinition.class, FinallyReifier::new); 137 map.put(IdempotentConsumerDefinition.class, IdempotentConsumerReifier::new); 138 map.put(InOnlyDefinition.class, SendReifier::new); 139 map.put(InOutDefinition.class, SendReifier::new); 140 map.put(InterceptDefinition.class, InterceptReifier::new); 141 map.put(InterceptFromDefinition.class, InterceptFromReifier::new); 142 map.put(InterceptSendToEndpointDefinition.class, InterceptSendToEndpointReifier::new); 143 map.put(LoadBalanceDefinition.class, LoadBalanceReifier::new); 144 map.put(LogDefinition.class, LogReifier::new); 145 map.put(LoopDefinition.class, LoopReifier::new); 146 map.put(MarshalDefinition.class, MarshalReifier::new); 147 map.put(MulticastDefinition.class, MulticastReifier::new); 148 map.put(OnCompletionDefinition.class, OnCompletionReifier::new); 149 map.put(OnExceptionDefinition.class, OnExceptionReifier::new); 150 map.put(OnFallbackDefinition.class, OnFallbackReifier::new); 151 map.put(OtherwiseDefinition.class, OtherwiseReifier::new); 152 map.put(PipelineDefinition.class, PipelineReifier::new); 153 map.put(PolicyDefinition.class, PolicyReifier::new); 154 map.put(PollEnrichDefinition.class, PollEnrichReifier::new); 155 map.put(ProcessDefinition.class, ProcessReifier::new); 156 map.put(RecipientListDefinition.class, RecipientListReifier::new); 157 map.put(RemoveHeaderDefinition.class, RemoveHeaderReifier::new); 158 map.put(RemoveHeadersDefinition.class, RemoveHeadersReifier::new); 159 map.put(RemovePropertiesDefinition.class, RemovePropertiesReifier::new); 160 map.put(RemovePropertyDefinition.class, RemovePropertyReifier::new); 161 map.put(ResequenceDefinition.class, ResequenceReifier::new); 162 map.put(RollbackDefinition.class, RollbackReifier::new); 163 map.put(RoutingSlipDefinition.class, RoutingSlipReifier::new); 164 map.put(SagaDefinition.class, SagaReifier::new); 165 map.put(SamplingDefinition.class, SamplingReifier::new); 166 map.put(ScriptDefinition.class, ScriptReifier::new); 167 map.put(ServiceCallDefinition.class, ServiceCallReifier::new); 168 map.put(SetBodyDefinition.class, SetBodyReifier::new); 169 map.put(SetExchangePatternDefinition.class, SetExchangePatternReifier::new); 170 map.put(SetHeaderDefinition.class, SetHeaderReifier::new); 171 map.put(SetPropertyDefinition.class, SetPropertyReifier::new); 172 map.put(SortDefinition.class, SortReifier::new); 173 map.put(SplitDefinition.class, SplitReifier::new); 174 map.put(StepDefinition.class, StepReifier::new); 175 map.put(StopDefinition.class, StopReifier::new); 176 map.put(ThreadsDefinition.class, ThreadsReifier::new); 177 map.put(ThrottleDefinition.class, ThrottleReifier::new); 178 map.put(ThrowExceptionDefinition.class, ThrowExceptionReifier::new); 179 map.put(ToDefinition.class, SendReifier::new); 180 map.put(ToDynamicDefinition.class, ToDynamicReifier::new); 181 map.put(TransactedDefinition.class, TransactedReifier::new); 182 map.put(TransformDefinition.class, TransformReifier::new); 183 map.put(TryDefinition.class, TryReifier::new); 184 map.put(UnmarshalDefinition.class, UnmarshalReifier::new); 185 map.put(ValidateDefinition.class, ValidateReifier::new); 186 map.put(WireTapDefinition.class, WireTapReifier::new); 187 map.put(WhenSkipSendToEndpointDefinition.class, WhenSkipSendToEndpointReifier::new); 188 map.put(WhenDefinition.class, WhenReifier::new); 189 PROCESSORS = map; 190 ReifierStrategy.addReifierClearer(ProcessorReifier::clearReifiers); 191 } 192 protected final Logger log = LoggerFactory.getLogger(getClass()); 193 194 protected final T definition; 195 196 public ProcessorReifier(Route route, T definition) { 197 super(route); 198 this.definition = definition; 199 } 200 201 public ProcessorReifier(CamelContext camelContext, T definition) { 202 super(camelContext); 203 this.definition = definition; 204 } 205 206 public static void registerReifier(Class<?> processorClass, BiFunction<Route, ProcessorDefinition<?>, ProcessorReifier<? extends ProcessorDefinition<?>>> creator) { 207 PROCESSORS.put(processorClass, creator); 208 } 209 210 public static void clearReifiers() { 211 PROCESSORS.clear(); 212 } 213 214 public static ProcessorReifier<? extends ProcessorDefinition<?>> reifier(Route route, ProcessorDefinition<?> definition) { 215 BiFunction<Route, ProcessorDefinition<?>, ProcessorReifier<? extends ProcessorDefinition<?>>> reifier = PROCESSORS.get(definition.getClass()); 216 if (reifier != null) { 217 return reifier.apply(route, definition); 218 } 219 throw new IllegalStateException("Unsupported definition: " + definition); 220 } 221 222 /** 223 * Determines whether a new thread pool will be created or not. 224 * <p/> 225 * This is used to know if a new thread pool will be created, and therefore 226 * is not shared by others, and therefore exclusive to the definition. 227 * 228 * @param definition the node definition which may leverage executor 229 * service. 230 * @param useDefault whether to fallback and use a default thread pool, if 231 * no explicit configured 232 * @return <tt>true</tt> if a new thread pool will be created, 233 * <tt>false</tt> if not 234 * @see #getConfiguredExecutorService(String, ExecutorServiceAwareDefinition, boolean) 235 */ 236 public boolean willCreateNewThreadPool(ExecutorServiceAwareDefinition<?> definition, boolean useDefault) { 237 ExecutorServiceManager manager = camelContext.getExecutorServiceManager(); 238 ObjectHelper.notNull(manager, "ExecutorServiceManager", camelContext); 239 240 if (definition.getExecutorService() != null) { 241 // no there is a custom thread pool configured 242 return false; 243 } else if (definition.getExecutorServiceRef() != null) { 244 ExecutorService answer = lookup(definition.getExecutorServiceRef(), ExecutorService.class); 245 // if no existing thread pool, then we will have to create a new 246 // thread pool 247 return answer == null; 248 } else if (useDefault) { 249 return true; 250 } 251 252 return false; 253 } 254 255 /** 256 * Will lookup and get the configured 257 * {@link ExecutorService} from the given definition. 258 * <p/> 259 * This method will lookup for configured thread pool in the following order 260 * <ul> 261 * <li>from the definition if any explicit configured executor service.</li> 262 * <li>from the {@link org.apache.camel.spi.Registry} if found</li> 263 * <li>from the known list of {@link org.apache.camel.spi.ThreadPoolProfile 264 * ThreadPoolProfile(s)}.</li> 265 * <li>if none found, then <tt>null</tt> is returned.</li> 266 * </ul> 267 * The various {@link ExecutorServiceAwareDefinition} should use this helper 268 * method to ensure they support configured executor services in the same 269 * coherent way. 270 * 271 * @param name name which is appended to the thread name, when the 272 * {@link ExecutorService} is created based 273 * on a {@link org.apache.camel.spi.ThreadPoolProfile}. 274 * @param definition the node definition which may leverage executor 275 * service. 276 * @param useDefault whether to fallback and use a default thread pool, if 277 * no explicit configured 278 * @return the configured executor service, or <tt>null</tt> if none was 279 * configured. 280 * @throws IllegalArgumentException is thrown if lookup of executor service 281 * in {@link org.apache.camel.spi.Registry} was not found 282 */ 283 public ExecutorService getConfiguredExecutorService(String name, ExecutorServiceAwareDefinition<?> definition, boolean useDefault) 284 throws IllegalArgumentException { 285 ExecutorServiceManager manager = camelContext.getExecutorServiceManager(); 286 ObjectHelper.notNull(manager, "ExecutorServiceManager", camelContext); 287 288 // prefer to use explicit configured executor on the definition 289 if (definition.getExecutorService() != null) { 290 return definition.getExecutorService(); 291 } else if (definition.getExecutorServiceRef() != null) { 292 // lookup in registry first and use existing thread pool if exists 293 ExecutorService answer = lookupExecutorServiceRef(name, definition, parseString(definition.getExecutorServiceRef())); 294 if (answer == null) { 295 throw new IllegalArgumentException("ExecutorServiceRef " + definition.getExecutorServiceRef() 296 + " not found in registry (as an ExecutorService instance) or as a thread pool profile."); 297 } 298 return answer; 299 } else if (useDefault) { 300 return manager.newDefaultThreadPool(definition, name); 301 } 302 303 return null; 304 } 305 306 /** 307 * Will lookup and get the configured 308 * {@link java.util.concurrent.ScheduledExecutorService} from the given 309 * definition. 310 * <p/> 311 * This method will lookup for configured thread pool in the following order 312 * <ul> 313 * <li>from the definition if any explicit configured executor service.</li> 314 * <li>from the {@link org.apache.camel.spi.Registry} if found</li> 315 * <li>from the known list of {@link org.apache.camel.spi.ThreadPoolProfile 316 * ThreadPoolProfile(s)}.</li> 317 * <li>if none found, then <tt>null</tt> is returned.</li> 318 * </ul> 319 * The various {@link ExecutorServiceAwareDefinition} should use this helper 320 * method to ensure they support configured executor services in the same 321 * coherent way. 322 * 323 * @param name name which is appended to the thread name, when the 324 * {@link ExecutorService} is created based 325 * on a {@link org.apache.camel.spi.ThreadPoolProfile}. 326 * @param definition the node definition which may leverage executor 327 * service. 328 * @param useDefault whether to fallback and use a default thread pool, if 329 * no explicit configured 330 * @return the configured executor service, or <tt>null</tt> if none was 331 * configured. 332 * @throws IllegalArgumentException is thrown if the found instance is not a 333 * ScheduledExecutorService type, or lookup of executor service 334 * in {@link org.apache.camel.spi.Registry} was not found 335 */ 336 public ScheduledExecutorService getConfiguredScheduledExecutorService(String name, ExecutorServiceAwareDefinition<?> definition, 337 boolean useDefault) 338 throws IllegalArgumentException { 339 ExecutorServiceManager manager = camelContext.getExecutorServiceManager(); 340 ObjectHelper.notNull(manager, "ExecutorServiceManager", camelContext); 341 342 // prefer to use explicit configured executor on the definition 343 if (definition.getExecutorService() != null) { 344 ExecutorService executorService = definition.getExecutorService(); 345 if (executorService instanceof ScheduledExecutorService) { 346 return (ScheduledExecutorService)executorService; 347 } 348 throw new IllegalArgumentException("ExecutorServiceRef " + definition.getExecutorServiceRef() + " is not an ScheduledExecutorService instance"); 349 } else if (definition.getExecutorServiceRef() != null) { 350 ScheduledExecutorService answer = lookupScheduledExecutorServiceRef(name, definition, definition.getExecutorServiceRef()); 351 if (answer == null) { 352 throw new IllegalArgumentException("ExecutorServiceRef " + definition.getExecutorServiceRef() 353 + " not found in registry (as an ScheduledExecutorService instance) or as a thread pool profile."); 354 } 355 return answer; 356 } else if (useDefault) { 357 return manager.newDefaultScheduledThreadPool(definition, name); 358 } 359 360 return null; 361 } 362 363 /** 364 * Will lookup in {@link org.apache.camel.spi.Registry} for a 365 * {@link ScheduledExecutorService} registered with the given 366 * <tt>executorServiceRef</tt> name. 367 * <p/> 368 * This method will lookup for configured thread pool in the following order 369 * <ul> 370 * <li>from the {@link org.apache.camel.spi.Registry} if found</li> 371 * <li>from the known list of {@link org.apache.camel.spi.ThreadPoolProfile 372 * ThreadPoolProfile(s)}.</li> 373 * <li>if none found, then <tt>null</tt> is returned.</li> 374 * </ul> 375 * 376 * @param name name which is appended to the thread name, when the 377 * {@link ExecutorService} is created based 378 * on a {@link org.apache.camel.spi.ThreadPoolProfile}. 379 * @param source the source to use the thread pool 380 * @param executorServiceRef reference name of the thread pool 381 * @return the executor service, or <tt>null</tt> if none was found. 382 */ 383 public ScheduledExecutorService lookupScheduledExecutorServiceRef(String name, Object source, String executorServiceRef) { 384 385 ExecutorServiceManager manager = camelContext.getExecutorServiceManager(); 386 ObjectHelper.notNull(manager, "ExecutorServiceManager", camelContext); 387 ObjectHelper.notNull(executorServiceRef, "executorServiceRef"); 388 389 // lookup in registry first and use existing thread pool if exists 390 ScheduledExecutorService answer = lookup(executorServiceRef, ScheduledExecutorService.class); 391 if (answer == null) { 392 // then create a thread pool assuming the ref is a thread pool 393 // profile id 394 answer = manager.newScheduledThreadPool(source, name, executorServiceRef); 395 } 396 return answer; 397 } 398 399 /** 400 * Will lookup in {@link org.apache.camel.spi.Registry} for a 401 * {@link ExecutorService} registered with the given 402 * <tt>executorServiceRef</tt> name. 403 * <p/> 404 * This method will lookup for configured thread pool in the following order 405 * <ul> 406 * <li>from the {@link org.apache.camel.spi.Registry} if found</li> 407 * <li>from the known list of {@link org.apache.camel.spi.ThreadPoolProfile 408 * ThreadPoolProfile(s)}.</li> 409 * <li>if none found, then <tt>null</tt> is returned.</li> 410 * </ul> 411 * 412 * @param name name which is appended to the thread name, when the 413 * {@link ExecutorService} is created based 414 * on a {@link org.apache.camel.spi.ThreadPoolProfile}. 415 * @param source the source to use the thread pool 416 * @param executorServiceRef reference name of the thread pool 417 * @return the executor service, or <tt>null</tt> if none was found. 418 */ 419 public ExecutorService lookupExecutorServiceRef(String name, Object source, String executorServiceRef) { 420 421 ExecutorServiceManager manager = camelContext.getExecutorServiceManager(); 422 ObjectHelper.notNull(manager, "ExecutorServiceManager", camelContext); 423 ObjectHelper.notNull(executorServiceRef, "executorServiceRef"); 424 425 // lookup in registry first and use existing thread pool if exists 426 ExecutorService answer = lookup(executorServiceRef, ExecutorService.class); 427 if (answer == null) { 428 // then create a thread pool assuming the ref is a thread pool 429 // profile id 430 answer = manager.newThreadPool(source, name, executorServiceRef); 431 } 432 return answer; 433 } 434 435 /** 436 * Is there any outputs in the given list. 437 * <p/> 438 * Is used for check if the route output has any real outputs (non 439 * abstracts) 440 * 441 * @param outputs the outputs 442 * @param excludeAbstract whether or not to exclude abstract outputs (e.g. 443 * skip onException etc.) 444 * @return <tt>true</tt> if has outputs, otherwise <tt>false</tt> is 445 * returned 446 */ 447 @SuppressWarnings({"unchecked", "rawtypes"}) 448 public boolean hasOutputs(List<ProcessorDefinition<?>> outputs, boolean excludeAbstract) { 449 if (outputs == null || outputs.isEmpty()) { 450 return false; 451 } 452 if (!excludeAbstract) { 453 return true; 454 } 455 for (ProcessorDefinition output : outputs) { 456 if (output.isWrappingEntireOutput()) { 457 // special for those as they wrap entire output, so we should 458 // just check its output 459 return hasOutputs(output.getOutputs(), excludeAbstract); 460 } 461 if (!output.isAbstract()) { 462 return true; 463 } 464 } 465 return false; 466 } 467 468 /** 469 * Override this in definition class and implement logic to create the 470 * processor based on the definition model. 471 */ 472 public abstract Processor createProcessor() throws Exception; 473 474 /** 475 * Prefer to use {#link #createChildProcessor}. 476 */ 477 protected Processor createOutputsProcessor() throws Exception { 478 Collection<ProcessorDefinition<?>> outputs = definition.getOutputs(); 479 return createOutputsProcessor(outputs); 480 } 481 482 /** 483 * Creates the child processor (outputs) from the current definition 484 * 485 * @param mandatory whether or not children is mandatory (ie the definition 486 * should have outputs) 487 * @return the created children, or <tt>null</tt> if definition had no 488 * output 489 * @throws Exception is thrown if error creating the child or if it was 490 * mandatory and there was no output defined on definition 491 */ 492 protected Processor createChildProcessor(boolean mandatory) throws Exception { 493 Processor children = null; 494 // at first use custom factory 495 if (camelContext.adapt(ExtendedCamelContext.class).getProcessorFactory() != null) { 496 children = camelContext.adapt(ExtendedCamelContext.class).getProcessorFactory().createChildProcessor(route, definition, mandatory); 497 } 498 // fallback to default implementation if factory did not create the 499 // child 500 if (children == null) { 501 children = createOutputsProcessor(); 502 } 503 504 if (children == null && mandatory) { 505 throw new IllegalArgumentException("Definition has no children on " + definition); 506 } 507 return children; 508 } 509 510 public void addRoutes() throws Exception { 511 Channel processor = makeProcessor(); 512 if (processor == null) { 513 // no processor to add 514 return; 515 } 516 517 // are we routing to an endpoint interceptor, if so we should not 518 // add it as an event driven 519 // processor as we use the producer to trigger the interceptor 520 boolean endpointInterceptor = processor.getNextProcessor() instanceof InterceptEndpointProcessor; 521 522 // only add regular processors as event driven 523 if (endpointInterceptor) { 524 log.debug("Endpoint interceptor should not be added as an event driven consumer route: {}", processor); 525 } else { 526 log.trace("Adding event driven processor: {}", processor); 527 route.getEventDrivenProcessors().add(processor); 528 } 529 } 530 531 /** 532 * Wraps the child processor in whatever necessary interceptors and error 533 * handlers 534 */ 535 public Channel wrapProcessor(Processor processor) throws Exception { 536 // don't double wrap 537 if (processor instanceof Channel) { 538 return (Channel)processor; 539 } 540 return wrapChannel(processor, null); 541 } 542 543 protected Channel wrapChannel(Processor processor, ProcessorDefinition<?> child) throws Exception { 544 return wrapChannel(processor, child, definition.isInheritErrorHandler()); 545 } 546 547 protected Channel wrapChannel(Processor processor, ProcessorDefinition<?> child, Boolean inheritErrorHandler) throws Exception { 548 // put a channel in between this and each output to control the route 549 // flow logic 550 DefaultChannel channel = new DefaultChannel(camelContext); 551 552 // add interceptor strategies to the channel must be in this order: 553 // camel context, route context, local 554 List<InterceptStrategy> interceptors = new ArrayList<>(); 555 interceptors.addAll(camelContext.adapt(ExtendedCamelContext.class).getInterceptStrategies()); 556 interceptors.addAll(route.getInterceptStrategies()); 557 interceptors.addAll(definition.getInterceptStrategies()); 558 559 // force the creation of an id 560 RouteDefinitionHelper.forceAssignIds(camelContext, definition); 561 562 // fix parent/child relationship. This will be the case of the routes 563 // has been 564 // defined using XML DSL or end user may have manually assembled a route 565 // from the model. 566 // Background note: parent/child relationship is assembled on-the-fly 567 // when using Java DSL (fluent builders) 568 // where as when using XML DSL (JAXB) then it fixed after, but if people 569 // are using custom interceptors 570 // then we need to fix the parent/child relationship beforehand, and 571 // thus we can do it here 572 // ideally we need the design time route -> runtime route to be a 573 // 2-phase pass (scheduled work for Camel 3.0) 574 if (child != null && definition != child) { 575 child.setParent(definition); 576 } 577 578 // set the child before init the channel 579 RouteDefinition route = ProcessorDefinitionHelper.getRoute(definition); 580 boolean first = false; 581 if (route != null && !route.getOutputs().isEmpty()) { 582 first = route.getOutputs().get(0) == definition; 583 } 584 // initialize the channel 585 channel.initChannel(this.route, definition, child, interceptors, processor, route, first); 586 587 boolean wrap = false; 588 // set the error handler, must be done after init as we can set the 589 // error handler as first in the chain 590 if (definition instanceof TryDefinition || definition instanceof CatchDefinition || definition instanceof FinallyDefinition) { 591 // do not use error handler for try .. catch .. finally blocks as it 592 // will handle errors itself 593 log.trace("{} is part of doTry .. doCatch .. doFinally so no error handler is applied", definition); 594 } else if (ProcessorDefinitionHelper.isParentOfType(TryDefinition.class, definition, true) 595 || ProcessorDefinitionHelper.isParentOfType(CatchDefinition.class, definition, true) 596 || ProcessorDefinitionHelper.isParentOfType(FinallyDefinition.class, definition, true)) { 597 // do not use error handler for try .. catch .. finally blocks as it 598 // will handle errors itself 599 // by checking that any of our parent(s) is not a try .. catch or 600 // finally type 601 log.trace("{} is part of doTry .. doCatch .. doFinally so no error handler is applied", definition); 602 } else if (definition instanceof OnExceptionDefinition || ProcessorDefinitionHelper.isParentOfType(OnExceptionDefinition.class, definition, true)) { 603 log.trace("{} is part of OnException so no error handler is applied", definition); 604 // do not use error handler for onExceptions blocks as it will 605 // handle errors itself 606 } else if (definition instanceof CircuitBreakerDefinition || ProcessorDefinitionHelper.isParentOfType(CircuitBreakerDefinition.class, definition, true)) { 607 // do not use error handler for circuit breaker 608 // however if inherit error handler is enabled, we need to wrap an error handler on the parent 609 if (inheritErrorHandler != null && inheritErrorHandler && child == null) { 610 // only wrap the parent (not the children of the circuit breaker) 611 wrap = true; 612 } else { 613 log.trace("{} is part of CircuitBreaker so no error handler is applied", definition); 614 } 615 } else if (definition instanceof MulticastDefinition) { 616 // do not use error handler for multicast as it offers fine grained 617 // error handlers for its outputs 618 // however if share unit of work is enabled, we need to wrap an 619 // error handler on the multicast parent 620 MulticastDefinition def = (MulticastDefinition)definition; 621 boolean isShareUnitOfWork = parseBoolean(def.getShareUnitOfWork(), false); 622 if (isShareUnitOfWork && child == null) { 623 // only wrap the parent (not the children of the multicast) 624 wrap = true; 625 } else { 626 log.trace("{} is part of multicast which have special error handling so no error handler is applied", definition); 627 } 628 } else { 629 // use error handler by default or if configured to do so 630 wrap = true; 631 } 632 if (wrap) { 633 wrapChannelInErrorHandler(channel, inheritErrorHandler); 634 } 635 636 // do post init at the end 637 channel.postInitChannel(); 638 log.trace("{} wrapped in Channel: {}", definition, channel); 639 640 return channel; 641 } 642 643 /** 644 * Wraps the given channel in error handler (if error handler is inherited) 645 * 646 * @param channel the channel 647 * @param inheritErrorHandler whether to inherit error handler 648 * @throws Exception can be thrown if failed to create error handler builder 649 */ 650 private void wrapChannelInErrorHandler(DefaultChannel channel, Boolean inheritErrorHandler) throws Exception { 651 if (inheritErrorHandler == null || inheritErrorHandler) { 652 log.trace("{} is configured to inheritErrorHandler", definition); 653 Processor output = channel.getOutput(); 654 Processor errorHandler = wrapInErrorHandler(output, true); 655 // set error handler on channel 656 channel.setErrorHandler(errorHandler); 657 } else { 658 log.debug("{} is configured to not inheritErrorHandler.", definition); 659 } 660 } 661 662 /** 663 * Wraps the given output in an error handler 664 * 665 * @param output the output 666 * @param longLived if the processor is longLived or not 667 * @return the output wrapped with the error handler 668 * @throws Exception can be thrown if failed to create error handler builder 669 */ 670 protected Processor wrapInErrorHandler(Processor output, boolean longLived) throws Exception { 671 ErrorHandlerFactory builder = route.getErrorHandlerFactory(); 672 673 // create error handler 674 Processor errorHandler = ErrorHandlerReifier.reifier(route, builder).createErrorHandler(output); 675 676 if (longLived) { 677 // invoke lifecycles so we can manage this error handler builder 678 for (LifecycleStrategy strategy : camelContext.getLifecycleStrategies()) { 679 strategy.onErrorHandlerAdd(route, errorHandler, builder); 680 } 681 } 682 683 return errorHandler; 684 } 685 686 /** 687 * Creates a new instance of some kind of composite processor which defaults 688 * to using a {@link Pipeline} but derived classes could change the 689 * behaviour 690 */ 691 protected Processor createCompositeProcessor(List<Processor> list) throws Exception { 692 return Pipeline.newInstance(camelContext, list); 693 } 694 695 protected Processor createOutputsProcessor(Collection<ProcessorDefinition<?>> outputs) throws Exception { 696 List<Processor> list = new ArrayList<>(); 697 for (ProcessorDefinition<?> output : outputs) { 698 699 // allow any custom logic before we create the processor 700 reifier(route, output).preCreateProcessor(); 701 702 Processor processor = createProcessor(output); 703 704 // inject id 705 if (processor instanceof IdAware) { 706 String id = getId(output); 707 ((IdAware)processor).setId(id); 708 } 709 if (processor instanceof RouteIdAware) { 710 ((RouteIdAware)processor).setRouteId(route.getRouteId()); 711 } 712 713 if (output instanceof Channel && processor == null) { 714 continue; 715 } 716 717 Processor channel = wrapChannel(processor, output); 718 list.add(channel); 719 } 720 721 // if more than one output wrap than in a composite processor else just 722 // keep it as is 723 Processor processor = null; 724 if (!list.isEmpty()) { 725 if (list.size() == 1) { 726 processor = list.get(0); 727 } else { 728 processor = createCompositeProcessor(list); 729 } 730 } 731 732 return processor; 733 } 734 735 protected Processor createProcessor(ProcessorDefinition<?> output) throws Exception { 736 Processor processor = null; 737 // at first use custom factory 738 if (camelContext.adapt(ExtendedCamelContext.class).getProcessorFactory() != null) { 739 processor = camelContext.adapt(ExtendedCamelContext.class).getProcessorFactory().createProcessor(route, output); 740 } 741 // fallback to default implementation if factory did not create the 742 // processor 743 if (processor == null) { 744 processor = reifier(route, output).createProcessor(); 745 } 746 return processor; 747 } 748 749 /** 750 * Creates the processor and wraps it in any necessary interceptors and 751 * error handlers 752 */ 753 protected Channel makeProcessor() throws Exception { 754 Processor processor = null; 755 756 // allow any custom logic before we create the processor 757 preCreateProcessor(); 758 759 // at first use custom factory 760 if (camelContext.adapt(ExtendedCamelContext.class).getProcessorFactory() != null) { 761 processor = camelContext.adapt(ExtendedCamelContext.class).getProcessorFactory().createProcessor(route, definition); 762 } 763 // fallback to default implementation if factory did not create the 764 // processor 765 if (processor == null) { 766 processor = createProcessor(); 767 } 768 769 // inject id 770 if (processor instanceof IdAware) { 771 String id = getId(definition); 772 ((IdAware)processor).setId(id); 773 } 774 if (processor instanceof RouteIdAware) { 775 ((RouteIdAware)processor).setRouteId(route.getRouteId()); 776 } 777 778 if (processor == null) { 779 // no processor to make 780 return null; 781 } 782 return wrapProcessor(processor); 783 } 784 785 /** 786 * Strategy to execute any custom logic before the {@link Processor} is 787 * created. 788 */ 789 protected void preCreateProcessor() { 790 definition.preCreateProcessor(); 791 } 792 793 /** 794 * Strategy for children to do any custom configuration 795 * 796 * @param output the child to be added as output to this 797 */ 798 public void configureChild(ProcessorDefinition<?> output) { 799 // noop 800 } 801 802 protected String getId(OptionalIdentifiedDefinition<?> def) { 803 return def.idOrCreate(camelContext.adapt(ExtendedCamelContext.class).getNodeIdFactory()); 804 } 805 806}