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 */ 017 package org.apache.camel.spring; 018 019 import java.util.ArrayList; 020 import java.util.Arrays; 021 import java.util.List; 022 import java.util.Map; 023 import javax.xml.bind.annotation.XmlAccessType; 024 import javax.xml.bind.annotation.XmlAccessorType; 025 import javax.xml.bind.annotation.XmlAttribute; 026 import javax.xml.bind.annotation.XmlElement; 027 import javax.xml.bind.annotation.XmlElements; 028 import javax.xml.bind.annotation.XmlRootElement; 029 import javax.xml.bind.annotation.XmlTransient; 030 031 import org.apache.camel.CamelException; 032 import org.apache.camel.RoutesBuilder; 033 import org.apache.camel.builder.ErrorHandlerBuilder; 034 import org.apache.camel.builder.RouteBuilder; 035 import org.apache.camel.impl.DefaultLifecycleStrategy; 036 import org.apache.camel.impl.scan.PatternBasedPackageScanFilter; 037 import org.apache.camel.management.DefaultInstrumentationAgent; 038 import org.apache.camel.management.InstrumentationLifecycleStrategy; 039 import org.apache.camel.model.FromDefinition; 040 import org.apache.camel.model.IdentifiedType; 041 import org.apache.camel.model.InterceptDefinition; 042 import org.apache.camel.model.InterceptFromDefinition; 043 import org.apache.camel.model.InterceptSendToEndpointDefinition; 044 import org.apache.camel.model.OnCompletionDefinition; 045 import org.apache.camel.model.OnExceptionDefinition; 046 import org.apache.camel.model.PackageScanDefinition; 047 import org.apache.camel.model.PolicyDefinition; 048 import org.apache.camel.model.ProcessorDefinition; 049 import org.apache.camel.model.RouteBuilderDefinition; 050 import org.apache.camel.model.RouteContainer; 051 import org.apache.camel.model.RouteDefinition; 052 import org.apache.camel.model.TransactedDefinition; 053 import org.apache.camel.model.config.PropertiesDefinition; 054 import org.apache.camel.model.dataformat.DataFormatsDefinition; 055 import org.apache.camel.processor.interceptor.Delayer; 056 import org.apache.camel.processor.interceptor.HandleFault; 057 import org.apache.camel.processor.interceptor.TraceFormatter; 058 import org.apache.camel.processor.interceptor.Tracer; 059 import org.apache.camel.spi.ClassResolver; 060 import org.apache.camel.spi.FactoryFinderResolver; 061 import org.apache.camel.spi.InterceptStrategy; 062 import org.apache.camel.spi.LifecycleStrategy; 063 import org.apache.camel.spi.PackageScanClassResolver; 064 import org.apache.camel.spi.Registry; 065 import org.apache.camel.util.EndpointHelper; 066 import org.apache.camel.util.ObjectHelper; 067 import org.apache.commons.logging.Log; 068 import org.apache.commons.logging.LogFactory; 069 import org.springframework.beans.factory.DisposableBean; 070 import org.springframework.beans.factory.FactoryBean; 071 import org.springframework.beans.factory.InitializingBean; 072 import org.springframework.beans.factory.config.BeanPostProcessor; 073 import org.springframework.context.ApplicationContext; 074 import org.springframework.context.ApplicationContextAware; 075 import org.springframework.context.ApplicationEvent; 076 import org.springframework.context.ApplicationListener; 077 import org.springframework.context.event.ContextRefreshedEvent; 078 import static org.apache.camel.util.ObjectHelper.wrapRuntimeCamelException; 079 080 /** 081 * A Spring {@link FactoryBean} to create and initialize a 082 * {@link SpringCamelContext} and install routes either explicitly configured in 083 * Spring XML or found by searching the classpath for Java classes which extend 084 * {@link RouteBuilder} using the nested {@link #setPackages(String[])}. 085 * 086 * @version $Revision: 801982 $ 087 */ 088 @XmlRootElement(name = "camelContext") 089 @XmlAccessorType(XmlAccessType.FIELD) 090 public class CamelContextFactoryBean extends IdentifiedType implements RouteContainer, FactoryBean, InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener { 091 private static final Log LOG = LogFactory.getLog(CamelContextFactoryBean.class); 092 093 @XmlAttribute(required = false) 094 private Boolean trace; 095 @XmlAttribute(required = false) 096 private Boolean streamCache = Boolean.FALSE; 097 @XmlAttribute(required = false) 098 private Long delayer; 099 @XmlAttribute(required = false) 100 private Boolean handleFault; 101 @XmlAttribute(required = false) 102 private String errorHandlerRef; 103 @XmlAttribute(required = false) 104 private Boolean shouldStartContext = Boolean.TRUE; 105 @XmlElement(name = "properties", required = false) 106 private PropertiesDefinition properties; 107 @XmlElement(name = "package", required = false) 108 private String[] packages = {}; 109 @XmlElement(name = "packageScan", type = PackageScanDefinition.class, required = false) 110 private PackageScanDefinition packageScan; 111 @XmlElement(name = "jmxAgent", type = CamelJMXAgentDefinition.class, required = false) 112 private CamelJMXAgentDefinition camelJMXAgent; 113 @XmlElements({ 114 @XmlElement(name = "beanPostProcessor", type = CamelBeanPostProcessor.class, required = false), 115 @XmlElement(name = "template", type = CamelProducerTemplateFactoryBean.class, required = false), 116 @XmlElement(name = "consumerTemplate", type = CamelConsumerTemplateFactoryBean.class, required = false), 117 @XmlElement(name = "proxy", type = CamelProxyFactoryDefinition.class, required = false), 118 @XmlElement(name = "export", type = CamelServiceExporterDefinition.class, required = false)}) 119 private List beans; 120 @XmlElement(name = "routeBuilder", required = false) 121 private List<RouteBuilderDefinition> builderRefs = new ArrayList<RouteBuilderDefinition>(); 122 @XmlElement(name = "endpoint", required = false) 123 private List<CamelEndpointFactoryBean> endpoints; 124 @XmlElement(name = "dataFormats", required = false) 125 private DataFormatsDefinition dataFormats; 126 @XmlElement(name = "onException", required = false) 127 private List<OnExceptionDefinition> onExceptions = new ArrayList<OnExceptionDefinition>(); 128 @XmlElement(name = "onCompletion", required = false) 129 private List<OnCompletionDefinition> onCompletions = new ArrayList<OnCompletionDefinition>(); 130 @XmlElement(name = "intercept", required = false) 131 private List<InterceptDefinition> intercepts = new ArrayList<InterceptDefinition>(); 132 @XmlElement(name = "interceptFrom", required = false) 133 private List<InterceptFromDefinition> interceptFroms = new ArrayList<InterceptFromDefinition>(); 134 @XmlElement(name = "interceptSendToEndpoint", required = false) 135 private List<InterceptSendToEndpointDefinition> interceptSendToEndpoints = new ArrayList<InterceptSendToEndpointDefinition>(); 136 @XmlElement(name = "route", required = false) 137 private List<RouteDefinition> routes = new ArrayList<RouteDefinition>(); 138 @XmlTransient 139 private SpringCamelContext context; 140 @XmlTransient 141 private RouteBuilder routeBuilder; 142 @XmlTransient 143 private List<RoutesBuilder> additionalBuilders = new ArrayList<RoutesBuilder>(); 144 @XmlTransient 145 private ApplicationContext applicationContext; 146 @XmlTransient 147 private ClassLoader contextClassLoaderOnStart; 148 @XmlTransient 149 private BeanPostProcessor beanPostProcessor; 150 151 public CamelContextFactoryBean() { 152 // Lets keep track of the class loader for when we actually do start things up 153 contextClassLoaderOnStart = Thread.currentThread().getContextClassLoader(); 154 } 155 156 public Object getObject() throws Exception { 157 return getContext(); 158 } 159 160 public Class getObjectType() { 161 return SpringCamelContext.class; 162 } 163 164 public boolean isSingleton() { 165 return true; 166 } 167 168 public ClassLoader getContextClassLoaderOnStart() { 169 return contextClassLoaderOnStart; 170 } 171 172 public List<RoutesBuilder> getAdditionalBuilders() { 173 return additionalBuilders; 174 } 175 176 public void afterPropertiesSet() throws Exception { 177 if (properties != null) { 178 getContext().setProperties(properties.asMap()); 179 } 180 181 // set the resolvers first 182 PackageScanClassResolver packageResolver = getBeanForType(PackageScanClassResolver.class); 183 if (packageResolver != null) { 184 LOG.info("Using custom PackageScanClassResolver: " + packageResolver); 185 getContext().setPackageScanClassResolver(packageResolver); 186 } 187 ClassResolver classResolver = getBeanForType(ClassResolver.class); 188 if (classResolver != null) { 189 LOG.info("Using custom ClassResolver: " + classResolver); 190 getContext().setClassResolver(classResolver); 191 } 192 FactoryFinderResolver factoryFinderResolver = getBeanForType(FactoryFinderResolver.class); 193 if (factoryFinderResolver != null) { 194 LOG.info("Using custom FactoryFinderResolver: " + factoryFinderResolver); 195 getContext().setFactoryFinderResolver(factoryFinderResolver); 196 } 197 198 // set the lifecycle strategy if defined 199 LifecycleStrategy lifecycleStrategy = getBeanForType(LifecycleStrategy.class); 200 if (lifecycleStrategy != null) { 201 LOG.info("Using custom LifecycleStrategy: " + lifecycleStrategy); 202 getContext().setLifecycleStrategy(lifecycleStrategy); 203 } 204 205 // set the strategy if defined 206 Registry registry = getBeanForType(Registry.class); 207 if (registry != null) { 208 LOG.info("Using custom Registry: " + registry); 209 getContext().setRegistry(registry); 210 } 211 212 Tracer tracer = getBeanForType(Tracer.class); 213 if (tracer != null) { 214 // use formatter if there is a TraceFormatter bean defined 215 TraceFormatter formatter = getBeanForType(TraceFormatter.class); 216 if (formatter != null) { 217 tracer.setFormatter(formatter); 218 } 219 LOG.info("Using custom Tracer: " + tracer); 220 getContext().addInterceptStrategy(tracer); 221 } 222 223 HandleFault handleFault = getBeanForType(HandleFault.class); 224 if (handleFault != null) { 225 LOG.info("Using custom HandleFault: " + handleFault); 226 getContext().addInterceptStrategy(handleFault); 227 } 228 229 Delayer delayer = getBeanForType(Delayer.class); 230 if (delayer != null) { 231 LOG.info("Using custom Delayer: " + delayer); 232 getContext().addInterceptStrategy(delayer); 233 } 234 235 // add global interceptors 236 Map<String, InterceptStrategy> strategies = getContext().getRegistry().lookupByType(InterceptStrategy.class); 237 if (strategies != null && !strategies.isEmpty()) { 238 for (String id : strategies.keySet()) { 239 InterceptStrategy strategy = strategies.get(id); 240 // do not add if already added, for instance a tracer that is also an InterceptStrategy class 241 if (!getContext().getInterceptStrategies().contains(strategy)) { 242 LOG.info("Using custom intercept strategy with id: " + id + " and implementation: " + strategy); 243 getContext().addInterceptStrategy(strategy); 244 } 245 } 246 } 247 248 // Set the application context and camelContext for the beanPostProcessor 249 if (beanPostProcessor != null) { 250 if (beanPostProcessor instanceof ApplicationContextAware) { 251 ((ApplicationContextAware)beanPostProcessor).setApplicationContext(applicationContext); 252 } 253 if (beanPostProcessor instanceof CamelBeanPostProcessor) { 254 ((CamelBeanPostProcessor)beanPostProcessor).setCamelContext(getContext()); 255 } 256 } 257 258 // do special preparation for some concepts such as interceptors and policies 259 // this is needed as JAXB does not build excaclty the same model definition as Spring DSL would do 260 // using route builders. So we have here a little custom code to fix the JAXB gaps 261 for (RouteDefinition route : routes) { 262 // interceptors should be first 263 initInterceptors(route); 264 // then on completion 265 initOnCompletions(route); 266 // then polices 267 initPolicies(route); 268 // and last on exception 269 initOnExceptions(route); 270 } 271 272 if (dataFormats != null) { 273 getContext().setDataFormats(dataFormats.asMap()); 274 } 275 276 // lets force any lazy creation 277 getContext().addRouteDefinitions(routes); 278 279 // setup JMX agent 280 initJMXAgent(); 281 282 if (LOG.isDebugEnabled()) { 283 LOG.debug("Found JAXB created routes: " + getRoutes()); 284 } 285 findRouteBuilders(); 286 installRoutes(); 287 } 288 289 private void initOnExceptions(RouteDefinition route) { 290 List<ProcessorDefinition<?>> outputs = new ArrayList<ProcessorDefinition<?>>(); 291 List<ProcessorDefinition<?>> exceptionHandlers = new ArrayList<ProcessorDefinition<?>>(); 292 293 // add global on exceptions if any 294 if (onExceptions != null && !onExceptions.isEmpty()) { 295 // on exceptions must be added at top, so the route flow is correct as 296 // on exceptions should be the first outputs 297 route.getOutputs().addAll(0, onExceptions); 298 } 299 300 for (ProcessorDefinition output : route.getOutputs()) { 301 // split into on exception and regular outputs 302 if (output instanceof OnExceptionDefinition) { 303 exceptionHandlers.add(output); 304 } else { 305 outputs.add(output); 306 } 307 } 308 309 // clearing the outputs 310 route.clearOutput(); 311 312 // add exception handlers as top children 313 route.getOutputs().addAll(exceptionHandlers); 314 315 // and the remaining outputs 316 route.getOutputs().addAll(outputs); 317 } 318 319 private void initInterceptors(RouteDefinition route) { 320 321 // configure intercept 322 for (InterceptDefinition intercept : getIntercepts()) { 323 intercept.afterPropertiesSet(); 324 // add as first output so intercept is handled before the acutal route and that gives 325 // us the needed head start to init and be able to intercept all the remaining processing steps 326 route.getOutputs().add(0, intercept); 327 } 328 329 // configure intercept from 330 for (InterceptFromDefinition intercept : getInterceptFroms()) { 331 332 // should we only apply interceptor for a given endpoint uri 333 boolean match = true; 334 if (intercept.getUri() != null) { 335 match = false; 336 for (FromDefinition input : route.getInputs()) { 337 if (EndpointHelper.matchEndpoint(input.getUri(), intercept.getUri())) { 338 match = true; 339 break; 340 } 341 } 342 } 343 344 if (match) { 345 intercept.afterPropertiesSet(); 346 // add as first output so intercept is handled before the acutal route and that gives 347 // us the needed head start to init and be able to intercept all the remaining processing steps 348 route.getOutputs().add(0, intercept); 349 } 350 } 351 352 // configure intercept send to endpoint 353 for (InterceptSendToEndpointDefinition intercept : getInterceptSendToEndpoints()) { 354 intercept.afterPropertiesSet(); 355 // add as first output so intercept is handled before the acutal route and that gives 356 // us the needed head start to init and be able to intercept all the remaining processing steps 357 route.getOutputs().add(0, intercept); 358 } 359 360 } 361 362 private void initOnCompletions(RouteDefinition route) { 363 // only add global onCompletion if there are no route alredy 364 boolean hasRouteScope = false; 365 for (ProcessorDefinition out : route.getOutputs()) { 366 if (out instanceof OnCompletionDefinition) { 367 hasRouteScope = true; 368 break; 369 } 370 } 371 // only add global onCompletion if we do *not* have any route onCompletion defined in the route 372 // add onCompletion *after* intercept, as its important intercept is first 373 if (!hasRouteScope) { 374 int index = 0; 375 for (int i = 0; i < route.getOutputs().size(); i++) { 376 index = i; 377 ProcessorDefinition out = route.getOutputs().get(i); 378 if (out instanceof InterceptDefinition || out instanceof InterceptSendToEndpointDefinition) { 379 continue; 380 } else { 381 // we found the spot 382 break; 383 } 384 } 385 route.getOutputs().addAll(index, getOnCompletions()); 386 } 387 } 388 389 private void initPolicies(RouteDefinition route) { 390 // setup the policies as JAXB yet again have not created a correct model for us 391 List<ProcessorDefinition> types = route.getOutputs(); 392 393 // we need two types as transacted cannot extend policy due JAXB limitations 394 PolicyDefinition policy = null; 395 TransactedDefinition transacted = null; 396 397 // add to correct type 398 for (ProcessorDefinition type : types) { 399 if (type instanceof PolicyDefinition) { 400 policy = (PolicyDefinition) type; 401 } else if (type instanceof TransactedDefinition) { 402 transacted = (TransactedDefinition) type; 403 } else if (policy != null) { 404 // the outputs should be moved to the policy 405 policy.addOutput(type); 406 } else if (transacted != null) { 407 // the outputs should be moved to the transacted policy 408 transacted.addOutput(type); 409 } 410 } 411 412 // did we find a policy if so replace it as the only output on the route 413 if (policy != null) { 414 route.clearOutput(); 415 route.addOutput(policy); 416 } else if (transacted != null) { 417 route.clearOutput(); 418 route.addOutput(transacted); 419 } 420 } 421 422 private void initJMXAgent() throws Exception { 423 if (camelJMXAgent != null && camelJMXAgent.isDisabled()) { 424 LOG.info("JMXAgent disabled"); 425 getContext().setLifecycleStrategy(new DefaultLifecycleStrategy()); 426 } else if (camelJMXAgent != null) { 427 DefaultInstrumentationAgent agent = new DefaultInstrumentationAgent(); 428 agent.setConnectorPort(camelJMXAgent.getConnectorPort()); 429 agent.setCreateConnector(camelJMXAgent.isCreateConnector()); 430 agent.setMBeanObjectDomainName(camelJMXAgent.getMbeanObjectDomainName()); 431 agent.setMBeanServerDefaultDomain(camelJMXAgent.getMbeanServerDefaultDomain()); 432 agent.setRegistryPort(camelJMXAgent.getRegistryPort()); 433 agent.setServiceUrlPath(camelJMXAgent.getServiceUrlPath()); 434 agent.setUsePlatformMBeanServer(camelJMXAgent.isUsePlatformMBeanServer()); 435 agent.setOnlyRegisterProcessorWithCustomId(camelJMXAgent.getOnlyRegisterProcessorWithCustomId()); 436 437 LOG.info("JMXAgent enabled: " + camelJMXAgent); 438 getContext().setLifecycleStrategy(new InstrumentationLifecycleStrategy(agent)); 439 } 440 } 441 442 @SuppressWarnings("unchecked") 443 private <T> T getBeanForType(Class<T> clazz) { 444 T bean = null; 445 String[] names = getApplicationContext().getBeanNamesForType(clazz, true, true); 446 if (names.length == 1) { 447 bean = (T) getApplicationContext().getBean(names[0], clazz); 448 } 449 if (bean == null) { 450 ApplicationContext parentContext = getApplicationContext().getParent(); 451 if (parentContext != null) { 452 names = parentContext.getBeanNamesForType(clazz, true, true); 453 if (names.length == 1) { 454 bean = (T) parentContext.getBean(names[0], clazz); 455 } 456 } 457 } 458 return bean; 459 460 } 461 462 public void destroy() throws Exception { 463 getContext().stop(); 464 } 465 466 public void onApplicationEvent(ApplicationEvent event) { 467 if (context != null) { 468 // let the spring camel context handle the events 469 context.onApplicationEvent(event); 470 } else { 471 if (LOG.isDebugEnabled()) { 472 LOG.debug("Publishing spring-event: " + event); 473 } 474 475 if (event instanceof ContextRefreshedEvent) { 476 // now lets start the CamelContext so that all its possible 477 // dependencies are initialized 478 try { 479 LOG.debug("Starting the context now!"); 480 getContext().start(); 481 } catch (Exception e) { 482 throw wrapRuntimeCamelException(e); 483 } 484 } 485 } 486 } 487 488 // Properties 489 // ------------------------------------------------------------------------- 490 public SpringCamelContext getContext() throws Exception { 491 if (context == null) { 492 context = createContext(); 493 } 494 return context; 495 } 496 497 public void setContext(SpringCamelContext context) { 498 this.context = context; 499 } 500 501 public List<RouteDefinition> getRoutes() { 502 return routes; 503 } 504 505 public void setRoutes(List<RouteDefinition> routes) { 506 this.routes = routes; 507 } 508 509 public List<InterceptDefinition> getIntercepts() { 510 return intercepts; 511 } 512 513 public void setIntercepts(List<InterceptDefinition> intercepts) { 514 this.intercepts = intercepts; 515 } 516 517 public List<InterceptFromDefinition> getInterceptFroms() { 518 return interceptFroms; 519 } 520 521 public void setInterceptFroms(List<InterceptFromDefinition> interceptFroms) { 522 this.interceptFroms = interceptFroms; 523 } 524 525 public List<InterceptSendToEndpointDefinition> getInterceptSendToEndpoints() { 526 return interceptSendToEndpoints; 527 } 528 529 public void setInterceptSendToEndpoints(List<InterceptSendToEndpointDefinition> interceptSendToEndpoints) { 530 this.interceptSendToEndpoints = interceptSendToEndpoints; 531 } 532 533 public RouteBuilder getRouteBuilder() { 534 return routeBuilder; 535 } 536 537 /** 538 * Set a single {@link RouteBuilder} to be used to create the default routes 539 * on startup 540 */ 541 public void setRouteBuilder(RouteBuilder routeBuilder) { 542 this.routeBuilder = routeBuilder; 543 } 544 545 /** 546 * Set a collection of {@link RouteBuilder} instances to be used to create 547 * the default routes on startup 548 */ 549 public void setRouteBuilders(RouteBuilder[] builders) { 550 additionalBuilders.addAll(Arrays.asList(builders)); 551 } 552 553 public ApplicationContext getApplicationContext() { 554 if (applicationContext == null) { 555 throw new IllegalArgumentException("No applicationContext has been injected!"); 556 } 557 return applicationContext; 558 } 559 560 public void setApplicationContext(ApplicationContext applicationContext) { 561 this.applicationContext = applicationContext; 562 } 563 564 public PropertiesDefinition getProperties() { 565 return properties; 566 } 567 568 public void setProperties(PropertiesDefinition properties) { 569 this.properties = properties; 570 } 571 572 /** 573 * @deprecated replaced by {@link #getPackageScan()} 574 */ 575 @Deprecated 576 public String[] getPackages() { 577 return packages; 578 } 579 580 /** 581 * Sets the package names to be recursively searched for Java classes which 582 * extend {@link RouteBuilder} to be auto-wired up to the 583 * {@link SpringCamelContext} as a route. Note that classes are excluded if 584 * they are specifically configured in the spring.xml 585 * 586 * @deprecated replaced by {@link #setPackageScan(org.apache.camel.model.PackageScanDefinition)} 587 * @param packages the package names which are recursively searched 588 */ 589 @Deprecated 590 public void setPackages(String[] packages) { 591 this.packages = packages; 592 } 593 594 public PackageScanDefinition getPackageScan() { 595 return packageScan; 596 } 597 598 /** 599 * Sets the package scanning information. Package scanning allows for the 600 * automatic discovery of certain camel classes at runtime for inclusion 601 * e.g. {@link RouteBuilder} implementations 602 * 603 * @param packageScan the package scan 604 */ 605 public void setPackageScan(PackageScanDefinition packageScan) { 606 this.packageScan = packageScan; 607 } 608 609 public void setBeanPostProcessor(BeanPostProcessor postProcessor) { 610 this.beanPostProcessor = postProcessor; 611 } 612 613 public BeanPostProcessor getBeanPostProcessor() { 614 return beanPostProcessor; 615 } 616 617 public void setCamelJMXAgent(CamelJMXAgentDefinition agent) { 618 camelJMXAgent = agent; 619 } 620 621 public Boolean getTrace() { 622 return trace; 623 } 624 625 public void setTrace(Boolean trace) { 626 this.trace = trace; 627 } 628 629 public Boolean getStreamCache() { 630 return streamCache; 631 } 632 633 public void setStreamCache(Boolean streamCache) { 634 this.streamCache = streamCache; 635 } 636 637 public Long getDelayer() { 638 return delayer; 639 } 640 641 public void setDelayer(Long delayer) { 642 this.delayer = delayer; 643 } 644 645 public Boolean getHandleFault() { 646 return handleFault; 647 } 648 649 public void setHandleFault(Boolean handleFault) { 650 this.handleFault = handleFault; 651 } 652 653 public CamelJMXAgentDefinition getCamelJMXAgent() { 654 return camelJMXAgent; 655 } 656 657 public List<RouteBuilderDefinition> getBuilderRefs() { 658 return builderRefs; 659 } 660 661 public void setBuilderRefs(List<RouteBuilderDefinition> builderRefs) { 662 this.builderRefs = builderRefs; 663 } 664 665 public String getErrorHandlerRef() { 666 return errorHandlerRef; 667 } 668 669 /** 670 * Sets the name of the error handler object used to default the error handling strategy 671 * 672 * @param errorHandlerRef the Spring bean ref of the error handler 673 */ 674 public void setErrorHandlerRef(String errorHandlerRef) { 675 this.errorHandlerRef = errorHandlerRef; 676 } 677 678 public Boolean getShouldStartContext() { 679 return shouldStartContext; 680 } 681 682 public void setShouldStartContext(Boolean shouldStartContext) { 683 this.shouldStartContext = shouldStartContext; 684 } 685 686 public void setDataFormats(DataFormatsDefinition dataFormats) { 687 this.dataFormats = dataFormats; 688 } 689 690 public DataFormatsDefinition getDataFormats() { 691 return dataFormats; 692 } 693 694 public void setOnExceptions(List<OnExceptionDefinition> onExceptions) { 695 this.onExceptions = onExceptions; 696 } 697 698 public List<OnExceptionDefinition> getOnExceptions() { 699 return onExceptions; 700 } 701 702 public List<OnCompletionDefinition> getOnCompletions() { 703 return onCompletions; 704 } 705 706 public void setOnCompletions(List<OnCompletionDefinition> onCompletions) { 707 this.onCompletions = onCompletions; 708 } 709 710 // Implementation methods 711 // ------------------------------------------------------------------------- 712 713 /** 714 * Create the context 715 */ 716 protected SpringCamelContext createContext() { 717 SpringCamelContext ctx = new SpringCamelContext(getApplicationContext()); 718 ctx.setName(getId()); 719 if (streamCache != null) { 720 ctx.setStreamCaching(streamCache); 721 } 722 if (trace != null) { 723 ctx.setTracing(trace); 724 } 725 if (delayer != null) { 726 ctx.setDelayer(delayer); 727 } 728 if (handleFault != null) { 729 ctx.setHandleFault(handleFault); 730 } 731 if (errorHandlerRef != null) { 732 ErrorHandlerBuilder errorHandlerBuilder = (ErrorHandlerBuilder) getApplicationContext().getBean(errorHandlerRef, ErrorHandlerBuilder.class); 733 if (errorHandlerBuilder == null) { 734 throw new IllegalArgumentException("Cannot find ErrorHandlerBuilder bean with id: " + errorHandlerRef); 735 } 736 ctx.setErrorHandlerBuilder(errorHandlerBuilder); 737 } 738 739 if (shouldStartContext != null) { 740 ctx.setShouldStartContext(shouldStartContext); 741 } 742 743 return ctx; 744 } 745 746 /** 747 * Strategy to install all available routes into the context 748 */ 749 @SuppressWarnings("unchecked") 750 protected void installRoutes() throws Exception { 751 List<RouteBuilder> builders = new ArrayList<RouteBuilder>(); 752 753 if (routeBuilder != null) { 754 builders.add(routeBuilder); 755 } 756 757 // lets add route builders added from references 758 if (builderRefs != null) { 759 for (RouteBuilderDefinition builderRef : builderRefs) { 760 RouteBuilder builder = builderRef.createRouteBuilder(getContext()); 761 if (builder != null) { 762 builders.add(builder); 763 } else { 764 // support to get the route here 765 RoutesBuilder routes = builderRef.createRoutes(getContext()); 766 if (routes != null) { 767 additionalBuilders.add(routes); 768 } else { 769 // Throw the exception that we can't find any build here 770 throw new CamelException("Cannot find any routes with this RouteBuilder reference: " + builderRef); 771 } 772 } 773 774 } 775 } 776 777 // install already configured routes 778 for (RoutesBuilder routeBuilder : additionalBuilders) { 779 getContext().addRoutes(routeBuilder); 780 } 781 782 // install builders 783 for (RouteBuilder builder : builders) { 784 if (beanPostProcessor != null) { 785 // Inject the annotated resource 786 beanPostProcessor.postProcessBeforeInitialization(builder, builder.toString()); 787 } 788 getContext().addRoutes(builder); 789 } 790 } 791 792 /** 793 * Strategy method to try find {@link RouteBuilder} instances on the classpath 794 */ 795 protected void findRouteBuilders() throws Exception { 796 PackageScanClassResolver resolver = getContext().getPackageScanClassResolver(); 797 addPackageElementContentsToScanDefinition(); 798 799 PackageScanDefinition packageScanDef = getPackageScan(); 800 if (packageScanDef != null && packageScanDef.getPackages().size() > 0) { 801 // use package scan filter 802 PatternBasedPackageScanFilter filter = new PatternBasedPackageScanFilter(); 803 filter.addIncludePatterns(packageScanDef.getIncludes()); 804 filter.addExcludePatterns(packageScanDef.getExcludes()); 805 resolver.addFilter(filter); 806 807 String[] normalized = normalizePackages(packageScanDef.getPackages()); 808 RouteBuilderFinder finder = new RouteBuilderFinder(getContext(), normalized, getContextClassLoaderOnStart(), 809 getBeanPostProcessor(), getContext().getPackageScanClassResolver()); 810 finder.appendBuilders(getAdditionalBuilders()); 811 } 812 } 813 814 private void addPackageElementContentsToScanDefinition() { 815 PackageScanDefinition packageScanDef = getPackageScan(); 816 817 if (getPackages() != null && getPackages().length > 0) { 818 LOG.warn("Using a packages element to specify packages to search has been deprecated. Please use a packageScan element instead."); 819 if (packageScanDef == null) { 820 packageScanDef = new PackageScanDefinition(); 821 setPackageScan(packageScanDef); 822 } 823 824 for (String pkg : getPackages()) { 825 packageScanDef.getPackages().add(pkg); 826 } 827 } 828 } 829 830 private String[] normalizePackages(List<String> unnormalized) { 831 List<String> packages = new ArrayList<String>(); 832 for (String name : unnormalized) { 833 name = ObjectHelper.normalizeClassName(name); 834 if (ObjectHelper.isNotEmpty(name)) { 835 if (LOG.isTraceEnabled()) { 836 LOG.trace("Using package: " + name + " to scan for RouteBuilder classes"); 837 } 838 packages.add(name); 839 } 840 } 841 return packages.toArray(new String[packages.size()]); 842 } 843 844 }