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.CamelException;
031 import org.apache.camel.RoutesBuilder;
032 import org.apache.camel.builder.ErrorHandlerBuilder;
033 import org.apache.camel.builder.RouteBuilder;
034 import org.apache.camel.impl.DefaultLifecycleStrategy;
035 import org.apache.camel.impl.scan.PatternBasedPackageScanFilter;
036 import org.apache.camel.management.DefaultInstrumentationAgent;
037 import org.apache.camel.management.InstrumentationLifecycleStrategy;
038 import org.apache.camel.model.FromDefinition;
039 import org.apache.camel.model.IdentifiedType;
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.PolicyDefinition;
047 import org.apache.camel.model.ProcessorDefinition;
048 import org.apache.camel.model.RouteBuilderDefinition;
049 import org.apache.camel.model.RouteContainer;
050 import org.apache.camel.model.RouteDefinition;
051 import org.apache.camel.model.TransactedDefinition;
052 import org.apache.camel.model.config.PropertiesDefinition;
053 import org.apache.camel.model.dataformat.DataFormatsDefinition;
054 import org.apache.camel.processor.interceptor.Delayer;
055 import org.apache.camel.processor.interceptor.HandleFault;
056 import org.apache.camel.processor.interceptor.TraceFormatter;
057 import org.apache.camel.processor.interceptor.Tracer;
058 import org.apache.camel.spi.ClassResolver;
059 import org.apache.camel.spi.FactoryFinderResolver;
060 import org.apache.camel.spi.InterceptStrategy;
061 import org.apache.camel.spi.LifecycleStrategy;
062 import org.apache.camel.spi.PackageScanClassResolver;
063 import org.apache.camel.spi.Registry;
064 import org.apache.camel.util.EndpointHelper;
065 import org.apache.camel.util.ObjectHelper;
066 import org.apache.commons.logging.Log;
067 import org.apache.commons.logging.LogFactory;
068 import org.springframework.beans.factory.DisposableBean;
069 import org.springframework.beans.factory.FactoryBean;
070 import org.springframework.beans.factory.InitializingBean;
071 import org.springframework.beans.factory.config.BeanPostProcessor;
072 import org.springframework.context.ApplicationContext;
073 import org.springframework.context.ApplicationContextAware;
074 import org.springframework.context.ApplicationEvent;
075 import org.springframework.context.ApplicationListener;
076 import org.springframework.context.event.ContextRefreshedEvent;
077 import static org.apache.camel.util.ObjectHelper.wrapRuntimeCamelException;
078
079 /**
080 * A Spring {@link FactoryBean} to create and initialize a
081 * {@link SpringCamelContext} and install routes either explicitly configured in
082 * Spring XML or found by searching the classpath for Java classes which extend
083 * {@link RouteBuilder} using the nested {@link #setPackages(String[])}.
084 *
085 * @version $Revision: 792468 $
086 */
087 @XmlRootElement(name = "camelContext")
088 @XmlAccessorType(XmlAccessType.FIELD)
089 public class CamelContextFactoryBean extends IdentifiedType implements RouteContainer, FactoryBean, InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener {
090 private static final Log LOG = LogFactory.getLog(CamelContextFactoryBean.class);
091
092 @XmlAttribute(required = false)
093 private Boolean trace;
094 @XmlAttribute(required = false)
095 private Boolean streamCache = Boolean.TRUE;
096 @XmlAttribute(required = false)
097 private Long delay;
098 @XmlAttribute(required = false)
099 private Boolean handleFault;
100 @XmlAttribute(required = false)
101 private String errorHandlerRef;
102 @XmlAttribute(required = false)
103 private Boolean shouldStartContext = Boolean.TRUE;
104 @XmlElement(name = "properties", required = false)
105 private PropertiesDefinition properties;
106 @XmlElement(name = "package", required = false)
107 private String[] packages = {};
108 @XmlElement(name = "packageScan", type = PackageScanDefinition.class, required = false)
109 private PackageScanDefinition packageScan;
110 @XmlElement(name = "jmxAgent", type = CamelJMXAgentDefinition.class, required = false)
111 private CamelJMXAgentDefinition camelJMXAgent;
112 @XmlElements({
113 @XmlElement(name = "beanPostProcessor", type = CamelBeanPostProcessor.class, required = false),
114 @XmlElement(name = "template", type = CamelProducerTemplateFactoryBean.class, required = false),
115 @XmlElement(name = "consumerTemplate", type = CamelConsumerTemplateFactoryBean.class, required = false),
116 @XmlElement(name = "proxy", type = CamelProxyFactoryDefinition.class, required = false),
117 @XmlElement(name = "export", type = CamelServiceExporterDefinition.class, required = false)})
118 private List beans;
119 @XmlElement(name = "routeBuilder", required = false)
120 private List<RouteBuilderDefinition> builderRefs = new ArrayList<RouteBuilderDefinition>();
121 @XmlElement(name = "endpoint", required = false)
122 private List<CamelEndpointFactoryBean> endpoints;
123 @XmlElement(name = "dataFormats", required = false)
124 private DataFormatsDefinition dataFormats;
125 @XmlElement(name = "onException", required = false)
126 private List<OnExceptionDefinition> onExceptions = new ArrayList<OnExceptionDefinition>();
127 @XmlElement(name = "onCompletion", required = false)
128 private List<OnCompletionDefinition> onCompletions = new ArrayList<OnCompletionDefinition>();
129 @XmlElement(name = "intercept", required = false)
130 private List<InterceptDefinition> intercepts = new ArrayList<InterceptDefinition>();
131 @XmlElement(name = "interceptFrom", required = false)
132 private List<InterceptFromDefinition> interceptFroms = new ArrayList<InterceptFromDefinition>();
133 @XmlElement(name = "interceptSendToEndpoint", required = false)
134 private List<InterceptSendToEndpointDefinition> interceptSendToEndpoints = new ArrayList<InterceptSendToEndpointDefinition>();
135 @XmlElement(name = "route", required = false)
136 private List<RouteDefinition> routes = new ArrayList<RouteDefinition>();
137 @XmlTransient
138 private SpringCamelContext context;
139 @XmlTransient
140 private RouteBuilder routeBuilder;
141 @XmlTransient
142 private List<RoutesBuilder> additionalBuilders = new ArrayList<RoutesBuilder>();
143 @XmlTransient
144 private ApplicationContext applicationContext;
145 @XmlTransient
146 private ClassLoader contextClassLoaderOnStart;
147 @XmlTransient
148 private BeanPostProcessor beanPostProcessor;
149
150 public CamelContextFactoryBean() {
151 // Lets keep track of the class loader for when we actually do start things up
152 contextClassLoaderOnStart = Thread.currentThread().getContextClassLoader();
153 }
154
155 public Object getObject() throws Exception {
156 return getContext();
157 }
158
159 public Class getObjectType() {
160 return SpringCamelContext.class;
161 }
162
163 public boolean isSingleton() {
164 return true;
165 }
166
167 public ClassLoader getContextClassLoaderOnStart() {
168 return contextClassLoaderOnStart;
169 }
170
171 public List<RoutesBuilder> getAdditionalBuilders() {
172 return additionalBuilders;
173 }
174
175 public void afterPropertiesSet() throws Exception {
176 if (properties != null) {
177 getContext().setProperties(properties.asMap());
178 }
179
180 // set the resolvers first
181 PackageScanClassResolver packageResolver = getBeanForType(PackageScanClassResolver.class);
182 if (packageResolver != null) {
183 LOG.info("Using custom PackageScanClassResolver: " + packageResolver);
184 getContext().setPackageScanClassResolver(packageResolver);
185 }
186 ClassResolver classResolver = getBeanForType(ClassResolver.class);
187 if (classResolver != null) {
188 LOG.info("Using custom ClassResolver: " + classResolver);
189 getContext().setClassResolver(classResolver);
190 }
191 FactoryFinderResolver factoryFinderResolver = getBeanForType(FactoryFinderResolver.class);
192 if (factoryFinderResolver != null) {
193 LOG.info("Using custom FactoryFinderResolver: " + factoryFinderResolver);
194 getContext().setFactoryFinderResolver(factoryFinderResolver);
195 }
196
197 // set the lifecycle strategy if defined
198 LifecycleStrategy lifecycleStrategy = getBeanForType(LifecycleStrategy.class);
199 if (lifecycleStrategy != null) {
200 LOG.info("Using custom LifecycleStrategy: " + lifecycleStrategy);
201 getContext().setLifecycleStrategy(lifecycleStrategy);
202 }
203
204 // set the strategy if defined
205 Registry registry = getBeanForType(Registry.class);
206 if (registry != null) {
207 LOG.info("Using custom Registry: " + registry);
208 getContext().setRegistry(registry);
209 }
210
211 Tracer tracer = getBeanForType(Tracer.class);
212 if (tracer != null) {
213 // use formatter if there is a TraceFormatter bean defined
214 TraceFormatter formatter = getBeanForType(TraceFormatter.class);
215 if (formatter != null) {
216 tracer.setFormatter(formatter);
217 }
218 LOG.info("Using custom Tracer: " + tracer);
219 getContext().addInterceptStrategy(tracer);
220 }
221
222 HandleFault handleFault = getBeanForType(HandleFault.class);
223 if (handleFault != null) {
224 LOG.info("Using custom HandleFault: " + handleFault);
225 getContext().addInterceptStrategy(handleFault);
226 }
227
228 Delayer delayer = getBeanForType(Delayer.class);
229 if (delayer != null) {
230 LOG.info("Using custom Delayer: " + delayer);
231 getContext().addInterceptStrategy(delayer);
232 }
233
234 // add global interceptors
235 Map<String, InterceptStrategy> strategies = getContext().getRegistry().lookupByType(InterceptStrategy.class);
236 if (strategies != null && !strategies.isEmpty()) {
237 for (String id : strategies.keySet()) {
238 InterceptStrategy strategy = strategies.get(id);
239 // do not add if already added, for instance a tracer that is also an InterceptStrategy class
240 if (!getContext().getInterceptStrategies().contains(strategy)) {
241 LOG.info("Using custom intercept strategy with id: " + id + " and implementation: " + strategy);
242 getContext().addInterceptStrategy(strategy);
243 }
244 }
245 }
246
247 // Set the application context and camelContext for the beanPostProcessor
248 if (beanPostProcessor != null) {
249 if (beanPostProcessor instanceof ApplicationContextAware) {
250 ((ApplicationContextAware)beanPostProcessor).setApplicationContext(applicationContext);
251 }
252 if (beanPostProcessor instanceof CamelBeanPostProcessor) {
253 ((CamelBeanPostProcessor)beanPostProcessor).setCamelContext(getContext());
254 }
255 }
256
257 // do special preparation for some concepts such as interceptors and policies
258 // this is needed as JAXB does not build excaclty the same model definition as Spring DSL would do
259 // using route builders. So we have here a little custom code to fix the JAXB gaps
260 for (RouteDefinition route : routes) {
261 // interceptors should be first
262 initInterceptors(route);
263 // then on completion
264 initOnCompletions(route);
265 // then polices
266 initPolicies(route);
267 // and last on exception
268 initOnExceptions(route);
269 }
270
271 if (dataFormats != null) {
272 getContext().setDataFormats(dataFormats.asMap());
273 }
274
275 // lets force any lazy creation
276 getContext().addRouteDefinitions(routes);
277
278 // setup JMX agent
279 initJMXAgent();
280
281 if (LOG.isDebugEnabled()) {
282 LOG.debug("Found JAXB created routes: " + getRoutes());
283 }
284 findRouteBuilders();
285 installRoutes();
286 }
287
288 private void initOnExceptions(RouteDefinition route) {
289 List<ProcessorDefinition<?>> outputs = new ArrayList<ProcessorDefinition<?>>();
290 List<ProcessorDefinition<?>> exceptionHandlers = new ArrayList<ProcessorDefinition<?>>();
291
292 // add global on exceptions if any
293 if (onExceptions != null && !onExceptions.isEmpty()) {
294 // on exceptions must be added at top, so the route flow is correct as
295 // on exceptions should be the first outputs
296 route.getOutputs().addAll(0, onExceptions);
297 }
298
299 for (ProcessorDefinition output : route.getOutputs()) {
300 // split into on exception and regular outputs
301 if (output instanceof OnExceptionDefinition) {
302 exceptionHandlers.add(output);
303 } else {
304 outputs.add(output);
305 }
306 }
307
308 // clearing the outputs
309 route.clearOutput();
310
311 // add exception handlers as top children
312 route.getOutputs().addAll(exceptionHandlers);
313
314 // and the remaining outputs
315 route.getOutputs().addAll(outputs);
316 }
317
318 private void initInterceptors(RouteDefinition route) {
319
320 // configure intercept
321 for (InterceptDefinition intercept : getIntercepts()) {
322 intercept.afterPropertiesSet();
323 // add as first output so intercept is handled before the acutal route and that gives
324 // us the needed head start to init and be able to intercept all the remaining processing steps
325 route.getOutputs().add(0, intercept);
326 }
327
328 // configure intercept from
329 for (InterceptFromDefinition intercept : getInterceptFroms()) {
330
331 // should we only apply interceptor for a given endpoint uri
332 boolean match = true;
333 if (intercept.getUri() != null) {
334 match = false;
335 for (FromDefinition input : route.getInputs()) {
336 if (EndpointHelper.matchEndpoint(input.getUri(), intercept.getUri())) {
337 match = true;
338 break;
339 }
340 }
341 }
342
343 if (match) {
344 intercept.afterPropertiesSet();
345 // add as first output so intercept is handled before the acutal route and that gives
346 // us the needed head start to init and be able to intercept all the remaining processing steps
347 route.getOutputs().add(0, intercept);
348 }
349 }
350
351 // configure intercept send to endpoint
352 for (InterceptSendToEndpointDefinition intercept : getInterceptSendToEndpoints()) {
353 intercept.afterPropertiesSet();
354 // add as first output so intercept is handled before the acutal route and that gives
355 // us the needed head start to init and be able to intercept all the remaining processing steps
356 route.getOutputs().add(0, intercept);
357 }
358
359 }
360
361 private void initOnCompletions(RouteDefinition route) {
362 // only add global onCompletion if there are no route alredy
363 boolean hasRouteScope = false;
364 for (ProcessorDefinition out : route.getOutputs()) {
365 if (out instanceof OnCompletionDefinition) {
366 hasRouteScope = true;
367 break;
368 }
369 }
370 // only add global onCompletion if we do *not* have any route onCompletion defined in the route
371 // add onCompletion *after* intercept, as its important intercept is first
372 if (!hasRouteScope) {
373 int index = 0;
374 for (int i = 0; i < route.getOutputs().size(); i++) {
375 index = i;
376 ProcessorDefinition out = route.getOutputs().get(i);
377 if (!(out instanceof InterceptDefinition)) {
378 break;
379 }
380 }
381 route.getOutputs().addAll(index, getOnCompletions());
382 }
383 }
384
385 private void initPolicies(RouteDefinition route) {
386 // setup the policies as JAXB yet again have not created a correct model for us
387 List<ProcessorDefinition> types = route.getOutputs();
388 // we need to types as transacted cannot extend policy due JAXB limitations
389 PolicyDefinition policy = null;
390 TransactedDefinition transacted = null;
391 for (ProcessorDefinition type : types) {
392 if (type instanceof PolicyDefinition) {
393 policy = (PolicyDefinition) type;
394 } else if (type instanceof TransactedDefinition) {
395 transacted = (TransactedDefinition) type;
396 } else if (policy != null) {
397 // the outputs should be moved to the policy
398 policy.addOutput(type);
399 } else if (transacted != null) {
400 // the outputs should be moved to the transacted policy
401 transacted.addOutput(type);
402 }
403 }
404 // did we find a policy if so replace it as the only output on the route
405 if (policy != null) {
406 route.clearOutput();
407 route.addOutput(policy);
408 } else if (transacted != null) {
409 route.clearOutput();
410 route.addOutput(transacted);
411 }
412 }
413
414 private void initJMXAgent() throws Exception {
415 if (camelJMXAgent != null && camelJMXAgent.isDisabled()) {
416 LOG.info("JMXAgent disabled");
417 getContext().setLifecycleStrategy(new DefaultLifecycleStrategy());
418 } else if (camelJMXAgent != null) {
419 DefaultInstrumentationAgent agent = new DefaultInstrumentationAgent();
420 agent.setConnectorPort(camelJMXAgent.getConnectorPort());
421 agent.setCreateConnector(camelJMXAgent.isCreateConnector());
422 agent.setMBeanObjectDomainName(camelJMXAgent.getMbeanObjectDomainName());
423 agent.setMBeanServerDefaultDomain(camelJMXAgent.getMbeanServerDefaultDomain());
424 agent.setRegistryPort(camelJMXAgent.getRegistryPort());
425 agent.setServiceUrlPath(camelJMXAgent.getServiceUrlPath());
426 agent.setUsePlatformMBeanServer(camelJMXAgent.isUsePlatformMBeanServer());
427 agent.setOnlyRegisterProcessorWithCustomId(camelJMXAgent.getOnlyRegisterProcessorWithCustomId());
428
429 LOG.info("JMXAgent enabled: " + camelJMXAgent);
430 getContext().setLifecycleStrategy(new InstrumentationLifecycleStrategy(agent));
431 }
432 }
433
434 @SuppressWarnings("unchecked")
435 private <T> T getBeanForType(Class<T> clazz) {
436 T bean = null;
437 String[] names = getApplicationContext().getBeanNamesForType(clazz, true, true);
438 if (names.length == 1) {
439 bean = (T) getApplicationContext().getBean(names[0], clazz);
440 }
441 if (bean == null) {
442 ApplicationContext parentContext = getApplicationContext().getParent();
443 if (parentContext != null) {
444 names = parentContext.getBeanNamesForType(clazz, true, true);
445 if (names.length == 1) {
446 bean = (T) parentContext.getBean(names[0], clazz);
447 }
448 }
449 }
450 return bean;
451
452 }
453
454 public void destroy() throws Exception {
455 getContext().stop();
456 }
457
458 public void onApplicationEvent(ApplicationEvent event) {
459 if (context != null) {
460 // let the spring camel context handle the events
461 context.onApplicationEvent(event);
462 } else {
463 if (LOG.isDebugEnabled()) {
464 LOG.debug("Publishing spring-event: " + event);
465 }
466
467 if (event instanceof ContextRefreshedEvent) {
468 // now lets start the CamelContext so that all its possible
469 // dependencies are initialized
470 try {
471 LOG.debug("Starting the context now!");
472 getContext().start();
473 } catch (Exception e) {
474 throw wrapRuntimeCamelException(e);
475 }
476 }
477 }
478 }
479
480 // Properties
481 // -------------------------------------------------------------------------
482 public SpringCamelContext getContext() throws Exception {
483 if (context == null) {
484 context = createContext();
485 }
486 return context;
487 }
488
489 public void setContext(SpringCamelContext context) {
490 this.context = context;
491 }
492
493 public List<RouteDefinition> getRoutes() {
494 return routes;
495 }
496
497 public void setRoutes(List<RouteDefinition> routes) {
498 this.routes = routes;
499 }
500
501 public List<InterceptDefinition> getIntercepts() {
502 return intercepts;
503 }
504
505 public void setIntercepts(List<InterceptDefinition> intercepts) {
506 this.intercepts = intercepts;
507 }
508
509 public List<InterceptFromDefinition> getInterceptFroms() {
510 return interceptFroms;
511 }
512
513 public void setInterceptFroms(List<InterceptFromDefinition> interceptFroms) {
514 this.interceptFroms = interceptFroms;
515 }
516
517 public List<InterceptSendToEndpointDefinition> getInterceptSendToEndpoints() {
518 return interceptSendToEndpoints;
519 }
520
521 public void setInterceptSendToEndpoints(List<InterceptSendToEndpointDefinition> interceptSendToEndpoints) {
522 this.interceptSendToEndpoints = interceptSendToEndpoints;
523 }
524
525 public RouteBuilder getRouteBuilder() {
526 return routeBuilder;
527 }
528
529 /**
530 * Set a single {@link RouteBuilder} to be used to create the default routes
531 * on startup
532 */
533 public void setRouteBuilder(RouteBuilder routeBuilder) {
534 this.routeBuilder = routeBuilder;
535 }
536
537 /**
538 * Set a collection of {@link RouteBuilder} instances to be used to create
539 * the default routes on startup
540 */
541 public void setRouteBuilders(RouteBuilder[] builders) {
542 for (RouteBuilder builder : builders) {
543 additionalBuilders.add(builder);
544 }
545 }
546
547 public ApplicationContext getApplicationContext() {
548 if (applicationContext == null) {
549 throw new IllegalArgumentException("No applicationContext has been injected!");
550 }
551 return applicationContext;
552 }
553
554 public void setApplicationContext(ApplicationContext applicationContext) {
555 this.applicationContext = applicationContext;
556 }
557
558 public PropertiesDefinition getProperties() {
559 return properties;
560 }
561
562 public void setProperties(PropertiesDefinition properties) {
563 this.properties = properties;
564 }
565
566 /**
567 * @deprecated replaced by {@link #getPackageScan()}
568 */
569 @Deprecated
570 public String[] getPackages() {
571 return packages;
572 }
573
574 /**
575 * Sets the package names to be recursively searched for Java classes which
576 * extend {@link RouteBuilder} to be auto-wired up to the
577 * {@link SpringCamelContext} as a route. Note that classes are excluded if
578 * they are specifically configured in the spring.xml
579 *
580 * @deprecated replaced by {@link #setPackageScan(org.apache.camel.model.PackageScanDefinition)}
581 * @param packages the package names which are recursively searched
582 */
583 @Deprecated
584 public void setPackages(String[] packages) {
585 this.packages = packages;
586 }
587
588 public PackageScanDefinition getPackageScan() {
589 return packageScan;
590 }
591
592 /**
593 * Sets the package scanning information. Package scanning allows for the
594 * automatic discovery of certain camel classes at runtime for inclusion
595 * e.g. {@link RouteBuilder} implementations
596 *
597 * @param packageScan the package scan
598 */
599 public void setPackageScan(PackageScanDefinition packageScan) {
600 this.packageScan = packageScan;
601 }
602
603 public void setBeanPostProcessor(BeanPostProcessor postProcessor) {
604 this.beanPostProcessor = postProcessor;
605 }
606
607 public BeanPostProcessor getBeanPostProcessor() {
608 return beanPostProcessor;
609 }
610
611 public void setCamelJMXAgent(CamelJMXAgentDefinition agent) {
612 camelJMXAgent = agent;
613 }
614
615 public Boolean getTrace() {
616 return trace;
617 }
618
619 public void setTrace(Boolean trace) {
620 this.trace = trace;
621 }
622
623 public Boolean getStreamCache() {
624 return streamCache;
625 }
626
627 public void setStreamCache(Boolean streamCache) {
628 this.streamCache = streamCache;
629 }
630
631 public Long getDelay() {
632 return delay;
633 }
634
635 public void setDelay(Long delay) {
636 this.delay = delay;
637 }
638
639 public Boolean getHandleFault() {
640 return handleFault;
641 }
642
643 public void setHandleFault(Boolean handleFault) {
644 this.handleFault = handleFault;
645 }
646
647 public CamelJMXAgentDefinition getCamelJMXAgent() {
648 return camelJMXAgent;
649 }
650
651 public List<RouteBuilderDefinition> getBuilderRefs() {
652 return builderRefs;
653 }
654
655 public void setBuilderRefs(List<RouteBuilderDefinition> builderRefs) {
656 this.builderRefs = builderRefs;
657 }
658
659 public String getErrorHandlerRef() {
660 return errorHandlerRef;
661 }
662
663 /**
664 * Sets the name of the error handler object used to default the error handling strategy
665 *
666 * @param errorHandlerRef the Spring bean ref of the error handler
667 */
668 public void setErrorHandlerRef(String errorHandlerRef) {
669 this.errorHandlerRef = errorHandlerRef;
670 }
671
672 public Boolean getShouldStartContext() {
673 return shouldStartContext;
674 }
675
676 public void setShouldStartContext(Boolean shouldStartContext) {
677 this.shouldStartContext = shouldStartContext;
678 }
679
680 public void setDataFormats(DataFormatsDefinition dataFormats) {
681 this.dataFormats = dataFormats;
682 }
683
684 public DataFormatsDefinition getDataFormats() {
685 return dataFormats;
686 }
687
688 public void setOnExceptions(List<OnExceptionDefinition> onExceptions) {
689 this.onExceptions = onExceptions;
690 }
691
692 public List<OnExceptionDefinition> getOnExceptions() {
693 return onExceptions;
694 }
695
696 public List<OnCompletionDefinition> getOnCompletions() {
697 return onCompletions;
698 }
699
700 public void setOnCompletions(List<OnCompletionDefinition> onCompletions) {
701 this.onCompletions = onCompletions;
702 }
703
704 // Implementation methods
705 // -------------------------------------------------------------------------
706
707 /**
708 * Create the context
709 */
710 protected SpringCamelContext createContext() {
711 SpringCamelContext ctx = new SpringCamelContext(getApplicationContext());
712 ctx.setName(getId());
713 if (streamCache != null) {
714 ctx.setStreamCaching(streamCache);
715 }
716 if (trace != null) {
717 ctx.setTrace(trace);
718 }
719 if (delay != null) {
720 ctx.setDelay(delay);
721 }
722 if (handleFault != null) {
723 ctx.setHandleFault(handleFault);
724 }
725 if (errorHandlerRef != null) {
726 ErrorHandlerBuilder errorHandlerBuilder = (ErrorHandlerBuilder) getApplicationContext().getBean(errorHandlerRef, ErrorHandlerBuilder.class);
727 if (errorHandlerBuilder == null) {
728 throw new IllegalArgumentException("Cannot find ErrorHandlerBuilder bean with id: " + errorHandlerRef);
729 }
730 ctx.setErrorHandlerBuilder(errorHandlerBuilder);
731 }
732
733 if (shouldStartContext != null) {
734 ctx.setShouldStartContext(shouldStartContext);
735 }
736
737 return ctx;
738 }
739
740 /**
741 * Strategy to install all available routes into the context
742 */
743 @SuppressWarnings("unchecked")
744 protected void installRoutes() throws Exception {
745 List<RouteBuilder> builders = new ArrayList<RouteBuilder>();
746
747 if (routeBuilder != null) {
748 builders.add(routeBuilder);
749 }
750
751 // lets add route builders added from references
752 if (builderRefs != null) {
753 for (RouteBuilderDefinition builderRef : builderRefs) {
754 RouteBuilder builder = builderRef.createRouteBuilder(getContext());
755 if (builder != null) {
756 builders.add(builder);
757 } else {
758 // support to get the route here
759 RoutesBuilder routes = builderRef.createRoutes(getContext());
760 if (routes != null) {
761 additionalBuilders.add(routes);
762 } else {
763 // Throw the exception that we can't find any build here
764 throw new CamelException("Cannot find any routes with this RouteBuilder reference: " + builderRef);
765 }
766 }
767
768 }
769 }
770
771 // install already configured routes
772 for (RoutesBuilder routeBuilder : additionalBuilders) {
773 getContext().addRoutes(routeBuilder);
774 }
775
776 // install builders
777 for (RouteBuilder builder : builders) {
778 if (beanPostProcessor != null) {
779 // Inject the annotated resource
780 beanPostProcessor.postProcessBeforeInitialization(builder, builder.toString());
781 }
782 getContext().addRoutes(builder);
783 }
784 }
785
786 /**
787 * Strategy method to try find {@link RouteBuilder} instances on the classpath
788 */
789 protected void findRouteBuilders() throws Exception {
790
791 PackageScanClassResolver resolver = getContext().getPackageScanClassResolver();
792 addPackageElementContentsToScanDefinition();
793
794 PackageScanDefinition packageScanDef = getPackageScan();
795
796 if (packageScanDef != null && packageScanDef.getPackages().size() > 0) {
797
798 PatternBasedPackageScanFilter filter = new PatternBasedPackageScanFilter();
799 filter.addIncludePatterns(packageScanDef.getIncludes());
800 filter.addExcludePatterns(packageScanDef.getExcludes());
801 resolver.addFilter(filter);
802
803 String[] normalized = normalizePackages(packageScanDef.getPackages());
804 RouteBuilderFinder finder = new RouteBuilderFinder(getContext(), normalized, getContextClassLoaderOnStart(), getBeanPostProcessor(), getContext()
805 .getPackageScanClassResolver());
806 finder.appendBuilders(getAdditionalBuilders());
807 }
808
809 }
810
811 private void addPackageElementContentsToScanDefinition() {
812 PackageScanDefinition packageScanDef = getPackageScan();
813
814 if (getPackages() != null && getPackages().length > 0) {
815 LOG.warn("Using a packages element to specify packages to search has been deprecated. Please use a packageScan element instead.");
816 if (packageScanDef == null) {
817 packageScanDef = new PackageScanDefinition();
818 setPackageScan(packageScanDef);
819 }
820
821 for (String pkg : getPackages()) {
822 packageScanDef.getPackages().add(pkg);
823 }
824 }
825 }
826
827 private String[] normalizePackages(List<String> unnormalized) {
828 List<String> packages = new ArrayList<String>();
829 for (String name : unnormalized) {
830 name = ObjectHelper.normalizeClassName(name);
831 if (ObjectHelper.isNotEmpty(name)) {
832 if (LOG.isTraceEnabled()) {
833 LOG.trace("Using package: " + name + " to scan for RouteBuilder classes");
834 }
835 packages.add(name);
836 }
837 }
838 return packages.toArray(new String[packages.size()]);
839 }
840
841 }