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 */
017package org.apache.camel.blueprint;
018
019import java.util.ArrayList;
020import java.util.Collection;
021import java.util.List;
022import java.util.Properties;
023import javax.xml.bind.annotation.XmlAccessType;
024import javax.xml.bind.annotation.XmlAccessorType;
025import javax.xml.bind.annotation.XmlAttribute;
026import javax.xml.bind.annotation.XmlElement;
027import javax.xml.bind.annotation.XmlElements;
028import javax.xml.bind.annotation.XmlRootElement;
029import javax.xml.bind.annotation.XmlTransient;
030
031import org.apache.camel.RoutesBuilder;
032import org.apache.camel.ShutdownRoute;
033import org.apache.camel.ShutdownRunningTask;
034import org.apache.camel.builder.RouteBuilder;
035import org.apache.camel.component.properties.PropertiesComponent;
036import org.apache.camel.core.osgi.OsgiCamelContextPublisher;
037import org.apache.camel.core.osgi.OsgiEventAdminNotifier;
038import org.apache.camel.core.osgi.utils.BundleDelegatingClassLoader;
039import org.apache.camel.core.xml.AbstractCamelContextFactoryBean;
040import org.apache.camel.core.xml.CamelJMXAgentDefinition;
041import org.apache.camel.core.xml.CamelPropertyPlaceholderDefinition;
042import org.apache.camel.core.xml.CamelServiceExporterDefinition;
043import org.apache.camel.core.xml.CamelStreamCachingStrategyDefinition;
044import org.apache.camel.model.ContextScanDefinition;
045import org.apache.camel.model.InterceptDefinition;
046import org.apache.camel.model.InterceptFromDefinition;
047import org.apache.camel.model.InterceptSendToEndpointDefinition;
048import org.apache.camel.model.OnCompletionDefinition;
049import org.apache.camel.model.OnExceptionDefinition;
050import org.apache.camel.model.PackageScanDefinition;
051import org.apache.camel.model.RouteBuilderDefinition;
052import org.apache.camel.model.RouteContextRefDefinition;
053import org.apache.camel.model.RouteDefinition;
054import org.apache.camel.model.ThreadPoolProfileDefinition;
055import org.apache.camel.model.config.PropertiesDefinition;
056import org.apache.camel.model.dataformat.DataFormatsDefinition;
057import org.apache.camel.spi.PackageScanFilter;
058import org.apache.camel.spi.Registry;
059import org.osgi.framework.BundleContext;
060import org.osgi.framework.ServiceReference;
061import org.osgi.service.blueprint.container.BlueprintContainer;
062import org.slf4j.Logger;
063import org.slf4j.LoggerFactory;
064
065/**
066 * A bean to create and initialize a {@link BlueprintCamelContext}
067 * and install routes either explicitly configured in
068 * Blueprint XML or found by searching the classpath for Java classes which extend
069 * {@link RouteBuilder} using the nested {@link #setPackages(String[])}.
070 *
071 * @version 
072 */
073@XmlRootElement(name = "camelContext")
074@XmlAccessorType(XmlAccessType.FIELD)
075public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<BlueprintCamelContext> {
076    private static final Logger LOG = LoggerFactory.getLogger(CamelContextFactoryBean.class);
077
078    @XmlAttribute(name = "depends-on", required = false)
079    private String dependsOn;
080    @XmlAttribute(required = false)
081    private String trace;
082    @XmlAttribute(required = false)
083    private String messageHistory;
084    @XmlAttribute(required = false)
085    private String streamCache = "false";
086    @XmlAttribute(required = false)
087    private String delayer;
088    @XmlAttribute(required = false)
089    private String handleFault;
090    @XmlAttribute(required = false)
091    private String errorHandlerRef;
092    @XmlAttribute(required = false)
093    private String autoStartup = "true";
094    @XmlAttribute(required = false)
095    private String useMDCLogging;
096    @XmlAttribute(required = false)
097    private String useBreadcrumb;
098    @XmlAttribute(required = false)
099    private String allowUseOriginalMessage;
100    @XmlAttribute(required = false)
101    private String managementNamePattern;
102    @XmlAttribute(required = false)
103    private String threadNamePattern;
104    @XmlAttribute(required = false)
105    private Boolean useBlueprintPropertyResolver;
106    @XmlAttribute(required = false)
107    private ShutdownRoute shutdownRoute;
108    @XmlAttribute(required = false)
109    private ShutdownRunningTask shutdownRunningTask;
110    @XmlAttribute(required = false)
111    @Deprecated
112    private Boolean lazyLoadTypeConverters;
113    @XmlAttribute(required = false)
114    private Boolean typeConverterStatisticsEnabled;
115    @XmlElement(name = "properties", required = false)
116    private PropertiesDefinition properties;
117    @XmlElement(name = "propertyPlaceholder", type = CamelPropertyPlaceholderDefinition.class, required = false)
118    private CamelPropertyPlaceholderDefinition camelPropertyPlaceholder;
119    @XmlElement(name = "package", required = false)
120    private String[] packages = {};
121    @XmlElement(name = "packageScan", type = PackageScanDefinition.class, required = false)
122    private PackageScanDefinition packageScan;
123    @XmlElement(name = "contextScan", type = ContextScanDefinition.class, required = false)
124    private ContextScanDefinition contextScan;
125    @XmlElement(name = "jmxAgent", type = CamelJMXAgentDefinition.class, required = false)
126    private CamelJMXAgentDefinition camelJMXAgent;
127    @XmlElement(name = "streamCaching", type = CamelStreamCachingStrategyDefinition.class, required = false)
128    private CamelStreamCachingStrategyDefinition camelStreamCachingStrategy;
129    @XmlElements({
130        @XmlElement(name = "template", type = CamelProducerTemplateFactoryBean.class, required = false),
131        @XmlElement(name = "consumerTemplate", type = CamelConsumerTemplateFactoryBean.class, required = false),
132        @XmlElement(name = "proxy", type = CamelProxyFactoryBean.class, required = false),
133        @XmlElement(name = "export", type = CamelServiceExporterDefinition.class, required = false),
134        @XmlElement(name = "errorHandler", type = CamelErrorHandlerFactoryBean.class, required = false)
135    })
136    private List<?> beans;
137    @XmlElement(name = "routeBuilder", required = false)
138    private List<RouteBuilderDefinition> builderRefs = new ArrayList<RouteBuilderDefinition>();
139    @XmlElement(name = "routeContextRef", required = false)
140    private List<RouteContextRefDefinition> routeRefs = new ArrayList<RouteContextRefDefinition>();
141    @XmlElement(name = "threadPoolProfile", required = false)
142    private List<ThreadPoolProfileDefinition> threadPoolProfiles;
143    @XmlElement(name = "threadPool", required = false)
144    private List<CamelThreadPoolFactoryBean> threadPools;
145    @XmlElement(name = "endpoint", required = false)
146    private List<CamelEndpointFactoryBean> endpoints;
147    @XmlElement(name = "dataFormats", required = false)
148    private DataFormatsDefinition dataFormats;
149    @XmlElement(name = "redeliveryPolicyProfile", required = false)
150    private List<CamelRedeliveryPolicyFactoryBean> redeliveryPolicies;
151    @XmlElement(name = "onException", required = false)
152    private List<OnExceptionDefinition> onExceptions = new ArrayList<OnExceptionDefinition>();
153    @XmlElement(name = "onCompletion", required = false)
154    private List<OnCompletionDefinition> onCompletions = new ArrayList<OnCompletionDefinition>();
155    @XmlElement(name = "intercept", required = false)
156    private List<InterceptDefinition> intercepts = new ArrayList<InterceptDefinition>();
157    @XmlElement(name = "interceptFrom", required = false)
158    private List<InterceptFromDefinition> interceptFroms = new ArrayList<InterceptFromDefinition>();
159    @XmlElement(name = "interceptSendToEndpoint", required = false)
160    private List<InterceptSendToEndpointDefinition> interceptSendToEndpoints = new ArrayList<InterceptSendToEndpointDefinition>();
161    @XmlElement(name = "route", required = false)
162    private List<RouteDefinition> routes = new ArrayList<RouteDefinition>();
163    @XmlTransient
164    private BlueprintCamelContext context;
165    @XmlTransient
166    private BlueprintContainer blueprintContainer;
167    @XmlTransient
168    private BundleContext bundleContext;
169    @XmlTransient
170    private boolean implicitId;
171    @XmlTransient
172    private OsgiCamelContextPublisher osgiCamelContextPublisher;
173
174    public Class<BlueprintCamelContext> getObjectType() {
175        return BlueprintCamelContext.class;
176    }
177
178    @Override
179    public BlueprintCamelContext getContext(boolean create) {
180        if (context == null && create) {
181            context = createContext();
182            if (!isImplicitId()) {
183                context.setName(getId());
184            }
185        }
186        return context;
187    }
188
189    public void setBlueprintContainer(BlueprintContainer blueprintContainer) {
190        this.blueprintContainer = blueprintContainer;
191    }
192
193    public void setBundleContext(BundleContext bundleContext) {
194        this.bundleContext = bundleContext;
195    }
196
197    protected BlueprintCamelContext createContext() {
198        return new BlueprintCamelContext(bundleContext, blueprintContainer);
199    }
200
201    @Override
202    protected void initCustomRegistry(BlueprintCamelContext context) {
203        Registry registry = getBeanForType(Registry.class);
204        if (registry != null) {
205            LOG.info("Using custom Registry: " + registry);
206            context.setRegistry(registry);
207        }
208    }
209
210    @Override
211    protected <S> S getBeanForType(Class<S> clazz) {
212        Collection<S> objects = BlueprintContainerRegistry.lookupByType(blueprintContainer, clazz).values();
213        if (objects.size() == 1) {
214            return objects.iterator().next();
215        }
216        return null;
217    }
218
219    @Override
220    protected void initPropertyPlaceholder() throws Exception {
221        super.initPropertyPlaceholder();
222
223        // if blueprint property resolver is enabled on CamelContext then bridge PropertiesComponent to blueprint
224        if (isUseBlueprintPropertyResolver()) {
225            // lookup existing configured properties component
226            PropertiesComponent pc = getContext().getComponent("properties", PropertiesComponent.class);
227
228            BlueprintPropertiesParser parser = new BlueprintPropertiesParser(pc, blueprintContainer, pc.getPropertiesParser());
229            BlueprintPropertiesResolver resolver = new BlueprintPropertiesResolver(pc.getPropertiesResolver(), parser);
230
231            // any extra properties
232            ServiceReference<?> ref = bundleContext.getServiceReference(PropertiesComponent.OVERRIDE_PROPERTIES);
233            if (ref != null) {
234                Properties extra = (Properties) bundleContext.getService(ref);
235                if (extra != null) {
236                    pc.setOverrideProperties(extra);
237                }
238            }
239
240            // no locations has been set, so its a default component
241            if (pc.getLocations() == null) {
242                StringBuilder sb = new StringBuilder();
243                String[] ids = parser.lookupPropertyPlaceholderIds();
244                for (String id : ids) {
245                    sb.append("blueprint:").append(id).append(",");
246                }
247                if (sb.length() > 0) {
248                    // location supports multiple separated by comma
249                    pc.setLocation(sb.toString());
250                }
251            }
252
253            if (pc.getLocations() != null) {
254                // bridge camel properties with blueprint
255                pc.setPropertiesParser(parser);
256                pc.setPropertiesResolver(resolver);
257            }
258        }
259    }
260
261    @Override
262    protected void initBeanPostProcessor(BlueprintCamelContext context) {
263    }
264
265    @Override
266    protected void postProcessBeforeInit(RouteBuilder builder) {
267    }
268
269    @Override
270    protected void findRouteBuildersByPackageScan(String[] packages, PackageScanFilter filter, List<RoutesBuilder> builders) throws Exception {
271        // add filter to class resolver which then will filter
272        getContext().getPackageScanClassResolver().addFilter(filter);
273        ClassLoader classLoader = new BundleDelegatingClassLoader(bundleContext.getBundle());
274        PackageScanRouteBuilderFinder finder = new PackageScanRouteBuilderFinder(getContext(), packages, classLoader,
275                                                                                 getContext().getPackageScanClassResolver());
276        finder.appendBuilders(builders);
277
278        // and remove the filter
279        getContext().getPackageScanClassResolver().removeFilter(filter);
280    }
281
282    @Override
283    protected void findRouteBuildersByContextScan(PackageScanFilter filter, List<RoutesBuilder> builders) throws Exception {
284        ContextScanRouteBuilderFinder finder = new ContextScanRouteBuilderFinder(getContext(), filter);
285        finder.appendBuilders(builders);
286    }
287
288    @Override
289    public void afterPropertiesSet() throws Exception {
290        super.afterPropertiesSet();
291        // setup the application context classloader with the bundle delegating classloader
292        ClassLoader cl = new BundleDelegatingClassLoader(bundleContext.getBundle());
293        LOG.debug("Set the application context classloader to: {}", cl);
294        getContext().setApplicationContextClassLoader(cl);
295        osgiCamelContextPublisher = new OsgiCamelContextPublisher(bundleContext);
296        osgiCamelContextPublisher.start();
297        getContext().getManagementStrategy().addEventNotifier(osgiCamelContextPublisher);
298        try {
299            getClass().getClassLoader().loadClass("org.osgi.service.event.EventAdmin");
300            getContext().getManagementStrategy().addEventNotifier(new OsgiEventAdminNotifier(bundleContext));
301        } catch (Throwable t) {
302            // Ignore, if the EventAdmin package is not available, just don't use it
303            LOG.debug("EventAdmin package is not available, just don't use it");
304        }
305        // ensure routes is setup
306        setupRoutes();
307    }
308
309    @Override
310    public void destroy() throws Exception {
311        super.destroy();
312        if (osgiCamelContextPublisher != null) {
313            osgiCamelContextPublisher.shutdown();
314        }
315    }
316
317    public String getDependsOn() {
318        return dependsOn;
319    }
320
321    public void setDependsOn(String dependsOn) {
322        this.dependsOn = dependsOn;
323    }
324
325    public String getAutoStartup() {
326        return autoStartup;
327    }
328
329    public void setAutoStartup(String autoStartup) {
330        this.autoStartup = autoStartup;
331    }
332
333    public String getUseMDCLogging() {
334        return useMDCLogging;
335    }
336
337    public void setUseMDCLogging(String useMDCLogging) {
338        this.useMDCLogging = useMDCLogging;
339    }
340
341    public String getUseBreadcrumb() {
342        return useBreadcrumb;
343    }
344
345    public void setUseBreadcrumb(String useBreadcrumb) {
346        this.useBreadcrumb = useBreadcrumb;
347    }
348
349    public String getAllowUseOriginalMessage() {
350        return allowUseOriginalMessage;
351    }
352
353    public void setAllowUseOriginalMessage(String allowUseOriginalMessage) {
354        this.allowUseOriginalMessage = allowUseOriginalMessage;
355    }
356
357    public String getManagementNamePattern() {
358        return managementNamePattern;
359    }
360
361    public void setManagementNamePattern(String managementNamePattern) {
362        this.managementNamePattern = managementNamePattern;
363    }
364
365    public String getThreadNamePattern() {
366        return threadNamePattern;
367    }
368
369    public void setThreadNamePattern(String threadNamePattern) {
370        this.threadNamePattern = threadNamePattern;
371    }
372
373    @Deprecated
374    public Boolean getLazyLoadTypeConverters() {
375        // use false by default
376        return lazyLoadTypeConverters != null ? lazyLoadTypeConverters : Boolean.FALSE;
377    }
378
379    @Deprecated
380    public void setLazyLoadTypeConverters(Boolean lazyLoadTypeConverters) {
381        this.lazyLoadTypeConverters = lazyLoadTypeConverters;
382    }
383
384    public Boolean getTypeConverterStatisticsEnabled() {
385        return typeConverterStatisticsEnabled;
386    }
387
388    public void setTypeConverterStatisticsEnabled(Boolean typeConverterStatisticsEnabled) {
389        this.typeConverterStatisticsEnabled = typeConverterStatisticsEnabled;
390    }
391
392    public ShutdownRoute getShutdownRoute() {
393        return shutdownRoute;
394    }
395
396    public void setShutdownRoute(ShutdownRoute shutdownRoute) {
397        this.shutdownRoute = shutdownRoute;
398    }
399
400    public ShutdownRunningTask getShutdownRunningTask() {
401        return shutdownRunningTask;
402    }
403
404    public void setShutdownRunningTask(ShutdownRunningTask shutdownRunningTask) {
405        this.shutdownRunningTask = shutdownRunningTask;
406    }
407
408    public CamelPropertyPlaceholderDefinition getCamelPropertyPlaceholder() {
409        return camelPropertyPlaceholder;
410    }
411
412    public void setCamelPropertyPlaceholder(CamelPropertyPlaceholderDefinition camelPropertyPlaceholder) {
413        this.camelPropertyPlaceholder = camelPropertyPlaceholder;
414    }
415
416    public List<RouteContextRefDefinition> getRouteRefs() {
417        return routeRefs;
418    }
419
420    public void setRouteRefs(List<RouteContextRefDefinition> routeRefs) {
421        this.routeRefs = routeRefs;
422    }
423
424    public List<CamelRedeliveryPolicyFactoryBean> getRedeliveryPolicies() {
425        return redeliveryPolicies;
426    }
427
428    public void setRedeliveryPolicies(List<CamelRedeliveryPolicyFactoryBean> redeliveryPolicies) {
429        this.redeliveryPolicies = redeliveryPolicies;
430    }
431
432    public List<ThreadPoolProfileDefinition> getThreadPoolProfiles() {
433        return threadPoolProfiles;
434    }
435
436    public void setThreadPoolProfiles(List<ThreadPoolProfileDefinition> threadPoolProfiles) {
437        this.threadPoolProfiles = threadPoolProfiles;
438    }
439
440    public List<CamelThreadPoolFactoryBean> getThreadPools() {
441        return threadPools;
442    }
443
444    public void setThreadPools(List<CamelThreadPoolFactoryBean> threadPools) {
445        this.threadPools = threadPools;
446    }
447
448    public String getTrace() {
449        return trace;
450    }
451
452    public void setTrace(String trace) {
453        this.trace = trace;
454    }
455
456    public String getMessageHistory() {
457        return messageHistory;
458    }
459
460    public void setMessageHistory(String messageHistory) {
461        this.messageHistory = messageHistory;
462    }
463
464    public String getStreamCache() {
465        return streamCache;
466    }
467
468    public void setStreamCache(String streamCache) {
469        this.streamCache = streamCache;
470    }
471
472    public String getDelayer() {
473        return delayer;
474    }
475
476    public void setDelayer(String delayer) {
477        this.delayer = delayer;
478    }
479
480    public String getHandleFault() {
481        return handleFault;
482    }
483
484    public void setHandleFault(String handleFault) {
485        this.handleFault = handleFault;
486    }
487
488    public String getErrorHandlerRef() {
489        return errorHandlerRef;
490    }
491
492    public void setErrorHandlerRef(String errorHandlerRef) {
493        this.errorHandlerRef = errorHandlerRef;
494    }
495
496    public PropertiesDefinition getProperties() {
497        return properties;
498    }
499
500    public void setProperties(PropertiesDefinition properties) {
501        this.properties = properties;
502    }
503
504    public String[] getPackages() {
505        return packages;
506    }
507
508    public void setPackages(String[] packages) {
509        this.packages = packages;
510    }
511
512    public PackageScanDefinition getPackageScan() {
513        return packageScan;
514    }
515
516    public void setPackageScan(PackageScanDefinition packageScan) {
517        this.packageScan = packageScan;
518    }
519
520    public ContextScanDefinition getContextScan() {
521        return contextScan;
522    }
523
524    public void setContextScan(ContextScanDefinition contextScan) {
525        this.contextScan = contextScan;
526    }
527
528    public CamelJMXAgentDefinition getCamelJMXAgent() {
529        return camelJMXAgent;
530    }
531
532    public void setCamelJMXAgent(CamelJMXAgentDefinition camelJMXAgent) {
533        this.camelJMXAgent = camelJMXAgent;
534    }
535
536    public CamelStreamCachingStrategyDefinition getCamelStreamCachingStrategy() {
537        return camelStreamCachingStrategy;
538    }
539
540    public void setCamelStreamCachingStrategy(CamelStreamCachingStrategyDefinition camelStreamCachingStrategy) {
541        this.camelStreamCachingStrategy = camelStreamCachingStrategy;
542    }
543
544    public List<?> getBeans() {
545        return beans;
546    }
547
548    public void setBeans(List<?> beans) {
549        this.beans = beans;
550    }
551
552    public List<RouteBuilderDefinition> getBuilderRefs() {
553        return builderRefs;
554    }
555
556    public void setBuilderRefs(List<RouteBuilderDefinition> builderRefs) {
557        this.builderRefs = builderRefs;
558    }
559
560    public List<CamelEndpointFactoryBean> getEndpoints() {
561        return endpoints;
562    }
563
564    public void setEndpoints(List<CamelEndpointFactoryBean> endpoints) {
565        this.endpoints = endpoints;
566    }
567
568    public DataFormatsDefinition getDataFormats() {
569        return dataFormats;
570    }
571
572    public void setDataFormats(DataFormatsDefinition dataFormats) {
573        this.dataFormats = dataFormats;
574    }
575
576    public List<OnExceptionDefinition> getOnExceptions() {
577        return onExceptions;
578    }
579
580    public void setOnExceptions(List<OnExceptionDefinition> onExceptions) {
581        this.onExceptions = onExceptions;
582    }
583
584    public List<OnCompletionDefinition> getOnCompletions() {
585        return onCompletions;
586    }
587
588    public void setOnCompletions(List<OnCompletionDefinition> onCompletions) {
589        this.onCompletions = onCompletions;
590    }
591
592    public List<InterceptDefinition> getIntercepts() {
593        return intercepts;
594    }
595
596    public void setIntercepts(List<InterceptDefinition> intercepts) {
597        this.intercepts = intercepts;
598    }
599
600    public List<InterceptFromDefinition> getInterceptFroms() {
601        return interceptFroms;
602    }
603
604    public void setInterceptFroms(List<InterceptFromDefinition> interceptFroms) {
605        this.interceptFroms = interceptFroms;
606    }
607
608    public List<InterceptSendToEndpointDefinition> getInterceptSendToEndpoints() {
609        return interceptSendToEndpoints;
610    }
611
612    public void setInterceptSendToEndpoints(List<InterceptSendToEndpointDefinition> interceptSendToEndpoints) {
613        this.interceptSendToEndpoints = interceptSendToEndpoints;
614    }
615
616    public List<RouteDefinition> getRoutes() {
617        return routes;
618    }
619
620    public void setRoutes(List<RouteDefinition> routes) {
621        this.routes = routes;
622    }
623
624    public boolean isImplicitId() {
625        return implicitId;
626    }
627    
628    public void setImplicitId(boolean flag) {
629        implicitId = flag;
630    }
631
632    public Boolean getUseBlueprintPropertyResolver() {
633        return useBlueprintPropertyResolver;
634    }
635
636    public void setUseBlueprintPropertyResolver(Boolean useBlueprintPropertyResolver) {
637        this.useBlueprintPropertyResolver = useBlueprintPropertyResolver;
638    }
639
640    public boolean isUseBlueprintPropertyResolver() {
641        // enable by default
642        return useBlueprintPropertyResolver == null || useBlueprintPropertyResolver.booleanValue();
643    }
644
645}