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