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.CamelContext; 031 import org.apache.camel.RoutesBuilder; 032 import org.apache.camel.ShutdownRoute; 033 import org.apache.camel.ShutdownRunningTask; 034 import org.apache.camel.builder.RouteBuilder; 035 import org.apache.camel.component.properties.PropertiesComponent; 036 import org.apache.camel.core.xml.AbstractCamelContextFactoryBean; 037 import org.apache.camel.core.xml.CamelJMXAgentDefinition; 038 import org.apache.camel.core.xml.CamelPropertyPlaceholderDefinition; 039 import org.apache.camel.core.xml.CamelProxyFactoryDefinition; 040 import org.apache.camel.core.xml.CamelServiceExporterDefinition; 041 import org.apache.camel.model.ContextScanDefinition; 042 import org.apache.camel.model.InterceptDefinition; 043 import org.apache.camel.model.InterceptFromDefinition; 044 import org.apache.camel.model.InterceptSendToEndpointDefinition; 045 import org.apache.camel.model.OnCompletionDefinition; 046 import org.apache.camel.model.OnExceptionDefinition; 047 import org.apache.camel.model.PackageScanDefinition; 048 import org.apache.camel.model.RouteBuilderDefinition; 049 import org.apache.camel.model.RouteContextRefDefinition; 050 import org.apache.camel.model.RouteDefinition; 051 import org.apache.camel.model.ThreadPoolProfileDefinition; 052 import org.apache.camel.model.config.PropertiesDefinition; 053 import org.apache.camel.model.dataformat.DataFormatsDefinition; 054 import org.apache.camel.spi.PackageScanFilter; 055 import org.apache.camel.spi.Registry; 056 import org.apache.camel.spring.spi.BridgePropertyPlaceholderConfigurer; 057 import org.slf4j.Logger; 058 import org.slf4j.LoggerFactory; 059 import org.springframework.beans.factory.DisposableBean; 060 import org.springframework.beans.factory.FactoryBean; 061 import org.springframework.beans.factory.InitializingBean; 062 import org.springframework.beans.factory.config.BeanPostProcessor; 063 import org.springframework.context.ApplicationContext; 064 import org.springframework.context.ApplicationContextAware; 065 import org.springframework.context.ApplicationEvent; 066 import org.springframework.context.ApplicationListener; 067 import org.springframework.context.event.ContextRefreshedEvent; 068 069 import static org.apache.camel.util.ObjectHelper.wrapRuntimeCamelException; 070 071 /** 072 * A Spring {@link FactoryBean} to create and initialize a 073 * {@link SpringCamelContext} and install routes either explicitly configured in 074 * Spring XML or found by searching the classpath for Java classes which extend 075 * {@link RouteBuilder} using the nested {@link #setPackages(String[])}. 076 * 077 * @version 078 */ 079 @XmlRootElement(name = "camelContext") 080 @XmlAccessorType(XmlAccessType.FIELD) 081 @SuppressWarnings("unused") 082 public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<SpringCamelContext> 083 implements FactoryBean<SpringCamelContext>, InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener<ApplicationEvent> { 084 private static final Logger LOG = LoggerFactory.getLogger(CamelContextFactoryBean.class); 085 086 @XmlAttribute(name = "depends-on", required = false) 087 private String dependsOn; 088 @XmlAttribute(required = false) 089 private String trace; 090 @XmlAttribute(required = false) 091 private String streamCache; 092 @XmlAttribute(required = false) 093 private String delayer; 094 @XmlAttribute(required = false) 095 private String handleFault; 096 @XmlAttribute(required = false) 097 private String errorHandlerRef; 098 @XmlAttribute(required = false) 099 private String autoStartup; 100 @XmlAttribute(required = false) 101 private String useMDCLogging; 102 @XmlAttribute(required = false) 103 private String useBreadcrumb; 104 @XmlAttribute(required = false) 105 private String managementNamePattern; 106 @XmlAttribute(required = false) 107 private ShutdownRoute shutdownRoute; 108 @XmlAttribute(required = false) 109 private ShutdownRunningTask shutdownRunningTask; 110 @XmlAttribute(required = false) 111 @Deprecated 112 private Boolean lazyLoadTypeConverters; 113 @XmlElement(name = "properties", required = false) 114 private PropertiesDefinition properties; 115 @XmlElement(name = "propertyPlaceholder", type = CamelPropertyPlaceholderDefinition.class, required = false) 116 private CamelPropertyPlaceholderDefinition camelPropertyPlaceholder; 117 @XmlElement(name = "package", required = false) 118 private String[] packages = {}; 119 @XmlElement(name = "packageScan", type = PackageScanDefinition.class, required = false) 120 private PackageScanDefinition packageScan; 121 @XmlElement(name = "contextScan", type = ContextScanDefinition.class, required = false) 122 private ContextScanDefinition contextScan; 123 @XmlElement(name = "jmxAgent", type = CamelJMXAgentDefinition.class, required = false) 124 private CamelJMXAgentDefinition camelJMXAgent; 125 @XmlElements({ 126 @XmlElement(name = "template", type = CamelProducerTemplateFactoryBean.class, required = false), 127 @XmlElement(name = "consumerTemplate", type = CamelConsumerTemplateFactoryBean.class, required = false), 128 @XmlElement(name = "proxy", type = CamelProxyFactoryDefinition.class, required = false), 129 @XmlElement(name = "export", type = CamelServiceExporterDefinition.class, required = false), 130 @XmlElement(name = "errorHandler", type = ErrorHandlerDefinition.class, required = false)}) 131 private List<?> beans; 132 @XmlElement(name = "routeBuilder", required = false) 133 private List<RouteBuilderDefinition> builderRefs = new ArrayList<RouteBuilderDefinition>(); 134 @XmlElement(name = "routeContextRef", required = false) 135 private List<RouteContextRefDefinition> routeRefs = new ArrayList<RouteContextRefDefinition>(); 136 @XmlElement(name = "threadPoolProfile", required = false) 137 private List<ThreadPoolProfileDefinition> threadPoolProfiles; 138 @XmlElement(name = "threadPool", required = false) 139 private List<CamelThreadPoolFactoryBean> threadPools; 140 @XmlElement(name = "endpoint", required = false) 141 private List<CamelEndpointFactoryBean> endpoints; 142 @XmlElement(name = "dataFormats", required = false) 143 private DataFormatsDefinition dataFormats; 144 @XmlElement(name = "redeliveryPolicyProfile", required = false) 145 private List<CamelRedeliveryPolicyFactoryBean> redeliveryPolicies; 146 @XmlElement(name = "onException", required = false) 147 private List<OnExceptionDefinition> onExceptions = new ArrayList<OnExceptionDefinition>(); 148 @XmlElement(name = "onCompletion", required = false) 149 private List<OnCompletionDefinition> onCompletions = new ArrayList<OnCompletionDefinition>(); 150 @XmlElement(name = "intercept", required = false) 151 private List<InterceptDefinition> intercepts = new ArrayList<InterceptDefinition>(); 152 @XmlElement(name = "interceptFrom", required = false) 153 private List<InterceptFromDefinition> interceptFroms = new ArrayList<InterceptFromDefinition>(); 154 @XmlElement(name = "interceptSendToEndpoint", required = false) 155 private List<InterceptSendToEndpointDefinition> interceptSendToEndpoints = new ArrayList<InterceptSendToEndpointDefinition>(); 156 @XmlElement(name = "route", required = false) 157 private List<RouteDefinition> routes = new ArrayList<RouteDefinition>(); 158 @XmlTransient 159 private SpringCamelContext context; 160 @XmlTransient 161 private ClassLoader contextClassLoaderOnStart; 162 @XmlTransient 163 private ApplicationContext applicationContext; 164 @XmlTransient 165 private BeanPostProcessor beanPostProcessor; 166 @XmlTransient 167 private boolean implicitId; 168 169 170 @Override 171 public Class<SpringCamelContext> getObjectType() { 172 return SpringCamelContext.class; 173 } 174 175 protected <S> S getBeanForType(Class<S> clazz) { 176 S bean = null; 177 String[] names = getApplicationContext().getBeanNamesForType(clazz, true, true); 178 if (names.length == 1) { 179 bean = getApplicationContext().getBean(names[0], clazz); 180 } 181 if (bean == null) { 182 ApplicationContext parentContext = getApplicationContext().getParent(); 183 if (parentContext != null) { 184 names = parentContext.getBeanNamesForType(clazz, true, true); 185 if (names.length == 1) { 186 bean = parentContext.getBean(names[0], clazz); 187 } 188 } 189 } 190 return bean; 191 } 192 193 @Override 194 protected void findRouteBuildersByPackageScan(String[] packages, PackageScanFilter filter, List<RoutesBuilder> builders) throws Exception { 195 // add filter to class resolver which then will filter 196 getContext().getPackageScanClassResolver().addFilter(filter); 197 198 PackageScanRouteBuilderFinder finder = new PackageScanRouteBuilderFinder(getContext(), packages, getContextClassLoaderOnStart(), 199 getBeanPostProcessor(), getContext().getPackageScanClassResolver()); 200 finder.appendBuilders(builders); 201 202 // and remove the filter 203 getContext().getPackageScanClassResolver().removeFilter(filter); 204 } 205 206 @Override 207 protected void findRouteBuildersByContextScan(PackageScanFilter filter, List<RoutesBuilder> builders) throws Exception { 208 ContextScanRouteBuilderFinder finder = new ContextScanRouteBuilderFinder(getContext(), filter); 209 finder.appendBuilders(builders); 210 } 211 212 protected void initBeanPostProcessor(SpringCamelContext context) { 213 if (beanPostProcessor != null) { 214 if (beanPostProcessor instanceof ApplicationContextAware) { 215 ((ApplicationContextAware) beanPostProcessor).setApplicationContext(applicationContext); 216 } 217 if (beanPostProcessor instanceof CamelBeanPostProcessor) { 218 ((CamelBeanPostProcessor) beanPostProcessor).setCamelContext(getContext()); 219 } 220 } 221 } 222 223 protected void postProcessBeforeInit(RouteBuilder builder) { 224 if (beanPostProcessor != null) { 225 // Inject the annotated resource 226 beanPostProcessor.postProcessBeforeInitialization(builder, builder.toString()); 227 } 228 } 229 230 protected void initCustomRegistry(SpringCamelContext context) { 231 Registry registry = getBeanForType(Registry.class); 232 if (registry != null) { 233 LOG.info("Using custom Registry: " + registry); 234 context.setRegistry(registry); 235 } 236 } 237 238 @Override 239 protected void initPropertyPlaceholder() throws Exception { 240 super.initPropertyPlaceholder(); 241 242 Map<String, BridgePropertyPlaceholderConfigurer> beans = applicationContext.getBeansOfType(BridgePropertyPlaceholderConfigurer.class); 243 if (beans.size() == 1) { 244 // setup properties component that uses this beans 245 BridgePropertyPlaceholderConfigurer configurer = beans.values().iterator().next(); 246 String id = beans.keySet().iterator().next(); 247 LOG.info("Bridging Camel and Spring property placeholder configurer with id: " + id); 248 249 // get properties component 250 PropertiesComponent pc = getContext().getComponent("properties", PropertiesComponent.class); 251 // replace existing resolver with us 252 configurer.setResolver(pc.getPropertiesResolver()); 253 configurer.setParser(pc.getPropertiesParser()); 254 String ref = "ref:" + id; 255 // use the bridge to handle the resolve and parsing 256 pc.setPropertiesResolver(configurer); 257 pc.setPropertiesParser(configurer); 258 // and update locations to have our as ref first 259 String[] locations = pc.getLocations(); 260 String[] updatedLocations; 261 if (locations != null && locations.length > 0) { 262 updatedLocations = new String[locations.length + 1]; 263 updatedLocations[0] = ref; 264 System.arraycopy(locations, 0, updatedLocations, 1, locations.length); 265 } else { 266 updatedLocations = new String[]{ref}; 267 } 268 pc.setLocations(updatedLocations); 269 } else if (beans.size() > 1) { 270 LOG.warn("Cannot bridge Camel and Spring property placeholders, as exact only 1 bean of type BridgePropertyPlaceholderConfigurer" 271 + " must be defined, was {} beans defined.", beans.size()); 272 } 273 } 274 275 public void onApplicationEvent(ApplicationEvent event) { 276 // From Spring 3.0.1, The BeanFactory applicationEventListener 277 // and Bean's applicationEventListener will be called, 278 // So we just delegate the onApplicationEvent call here. 279 280 SpringCamelContext context = getContext(false); 281 if (context != null) { 282 // let the spring camel context handle the events 283 context.onApplicationEvent(event); 284 } else { 285 LOG.debug("Publishing spring-event: {}", event); 286 287 if (event instanceof ContextRefreshedEvent) { 288 // now lets start the CamelContext so that all its possible 289 // dependencies are initialized 290 try { 291 LOG.trace("Starting the context now"); 292 getContext().start(); 293 } catch (Exception e) { 294 throw wrapRuntimeCamelException(e); 295 } 296 } 297 } 298 } 299 300 // Properties 301 // ------------------------------------------------------------------------- 302 303 public ApplicationContext getApplicationContext() { 304 if (applicationContext == null) { 305 throw new IllegalArgumentException("No applicationContext has been injected!"); 306 } 307 return applicationContext; 308 } 309 310 public void setApplicationContext(ApplicationContext applicationContext) { 311 this.applicationContext = applicationContext; 312 } 313 314 public void setBeanPostProcessor(BeanPostProcessor postProcessor) { 315 this.beanPostProcessor = postProcessor; 316 } 317 318 public BeanPostProcessor getBeanPostProcessor() { 319 return beanPostProcessor; 320 } 321 322 // Implementation methods 323 // ------------------------------------------------------------------------- 324 325 /** 326 * Create the context 327 */ 328 protected SpringCamelContext createContext() { 329 SpringCamelContext ctx = newCamelContext(); 330 ctx.setName(getId()); 331 return ctx; 332 } 333 334 protected SpringCamelContext newCamelContext() { 335 return new SpringCamelContext(getApplicationContext()); 336 } 337 338 public SpringCamelContext getContext(boolean create) { 339 if (context == null && create) { 340 context = createContext(); 341 } 342 return context; 343 } 344 345 public void setContext(SpringCamelContext context) { 346 this.context = context; 347 } 348 349 public List<RouteDefinition> getRoutes() { 350 return routes; 351 } 352 353 public void setRoutes(List<RouteDefinition> routes) { 354 this.routes = routes; 355 } 356 357 public List<CamelEndpointFactoryBean> getEndpoints() { 358 return endpoints; 359 } 360 361 public List<CamelRedeliveryPolicyFactoryBean> getRedeliveryPolicies() { 362 return redeliveryPolicies; 363 } 364 365 public List<InterceptDefinition> getIntercepts() { 366 return intercepts; 367 } 368 369 public void setIntercepts(List<InterceptDefinition> intercepts) { 370 this.intercepts = intercepts; 371 } 372 373 public List<InterceptFromDefinition> getInterceptFroms() { 374 return interceptFroms; 375 } 376 377 public void setInterceptFroms(List<InterceptFromDefinition> interceptFroms) { 378 this.interceptFroms = interceptFroms; 379 } 380 381 public List<InterceptSendToEndpointDefinition> getInterceptSendToEndpoints() { 382 return interceptSendToEndpoints; 383 } 384 385 public void setInterceptSendToEndpoints(List<InterceptSendToEndpointDefinition> interceptSendToEndpoints) { 386 this.interceptSendToEndpoints = interceptSendToEndpoints; 387 } 388 389 public PropertiesDefinition getProperties() { 390 return properties; 391 } 392 393 public void setProperties(PropertiesDefinition properties) { 394 this.properties = properties; 395 } 396 397 public String[] getPackages() { 398 return packages; 399 } 400 401 /** 402 * Sets the package names to be recursively searched for Java classes which 403 * extend {@link org.apache.camel.builder.RouteBuilder} to be auto-wired up to the 404 * {@link CamelContext} as a route. Note that classes are excluded if 405 * they are specifically configured in the spring.xml 406 * <p/> 407 * A more advanced configuration can be done using {@link #setPackageScan(org.apache.camel.model.PackageScanDefinition)} 408 * 409 * @param packages the package names which are recursively searched 410 * @see #setPackageScan(org.apache.camel.model.PackageScanDefinition) 411 */ 412 public void setPackages(String[] packages) { 413 this.packages = packages; 414 } 415 416 public PackageScanDefinition getPackageScan() { 417 return packageScan; 418 } 419 420 /** 421 * Sets the package scanning information. Package scanning allows for the 422 * automatic discovery of certain camel classes at runtime for inclusion 423 * e.g. {@link org.apache.camel.builder.RouteBuilder} implementations 424 * 425 * @param packageScan the package scan 426 */ 427 public void setPackageScan(PackageScanDefinition packageScan) { 428 this.packageScan = packageScan; 429 } 430 431 public ContextScanDefinition getContextScan() { 432 return contextScan; 433 } 434 435 /** 436 * Sets the context scanning (eg Spring's ApplicationContext) information. 437 * Context scanning allows for the automatic discovery of Camel routes runtime for inclusion 438 * e.g. {@link org.apache.camel.builder.RouteBuilder} implementations 439 * 440 * @param contextScan the context scan 441 */ 442 public void setContextScan(ContextScanDefinition contextScan) { 443 this.contextScan = contextScan; 444 } 445 446 public CamelPropertyPlaceholderDefinition getCamelPropertyPlaceholder() { 447 return camelPropertyPlaceholder; 448 } 449 450 public void setCamelPropertyPlaceholder(CamelPropertyPlaceholderDefinition camelPropertyPlaceholder) { 451 this.camelPropertyPlaceholder = camelPropertyPlaceholder; 452 } 453 454 public void setCamelJMXAgent(CamelJMXAgentDefinition agent) { 455 camelJMXAgent = agent; 456 } 457 458 public String getTrace() { 459 return trace; 460 } 461 462 public void setTrace(String trace) { 463 this.trace = trace; 464 } 465 466 public String getStreamCache() { 467 return streamCache; 468 } 469 470 public void setStreamCache(String streamCache) { 471 this.streamCache = streamCache; 472 } 473 474 public String getDelayer() { 475 return delayer; 476 } 477 478 public void setDelayer(String delayer) { 479 this.delayer = delayer; 480 } 481 482 public String getHandleFault() { 483 return handleFault; 484 } 485 486 public void setHandleFault(String handleFault) { 487 this.handleFault = handleFault; 488 } 489 490 public String getAutoStartup() { 491 return autoStartup; 492 } 493 494 public void setAutoStartup(String autoStartup) { 495 this.autoStartup = autoStartup; 496 } 497 498 public String getUseMDCLogging() { 499 return useMDCLogging; 500 } 501 502 public void setUseMDCLogging(String useMDCLogging) { 503 this.useMDCLogging = useMDCLogging; 504 } 505 506 public String getUseBreadcrumb() { 507 return useBreadcrumb; 508 } 509 510 public void setUseBreadcrumb(String useBreadcrumb) { 511 this.useBreadcrumb = useBreadcrumb; 512 } 513 514 public String getManagementNamePattern() { 515 return managementNamePattern; 516 } 517 518 public void setManagementNamePattern(String managementNamePattern) { 519 this.managementNamePattern = managementNamePattern; 520 } 521 522 @Deprecated 523 public Boolean getLazyLoadTypeConverters() { 524 return lazyLoadTypeConverters; 525 } 526 527 @Deprecated 528 public void setLazyLoadTypeConverters(Boolean lazyLoadTypeConverters) { 529 this.lazyLoadTypeConverters = lazyLoadTypeConverters; 530 } 531 532 public CamelJMXAgentDefinition getCamelJMXAgent() { 533 return camelJMXAgent; 534 } 535 536 public List<RouteBuilderDefinition> getBuilderRefs() { 537 return builderRefs; 538 } 539 540 public void setBuilderRefs(List<RouteBuilderDefinition> builderRefs) { 541 this.builderRefs = builderRefs; 542 } 543 544 public List<RouteContextRefDefinition> getRouteRefs() { 545 return routeRefs; 546 } 547 548 public void setRouteRefs(List<RouteContextRefDefinition> routeRefs) { 549 this.routeRefs = routeRefs; 550 } 551 552 public String getErrorHandlerRef() { 553 return errorHandlerRef; 554 } 555 556 /** 557 * Sets the name of the error handler object used to default the error handling strategy 558 * 559 * @param errorHandlerRef the Spring bean ref of the error handler 560 */ 561 public void setErrorHandlerRef(String errorHandlerRef) { 562 this.errorHandlerRef = errorHandlerRef; 563 } 564 565 public void setDataFormats(DataFormatsDefinition dataFormats) { 566 this.dataFormats = dataFormats; 567 } 568 569 public DataFormatsDefinition getDataFormats() { 570 return dataFormats; 571 } 572 573 public void setOnExceptions(List<OnExceptionDefinition> onExceptions) { 574 this.onExceptions = onExceptions; 575 } 576 577 public List<OnExceptionDefinition> getOnExceptions() { 578 return onExceptions; 579 } 580 581 public List<OnCompletionDefinition> getOnCompletions() { 582 return onCompletions; 583 } 584 585 public void setOnCompletions(List<OnCompletionDefinition> onCompletions) { 586 this.onCompletions = onCompletions; 587 } 588 589 public ShutdownRoute getShutdownRoute() { 590 return shutdownRoute; 591 } 592 593 public void setShutdownRoute(ShutdownRoute shutdownRoute) { 594 this.shutdownRoute = shutdownRoute; 595 } 596 597 public ShutdownRunningTask getShutdownRunningTask() { 598 return shutdownRunningTask; 599 } 600 601 public void setShutdownRunningTask(ShutdownRunningTask shutdownRunningTask) { 602 this.shutdownRunningTask = shutdownRunningTask; 603 } 604 605 public List<ThreadPoolProfileDefinition> getThreadPoolProfiles() { 606 return threadPoolProfiles; 607 } 608 609 public void setThreadPoolProfiles(List<ThreadPoolProfileDefinition> threadPoolProfiles) { 610 this.threadPoolProfiles = threadPoolProfiles; 611 } 612 613 public String getDependsOn() { 614 return dependsOn; 615 } 616 617 public void setDependsOn(String dependsOn) { 618 this.dependsOn = dependsOn; 619 } 620 621 public boolean isImplicitId() { 622 return implicitId; 623 } 624 625 public void setImplicitId(boolean flag) { 626 implicitId = flag; 627 } 628 629 }