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