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    }