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