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: 1025866 $
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 = "false";
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 = "true";
099 @XmlAttribute(required = false)
100 private ShutdownRoute shutdownRoute;
101 @XmlAttribute(required = false)
102 private ShutdownRunningTask shutdownRunningTask;
103 @XmlAttribute(required = false)
104 private Boolean lazyLoadTypeConverters = Boolean.FALSE;
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 }