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