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