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