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.CamelContext;
030    import org.apache.camel.RoutesBuilder;
031    import org.apache.camel.ShutdownRoute;
032    import org.apache.camel.ShutdownRunningTask;
033    import org.apache.camel.builder.RouteBuilder;
034    import org.apache.camel.core.xml.AbstractCamelContextFactoryBean;
035    import org.apache.camel.core.xml.CamelJMXAgentDefinition;
036    import org.apache.camel.core.xml.CamelPropertyPlaceholderDefinition;
037    import org.apache.camel.core.xml.CamelProxyFactoryDefinition;
038    import org.apache.camel.core.xml.CamelServiceExporterDefinition;
039    import org.apache.camel.model.ContextScanDefinition;
040    import org.apache.camel.model.InterceptDefinition;
041    import org.apache.camel.model.InterceptFromDefinition;
042    import org.apache.camel.model.InterceptSendToEndpointDefinition;
043    import org.apache.camel.model.OnCompletionDefinition;
044    import org.apache.camel.model.OnExceptionDefinition;
045    import org.apache.camel.model.PackageScanDefinition;
046    import org.apache.camel.model.RouteBuilderDefinition;
047    import org.apache.camel.model.RouteContextRefDefinition;
048    import org.apache.camel.model.RouteDefinition;
049    import org.apache.camel.model.ThreadPoolProfileDefinition;
050    import org.apache.camel.model.config.PropertiesDefinition;
051    import org.apache.camel.model.dataformat.DataFormatsDefinition;
052    import org.apache.camel.spi.PackageScanFilter;
053    import org.apache.camel.spi.Registry;
054    import org.slf4j.Logger;
055    import org.slf4j.LoggerFactory;
056    import org.springframework.beans.factory.DisposableBean;
057    import org.springframework.beans.factory.FactoryBean;
058    import org.springframework.beans.factory.InitializingBean;
059    import org.springframework.beans.factory.config.BeanPostProcessor;
060    import org.springframework.context.ApplicationContext;
061    import org.springframework.context.ApplicationContextAware;
062    import org.springframework.context.ApplicationEvent;
063    import org.springframework.context.ApplicationListener;
064    import org.springframework.context.event.ContextRefreshedEvent;
065    
066    import static org.apache.camel.util.ObjectHelper.wrapRuntimeCamelException;
067    
068    /**
069     * A Spring {@link FactoryBean} to create and initialize a
070     * {@link SpringCamelContext} and install routes either explicitly configured in
071     * Spring XML or found by searching the classpath for Java classes which extend
072     * {@link RouteBuilder} using the nested {@link #setPackages(String[])}.
073     *
074     * @version 
075     */
076    @XmlRootElement(name = "camelContext")
077    @XmlAccessorType(XmlAccessType.FIELD)
078    @SuppressWarnings("unused")
079    public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<SpringCamelContext>
080            implements FactoryBean, InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener {
081        private static final Logger LOG = LoggerFactory.getLogger(CamelContextFactoryBean.class);
082    
083        @XmlAttribute(name = "depends-on", required = false)
084        private String dependsOn;
085        @XmlAttribute(required = false)
086        private String trace;
087        @XmlAttribute(required = false)
088        private String streamCache;
089        @XmlAttribute(required = false)
090        private String delayer;
091        @XmlAttribute(required = false)
092        private String handleFault;
093        @XmlAttribute(required = false)
094        private String errorHandlerRef;
095        @XmlAttribute(required = false)
096        private String autoStartup;
097        @XmlAttribute(required = false)
098        private String useMDCLogging;
099        @XmlAttribute(required = false)
100        private String useBreadcrumb;
101        @XmlAttribute(required = false)
102        private ShutdownRoute shutdownRoute;
103        @XmlAttribute(required = false)
104        private ShutdownRunningTask shutdownRunningTask;
105        @XmlAttribute(required = false)
106        private Boolean lazyLoadTypeConverters;
107        @XmlElement(name = "properties", required = false)
108        private PropertiesDefinition properties;
109        @XmlElement(name = "propertyPlaceholder", type = CamelPropertyPlaceholderDefinition.class, required = false)
110        private CamelPropertyPlaceholderDefinition camelPropertyPlaceholder;
111        @XmlElement(name = "package", required = false)
112        private String[] packages = {};
113        @XmlElement(name = "packageScan", type = PackageScanDefinition.class, required = false)
114        private PackageScanDefinition packageScan;
115        @XmlElement(name = "contextScan", type = ContextScanDefinition.class, required = false)
116        private ContextScanDefinition contextScan;
117        @XmlElement(name = "jmxAgent", type = CamelJMXAgentDefinition.class, required = false)
118        private CamelJMXAgentDefinition camelJMXAgent;
119        @XmlElements({
120                @XmlElement(name = "template", type = CamelProducerTemplateFactoryBean.class, required = false),
121                @XmlElement(name = "consumerTemplate", type = CamelConsumerTemplateFactoryBean.class, required = false),
122                @XmlElement(name = "proxy", type = CamelProxyFactoryDefinition.class, required = false),
123                @XmlElement(name = "export", type = CamelServiceExporterDefinition.class, required = false),
124                @XmlElement(name = "errorHandler", type = ErrorHandlerDefinition.class, required = false)})
125        private List beans;
126        @XmlElement(name = "routeBuilder", required = false)
127        private List<RouteBuilderDefinition> builderRefs = new ArrayList<RouteBuilderDefinition>();
128        @XmlElement(name = "routeContextRef", required = false)
129        private List<RouteContextRefDefinition> routeRefs = new ArrayList<RouteContextRefDefinition>();
130        @XmlElement(name = "threadPoolProfile", required = false)
131        private List<ThreadPoolProfileDefinition> threadPoolProfiles;
132        @XmlElement(name = "threadPool", required = false)
133        private List<CamelThreadPoolFactoryBean> threadPools;
134        @XmlElement(name = "endpoint", required = false)
135        private List<CamelEndpointFactoryBean> endpoints;
136        @XmlElement(name = "dataFormats", required = false)
137        private DataFormatsDefinition dataFormats;
138        @XmlElement(name = "redeliveryPolicyProfile", required = false)
139        private List<CamelRedeliveryPolicyFactoryBean> redeliveryPolicies;
140        @XmlElement(name = "onException", required = false)
141        private List<OnExceptionDefinition> onExceptions = new ArrayList<OnExceptionDefinition>();
142        @XmlElement(name = "onCompletion", required = false)
143        private List<OnCompletionDefinition> onCompletions = new ArrayList<OnCompletionDefinition>();
144        @XmlElement(name = "intercept", required = false)
145        private List<InterceptDefinition> intercepts = new ArrayList<InterceptDefinition>();
146        @XmlElement(name = "interceptFrom", required = false)
147        private List<InterceptFromDefinition> interceptFroms = new ArrayList<InterceptFromDefinition>();
148        @XmlElement(name = "interceptSendToEndpoint", required = false)
149        private List<InterceptSendToEndpointDefinition> interceptSendToEndpoints = new ArrayList<InterceptSendToEndpointDefinition>();
150        @XmlElement(name = "route", required = false)
151        private List<RouteDefinition> routes = new ArrayList<RouteDefinition>();
152        @XmlTransient
153        private SpringCamelContext context;
154        @XmlTransient
155        private ClassLoader contextClassLoaderOnStart;
156        @XmlTransient
157        private ApplicationContext applicationContext;
158        @XmlTransient
159        private BeanPostProcessor beanPostProcessor;
160        @XmlTransient
161        private boolean implicitId;
162        
163    
164        @Override
165        public Class<SpringCamelContext> getObjectType() {
166            return SpringCamelContext.class;
167        }
168        
169        protected <S> S getBeanForType(Class<S> clazz) {
170            S bean = null;
171            String[] names = getApplicationContext().getBeanNamesForType(clazz, true, true);
172            if (names.length == 1) {
173                bean = getApplicationContext().getBean(names[0], clazz);
174            }
175            if (bean == null) {
176                ApplicationContext parentContext = getApplicationContext().getParent();
177                if (parentContext != null) {
178                    names = parentContext.getBeanNamesForType(clazz, true, true);
179                    if (names.length == 1) {
180                        bean = parentContext.getBean(names[0], clazz);
181                    }
182                }
183            }
184            return bean;
185        }
186    
187        @Override
188        protected void findRouteBuildersByPackageScan(String[] packages, PackageScanFilter filter, List<RoutesBuilder> builders) throws Exception {
189            // add filter to class resolver which then will filter
190            getContext().getPackageScanClassResolver().addFilter(filter);
191    
192            PackageScanRouteBuilderFinder finder = new PackageScanRouteBuilderFinder(getContext(), packages, getContextClassLoaderOnStart(),
193                                                                                     getBeanPostProcessor(), getContext().getPackageScanClassResolver());
194            finder.appendBuilders(builders);
195    
196            // and remove the filter
197            getContext().getPackageScanClassResolver().removeFilter(filter);
198        }
199    
200        @Override
201        protected void findRouteBuildersByContextScan(PackageScanFilter filter, List<RoutesBuilder> builders) throws Exception {
202            ContextScanRouteBuilderFinder finder = new ContextScanRouteBuilderFinder(getContext(), filter);
203            finder.appendBuilders(builders);
204        }
205    
206        protected void initBeanPostProcessor(SpringCamelContext context) {
207            if (beanPostProcessor != null) {
208                if (beanPostProcessor instanceof ApplicationContextAware) {
209                    ((ApplicationContextAware) beanPostProcessor).setApplicationContext(applicationContext);
210                }
211                if (beanPostProcessor instanceof CamelBeanPostProcessor) {
212                    ((CamelBeanPostProcessor) beanPostProcessor).setCamelContext(getContext());
213                }
214            }
215        }
216    
217        protected void postProcessBeforeInit(RouteBuilder builder) {
218            if (beanPostProcessor != null) {
219                // Inject the annotated resource
220                beanPostProcessor.postProcessBeforeInitialization(builder, builder.toString());
221            }
222        }
223    
224        protected void initCustomRegistry(SpringCamelContext context) {
225            Registry registry = getBeanForType(Registry.class);
226            if (registry != null) {
227                LOG.info("Using custom Registry: " + registry);
228                context.setRegistry(registry);
229            }
230        }
231    
232        public void onApplicationEvent(ApplicationEvent event) {
233            // From Spring 3.0.1, The BeanFactory applicationEventListener 
234            // and Bean's applicationEventListener will be called,
235            // So we just delegate the onApplicationEvent call here.
236    
237            SpringCamelContext context = getContext(false);
238            if (context != null) {
239                // let the spring camel context handle the events
240                context.onApplicationEvent(event);
241            } else {
242                LOG.debug("Publishing spring-event: {}", event);
243    
244                if (event instanceof ContextRefreshedEvent) {
245                    // now lets start the CamelContext so that all its possible
246                    // dependencies are initialized
247                    try {
248                        LOG.debug("Starting the context now!");
249                        getContext().start();
250                    } catch (Exception e) {
251                        throw wrapRuntimeCamelException(e);
252                    }
253                }
254            }
255        }
256    
257        // Properties
258        // -------------------------------------------------------------------------
259    
260        public ApplicationContext getApplicationContext() {
261            if (applicationContext == null) {
262                throw new IllegalArgumentException("No applicationContext has been injected!");
263            }
264            return applicationContext;
265        }
266    
267        public void setApplicationContext(ApplicationContext applicationContext) {
268            this.applicationContext = applicationContext;
269        }
270    
271        public void setBeanPostProcessor(BeanPostProcessor postProcessor) {
272            this.beanPostProcessor = postProcessor;
273        }
274    
275        public BeanPostProcessor getBeanPostProcessor() {
276            return beanPostProcessor;
277        }
278    
279        // Implementation methods
280        // -------------------------------------------------------------------------
281    
282        /**
283         * Create the context
284         */
285        protected SpringCamelContext createContext() {
286            SpringCamelContext ctx = newCamelContext();        
287            ctx.setName(getId());        
288            return ctx;
289        }
290    
291        protected SpringCamelContext newCamelContext() {
292            return new SpringCamelContext(getApplicationContext());
293        }
294    
295        public SpringCamelContext getContext(boolean create) {
296            if (context == null && create) {
297                context = createContext();
298            }
299            return context;
300        }
301    
302        public void setContext(SpringCamelContext context) {
303            this.context = context;
304        }
305    
306        public List<RouteDefinition> getRoutes() {
307            return routes;
308        }
309    
310        public void setRoutes(List<RouteDefinition> routes) {
311            this.routes = routes;
312        }
313    
314        public List<CamelEndpointFactoryBean> getEndpoints() {
315            return endpoints;
316        }
317    
318        public List<CamelRedeliveryPolicyFactoryBean> getRedeliveryPolicies() {
319            return redeliveryPolicies;
320        }
321    
322        public List<InterceptDefinition> getIntercepts() {
323            return intercepts;
324        }
325    
326        public void setIntercepts(List<InterceptDefinition> intercepts) {
327            this.intercepts = intercepts;
328        }
329    
330        public List<InterceptFromDefinition> getInterceptFroms() {
331            return interceptFroms;
332        }
333    
334        public void setInterceptFroms(List<InterceptFromDefinition> interceptFroms) {
335            this.interceptFroms = interceptFroms;
336        }
337    
338        public List<InterceptSendToEndpointDefinition> getInterceptSendToEndpoints() {
339            return interceptSendToEndpoints;
340        }
341    
342        public void setInterceptSendToEndpoints(List<InterceptSendToEndpointDefinition> interceptSendToEndpoints) {
343            this.interceptSendToEndpoints = interceptSendToEndpoints;
344        }
345    
346        public PropertiesDefinition getProperties() {
347            return properties;
348        }
349    
350        public void setProperties(PropertiesDefinition properties) {
351            this.properties = properties;
352        }
353    
354        public String[] getPackages() {
355            return packages;
356        }
357    
358        /**
359         * Sets the package names to be recursively searched for Java classes which
360         * extend {@link org.apache.camel.builder.RouteBuilder} to be auto-wired up to the
361         * {@link CamelContext} as a route. Note that classes are excluded if
362         * they are specifically configured in the spring.xml
363         * <p/>
364         * A more advanced configuration can be done using {@link #setPackageScan(org.apache.camel.model.PackageScanDefinition)}
365         *
366         * @param packages the package names which are recursively searched
367         * @see #setPackageScan(org.apache.camel.model.PackageScanDefinition)
368         */
369        public void setPackages(String[] packages) {
370            this.packages = packages;
371        }
372    
373        public PackageScanDefinition getPackageScan() {
374            return packageScan;
375        }
376    
377        /**
378         * Sets the package scanning information. Package scanning allows for the
379         * automatic discovery of certain camel classes at runtime for inclusion
380         * e.g. {@link org.apache.camel.builder.RouteBuilder} implementations
381         *
382         * @param packageScan the package scan
383         */
384        public void setPackageScan(PackageScanDefinition packageScan) {
385            this.packageScan = packageScan;
386        }
387    
388        public ContextScanDefinition getContextScan() {
389            return contextScan;
390        }
391    
392        /**
393         * Sets the context scanning (eg Spring's ApplicationContext) information.
394         * Context scanning allows for the automatic discovery of Camel routes runtime for inclusion
395         * e.g. {@link org.apache.camel.builder.RouteBuilder} implementations
396         *
397         * @param contextScan the context scan
398         */
399        public void setContextScan(ContextScanDefinition contextScan) {
400            this.contextScan = contextScan;
401        }
402    
403        public CamelPropertyPlaceholderDefinition getCamelPropertyPlaceholder() {
404            return camelPropertyPlaceholder;
405        }
406    
407        public void setCamelPropertyPlaceholder(CamelPropertyPlaceholderDefinition camelPropertyPlaceholder) {
408            this.camelPropertyPlaceholder = camelPropertyPlaceholder;
409        }
410    
411        public void setCamelJMXAgent(CamelJMXAgentDefinition agent) {
412            camelJMXAgent = agent;
413        }
414    
415        public String getTrace() {
416            return trace;
417        }
418    
419        public void setTrace(String trace) {
420            this.trace = trace;
421        }
422    
423        public String getStreamCache() {
424            return streamCache;
425        }
426    
427        public void setStreamCache(String streamCache) {
428            this.streamCache = streamCache;
429        }
430    
431        public String getDelayer() {
432            return delayer;
433        }
434    
435        public void setDelayer(String delayer) {
436            this.delayer = delayer;
437        }
438    
439        public String getHandleFault() {
440            return handleFault;
441        }
442    
443        public void setHandleFault(String handleFault) {
444            this.handleFault = handleFault;
445        }
446    
447        public String getAutoStartup() {
448            return autoStartup;
449        }
450    
451        public void setAutoStartup(String autoStartup) {
452            this.autoStartup = autoStartup;
453        }
454    
455        public String getUseMDCLogging() {
456            return useMDCLogging;
457        }
458    
459        public void setUseMDCLogging(String useMDCLogging) {
460            this.useMDCLogging = useMDCLogging;
461        }
462    
463        public String getUseBreadcrumb() {
464            return useBreadcrumb;
465        }
466    
467        public void setUseBreadcrumb(String useBreadcrumb) {
468            this.useBreadcrumb = useBreadcrumb;
469        }
470    
471        public Boolean getLazyLoadTypeConverters() {
472            return lazyLoadTypeConverters;
473        }
474    
475        public void setLazyLoadTypeConverters(Boolean lazyLoadTypeConverters) {
476            this.lazyLoadTypeConverters = lazyLoadTypeConverters;
477        }
478    
479        public CamelJMXAgentDefinition getCamelJMXAgent() {
480            return camelJMXAgent;
481        }
482    
483        public List<RouteBuilderDefinition> getBuilderRefs() {
484            return builderRefs;
485        }
486    
487        public void setBuilderRefs(List<RouteBuilderDefinition> builderRefs) {
488            this.builderRefs = builderRefs;
489        }
490    
491        public List<RouteContextRefDefinition> getRouteRefs() {
492            return routeRefs;
493        }
494    
495        public void setRouteRefs(List<RouteContextRefDefinition> routeRefs) {
496            this.routeRefs = routeRefs;
497        }
498    
499        public String getErrorHandlerRef() {
500            return errorHandlerRef;
501        }
502    
503        /**
504         * Sets the name of the error handler object used to default the error handling strategy
505         *
506         * @param errorHandlerRef the Spring bean ref of the error handler
507         */
508        public void setErrorHandlerRef(String errorHandlerRef) {
509            this.errorHandlerRef = errorHandlerRef;
510        }
511    
512        public void setDataFormats(DataFormatsDefinition dataFormats) {
513            this.dataFormats = dataFormats;
514        }
515    
516        public DataFormatsDefinition getDataFormats() {
517            return dataFormats;
518        }
519    
520        public void setOnExceptions(List<OnExceptionDefinition> onExceptions) {
521            this.onExceptions = onExceptions;
522        }
523    
524        public List<OnExceptionDefinition> getOnExceptions() {
525            return onExceptions;
526        }
527    
528        public List<OnCompletionDefinition> getOnCompletions() {
529            return onCompletions;
530        }
531    
532        public void setOnCompletions(List<OnCompletionDefinition> onCompletions) {
533            this.onCompletions = onCompletions;
534        }
535    
536        public ShutdownRoute getShutdownRoute() {
537            return shutdownRoute;
538        }
539    
540        public void setShutdownRoute(ShutdownRoute shutdownRoute) {
541            this.shutdownRoute = shutdownRoute;
542        }
543    
544        public ShutdownRunningTask getShutdownRunningTask() {
545            return shutdownRunningTask;
546        }
547    
548        public void setShutdownRunningTask(ShutdownRunningTask shutdownRunningTask) {
549            this.shutdownRunningTask = shutdownRunningTask;
550        }
551    
552        public List<ThreadPoolProfileDefinition> getThreadPoolProfiles() {
553            return threadPoolProfiles;
554        }
555    
556        public void setThreadPoolProfiles(List<ThreadPoolProfileDefinition> threadPoolProfiles) {
557            this.threadPoolProfiles = threadPoolProfiles;
558        }
559    
560        public String getDependsOn() {
561            return dependsOn;
562        }
563    
564        public void setDependsOn(String dependsOn) {
565            this.dependsOn = dependsOn;
566        }
567        
568        public boolean isImplicitId() {
569            return implicitId;
570        }
571        
572        public void setImplicitId(boolean flag) {
573            implicitId = flag;
574        }
575    
576    }