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