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