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