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.aries.blueprint.ExtendedBlueprintContainer;
032import org.apache.camel.RoutesBuilder;
033import org.apache.camel.ShutdownRoute;
034import org.apache.camel.ShutdownRunningTask;
035import org.apache.camel.builder.RouteBuilder;
036import org.apache.camel.component.properties.PropertiesComponent;
037import org.apache.camel.core.osgi.OsgiCamelContextPublisher;
038import org.apache.camel.core.osgi.OsgiEventAdminNotifier;
039import org.apache.camel.core.osgi.utils.BundleDelegatingClassLoader;
040import org.apache.camel.core.xml.AbstractCamelContextFactoryBean;
041import org.apache.camel.core.xml.CamelJMXAgentDefinition;
042import org.apache.camel.core.xml.CamelPropertyPlaceholderDefinition;
043import org.apache.camel.core.xml.CamelServiceExporterDefinition;
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 streamCache = "false";
084    @XmlAttribute(required = false)
085    private String delayer;
086    @XmlAttribute(required = false)
087    private String handleFault;
088    @XmlAttribute(required = false)
089    private String errorHandlerRef;
090    @XmlAttribute(required = false)
091    private String autoStartup = "true";
092    @XmlAttribute(required = false)
093    private String useMDCLogging;
094    @XmlAttribute(required = false)
095    private String useBreadcrumb;
096    @XmlAttribute(required = false)
097    private String managementNamePattern;
098    @XmlAttribute(required = false)
099    private Boolean useBlueprintPropertyResolver;
100    @XmlAttribute(required = false)
101    private ShutdownRoute shutdownRoute;
102    @XmlAttribute(required = false)
103    private ShutdownRunningTask shutdownRunningTask;
104    @XmlAttribute(required = false)
105    @Deprecated
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 = CamelProxyFactoryBean.class, required = false),
123        @XmlElement(name = "export", type = CamelServiceExporterDefinition.class, required = false),
124        @XmlElement(name = "errorHandler", type = CamelErrorHandlerFactoryBean.class, required = false)
125    })
126    private List<?> beans;
127    @XmlElement(name = "routeBuilder", required = false)
128    private List<RouteBuilderDefinition> builderRefs = new ArrayList<RouteBuilderDefinition>();
129    @XmlElement(name = "routeContextRef", required = false)
130    private List<RouteContextRefDefinition> routeRefs = new ArrayList<RouteContextRefDefinition>();
131    @XmlElement(name = "threadPoolProfile", required = false)
132    private List<ThreadPoolProfileDefinition> threadPoolProfiles;
133    @XmlElement(name = "threadPool", required = false)
134    private List<CamelThreadPoolFactoryBean> threadPools;
135    @XmlElement(name = "endpoint", required = false)
136    private List<CamelEndpointFactoryBean> endpoints;
137    @XmlElement(name = "dataFormats", required = false)
138    private DataFormatsDefinition dataFormats;
139    @XmlElement(name = "redeliveryPolicyProfile", required = false)
140    private List<CamelRedeliveryPolicyFactoryBean> redeliveryPolicies;
141    @XmlElement(name = "onException", required = false)
142    private List<OnExceptionDefinition> onExceptions = new ArrayList<OnExceptionDefinition>();
143    @XmlElement(name = "onCompletion", required = false)
144    private List<OnCompletionDefinition> onCompletions = new ArrayList<OnCompletionDefinition>();
145    @XmlElement(name = "intercept", required = false)
146    private List<InterceptDefinition> intercepts = new ArrayList<InterceptDefinition>();
147    @XmlElement(name = "interceptFrom", required = false)
148    private List<InterceptFromDefinition> interceptFroms = new ArrayList<InterceptFromDefinition>();
149    @XmlElement(name = "interceptSendToEndpoint", required = false)
150    private List<InterceptSendToEndpointDefinition> interceptSendToEndpoints = new ArrayList<InterceptSendToEndpointDefinition>();
151    @XmlElement(name = "route", required = false)
152    private List<RouteDefinition> routes = new ArrayList<RouteDefinition>();
153    @XmlTransient
154    private BlueprintCamelContext context;
155    @XmlTransient
156    private BlueprintContainer blueprintContainer;
157    @XmlTransient
158    private BundleContext bundleContext;
159    @XmlTransient
160    private boolean implicitId;
161
162
163    public Class<BlueprintCamelContext> getObjectType() {
164        return BlueprintCamelContext.class;
165    }
166
167    @Override
168    public BlueprintCamelContext getContext(boolean create) {
169        if (context == null && create) {
170            context = createContext();
171            if (!isImplicitId()) {
172                context.setName(getId());
173            }
174        }
175        return context;
176    }
177
178    public void setBlueprintContainer(BlueprintContainer blueprintContainer) {
179        this.blueprintContainer = blueprintContainer;
180    }
181
182    public void setBundleContext(BundleContext bundleContext) {
183        this.bundleContext = bundleContext;
184    }
185
186    protected BlueprintCamelContext createContext() {
187        return new BlueprintCamelContext(bundleContext, blueprintContainer);
188    }
189
190    @Override
191    protected void initCustomRegistry(BlueprintCamelContext context) {
192        Registry registry = getBeanForType(Registry.class);
193        if (registry != null) {
194            LOG.info("Using custom Registry: " + registry);
195            context.setRegistry(registry);
196        }
197    }
198
199    @Override
200    protected <S> S getBeanForType(Class<S> clazz) {
201        Collection<S> objects = BlueprintContainerRegistry.lookupByType(blueprintContainer, clazz).values();
202        if (objects.size() == 1) {
203            return objects.iterator().next();
204        }
205        return null;
206    }
207
208    @Override
209    protected void initPropertyPlaceholder() throws Exception {
210        super.initPropertyPlaceholder();
211
212        // if blueprint property resolver is enabled on CamelContext then bridge PropertiesComponent to blueprint
213        if (isUseBlueprintPropertyResolver()) {
214            // lookup existing configured properties component
215            PropertiesComponent pc = getContext().getComponent("properties", PropertiesComponent.class);
216
217            BlueprintPropertiesParser parser = new BlueprintPropertiesParser(pc, blueprintContainer, pc.getPropertiesParser());
218            BlueprintPropertiesResolver resolver = new BlueprintPropertiesResolver(pc.getPropertiesResolver(), parser);
219
220            // any extra properties
221            ServiceReference ref = bundleContext.getServiceReference(PropertiesComponent.OVERRIDE_PROPERTIES);
222            if (ref != null) {
223                Properties extra = (Properties) bundleContext.getService(ref);
224                if (extra != null) {
225                    pc.setOverrideProperties(extra);
226                }
227            }
228
229            // no locations has been set, so its a default component
230            if (pc.getLocations() == null) {
231                StringBuilder sb = new StringBuilder();
232                String[] ids = parser.lookupPropertyPlaceholderIds();
233                for (String id : ids) {
234                    sb.append("blueprint:").append(id).append(",");
235                }
236                if (sb.length() > 0) {
237                    // location supports multiple separated by comma
238                    pc.setLocation(sb.toString());
239                }
240            }
241
242            if (pc.getLocations() != null) {
243                // bridge camel properties with blueprint
244                pc.setPropertiesParser(parser);
245                pc.setPropertiesResolver(resolver);
246            }
247        }
248    }
249
250    @Override
251    protected void initBeanPostProcessor(BlueprintCamelContext context) {
252    }
253
254    @Override
255    protected void postProcessBeforeInit(RouteBuilder builder) {
256    }
257
258    @Override
259    protected void findRouteBuildersByPackageScan(String[] packages, PackageScanFilter filter, List<RoutesBuilder> builders) throws Exception {
260        // add filter to class resolver which then will filter
261        getContext().getPackageScanClassResolver().addFilter(filter);
262        ClassLoader classLoader = new BundleDelegatingClassLoader(((ExtendedBlueprintContainer) blueprintContainer).getBundleContext().getBundle());
263        PackageScanRouteBuilderFinder finder = new PackageScanRouteBuilderFinder(getContext(), packages, classLoader,
264                                                                                 getContext().getPackageScanClassResolver());
265        finder.appendBuilders(builders);
266
267        // and remove the filter
268        getContext().getPackageScanClassResolver().removeFilter(filter);
269    }
270
271    @Override
272    protected void findRouteBuildersByContextScan(PackageScanFilter filter, List<RoutesBuilder> builders) throws Exception {
273        ContextScanRouteBuilderFinder finder = new ContextScanRouteBuilderFinder(getContext(), filter);
274        finder.appendBuilders(builders);
275    }
276
277    @Override
278    public void afterPropertiesSet() throws Exception {
279        super.afterPropertiesSet();
280        // setup the application context classloader with the bundle delegating classloader
281        ClassLoader cl = new BundleDelegatingClassLoader(((ExtendedBlueprintContainer) blueprintContainer).getBundleContext().getBundle());
282        LOG.debug("Set the application context classloader to: {}", cl);
283        getContext().setApplicationContextClassLoader(cl);
284        getContext().getManagementStrategy().addEventNotifier(new OsgiCamelContextPublisher(bundleContext));
285        try {
286            getClass().getClassLoader().loadClass("org.osgi.service.event.EventAdmin");
287            getContext().getManagementStrategy().addEventNotifier(new OsgiEventAdminNotifier(bundleContext));
288        } catch (Throwable t) {
289            // Ignore, if the EventAdmin package is not available, just don't use it
290            LOG.debug("EventAdmin package is not available, just don't use it");
291        }
292    }
293
294    public String getDependsOn() {
295        return dependsOn;
296    }
297
298    public void setDependsOn(String dependsOn) {
299        this.dependsOn = dependsOn;
300    }
301
302    public String getAutoStartup() {
303        return autoStartup;
304    }
305
306    public void setAutoStartup(String autoStartup) {
307        this.autoStartup = autoStartup;
308    }
309
310    public String getUseMDCLogging() {
311        return useMDCLogging;
312    }
313
314    public void setUseMDCLogging(String useMDCLogging) {
315        this.useMDCLogging = useMDCLogging;
316    }
317
318    public String getUseBreadcrumb() {
319        return useBreadcrumb;
320    }
321
322    public void setUseBreadcrumb(String useBreadcrumb) {
323        this.useBreadcrumb = useBreadcrumb;
324    }
325
326    public String getManagementNamePattern() {
327        return managementNamePattern;
328    }
329
330    public void setManagementNamePattern(String managementNamePattern) {
331        this.managementNamePattern = managementNamePattern;
332    }
333
334    @Deprecated
335    public Boolean getLazyLoadTypeConverters() {
336        // use false by default
337        return lazyLoadTypeConverters != null ? lazyLoadTypeConverters : Boolean.FALSE;
338    }
339
340    @Deprecated
341    public void setLazyLoadTypeConverters(Boolean lazyLoadTypeConverters) {
342        this.lazyLoadTypeConverters = lazyLoadTypeConverters;
343    }
344
345    public ShutdownRoute getShutdownRoute() {
346        return shutdownRoute;
347    }
348
349    public void setShutdownRoute(ShutdownRoute shutdownRoute) {
350        this.shutdownRoute = shutdownRoute;
351    }
352
353    public ShutdownRunningTask getShutdownRunningTask() {
354        return shutdownRunningTask;
355    }
356
357    public void setShutdownRunningTask(ShutdownRunningTask shutdownRunningTask) {
358        this.shutdownRunningTask = shutdownRunningTask;
359    }
360
361    public CamelPropertyPlaceholderDefinition getCamelPropertyPlaceholder() {
362        return camelPropertyPlaceholder;
363    }
364
365    public void setCamelPropertyPlaceholder(CamelPropertyPlaceholderDefinition camelPropertyPlaceholder) {
366        this.camelPropertyPlaceholder = camelPropertyPlaceholder;
367    }
368
369    public List<RouteContextRefDefinition> getRouteRefs() {
370        return routeRefs;
371    }
372
373    public void setRouteRefs(List<RouteContextRefDefinition> routeRefs) {
374        this.routeRefs = routeRefs;
375    }
376
377    public List<CamelRedeliveryPolicyFactoryBean> getRedeliveryPolicies() {
378        return redeliveryPolicies;
379    }
380
381    public void setRedeliveryPolicies(List<CamelRedeliveryPolicyFactoryBean> redeliveryPolicies) {
382        this.redeliveryPolicies = redeliveryPolicies;
383    }
384
385    public List<ThreadPoolProfileDefinition> getThreadPoolProfiles() {
386        return threadPoolProfiles;
387    }
388
389    public void setThreadPoolProfiles(List<ThreadPoolProfileDefinition> threadPoolProfiles) {
390        this.threadPoolProfiles = threadPoolProfiles;
391    }
392
393    public List<CamelThreadPoolFactoryBean> getThreadPools() {
394        return threadPools;
395    }
396
397    public void setThreadPools(List<CamelThreadPoolFactoryBean> threadPools) {
398        this.threadPools = threadPools;
399    }
400
401    public String getTrace() {
402        return trace;
403    }
404
405    public void setTrace(String trace) {
406        this.trace = trace;
407    }
408
409    public String getStreamCache() {
410        return streamCache;
411    }
412
413    public void setStreamCache(String streamCache) {
414        this.streamCache = streamCache;
415    }
416
417    public String getDelayer() {
418        return delayer;
419    }
420
421    public void setDelayer(String delayer) {
422        this.delayer = delayer;
423    }
424
425    public String getHandleFault() {
426        return handleFault;
427    }
428
429    public void setHandleFault(String handleFault) {
430        this.handleFault = handleFault;
431    }
432
433    public String getErrorHandlerRef() {
434        return errorHandlerRef;
435    }
436
437    public void setErrorHandlerRef(String errorHandlerRef) {
438        this.errorHandlerRef = errorHandlerRef;
439    }
440
441    public PropertiesDefinition getProperties() {
442        return properties;
443    }
444
445    public void setProperties(PropertiesDefinition properties) {
446        this.properties = properties;
447    }
448
449    public String[] getPackages() {
450        return packages;
451    }
452
453    public void setPackages(String[] packages) {
454        this.packages = packages;
455    }
456
457    public PackageScanDefinition getPackageScan() {
458        return packageScan;
459    }
460
461    public void setPackageScan(PackageScanDefinition packageScan) {
462        this.packageScan = packageScan;
463    }
464
465    public ContextScanDefinition getContextScan() {
466        return contextScan;
467    }
468
469    public void setContextScan(ContextScanDefinition contextScan) {
470        this.contextScan = contextScan;
471    }
472
473    public CamelJMXAgentDefinition getCamelJMXAgent() {
474        return camelJMXAgent;
475    }
476
477    public void setCamelJMXAgent(CamelJMXAgentDefinition camelJMXAgent) {
478        this.camelJMXAgent = camelJMXAgent;
479    }
480
481    public List<?> getBeans() {
482        return beans;
483    }
484
485    public void setBeans(List<?> beans) {
486        this.beans = beans;
487    }
488
489    public List<RouteBuilderDefinition> getBuilderRefs() {
490        return builderRefs;
491    }
492
493    public void setBuilderRefs(List<RouteBuilderDefinition> builderRefs) {
494        this.builderRefs = builderRefs;
495    }
496
497    public List<CamelEndpointFactoryBean> getEndpoints() {
498        return endpoints;
499    }
500
501    public void setEndpoints(List<CamelEndpointFactoryBean> endpoints) {
502        this.endpoints = endpoints;
503    }
504
505    public DataFormatsDefinition getDataFormats() {
506        return dataFormats;
507    }
508
509    public void setDataFormats(DataFormatsDefinition dataFormats) {
510        this.dataFormats = dataFormats;
511    }
512
513    public List<OnExceptionDefinition> getOnExceptions() {
514        return onExceptions;
515    }
516
517    public void setOnExceptions(List<OnExceptionDefinition> onExceptions) {
518        this.onExceptions = onExceptions;
519    }
520
521    public List<OnCompletionDefinition> getOnCompletions() {
522        return onCompletions;
523    }
524
525    public void setOnCompletions(List<OnCompletionDefinition> onCompletions) {
526        this.onCompletions = onCompletions;
527    }
528
529    public List<InterceptDefinition> getIntercepts() {
530        return intercepts;
531    }
532
533    public void setIntercepts(List<InterceptDefinition> intercepts) {
534        this.intercepts = intercepts;
535    }
536
537    public List<InterceptFromDefinition> getInterceptFroms() {
538        return interceptFroms;
539    }
540
541    public void setInterceptFroms(List<InterceptFromDefinition> interceptFroms) {
542        this.interceptFroms = interceptFroms;
543    }
544
545    public List<InterceptSendToEndpointDefinition> getInterceptSendToEndpoints() {
546        return interceptSendToEndpoints;
547    }
548
549    public void setInterceptSendToEndpoints(List<InterceptSendToEndpointDefinition> interceptSendToEndpoints) {
550        this.interceptSendToEndpoints = interceptSendToEndpoints;
551    }
552
553    public List<RouteDefinition> getRoutes() {
554        return routes;
555    }
556
557    public void setRoutes(List<RouteDefinition> routes) {
558        this.routes = routes;
559    }
560
561    public boolean isImplicitId() {
562        return implicitId;
563    }
564    
565    public void setImplicitId(boolean flag) {
566        implicitId = flag;
567    }
568
569    public Boolean getUseBlueprintPropertyResolver() {
570        return useBlueprintPropertyResolver;
571    }
572
573    public void setUseBlueprintPropertyResolver(Boolean useBlueprintPropertyResolver) {
574        this.useBlueprintPropertyResolver = useBlueprintPropertyResolver;
575    }
576
577    public boolean isUseBlueprintPropertyResolver() {
578        // enable by default
579        return useBlueprintPropertyResolver == null || useBlueprintPropertyResolver.booleanValue();
580    }
581
582}