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