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.handler;
018
019import java.lang.reflect.Field;
020import java.lang.reflect.Method;
021import java.lang.reflect.Modifier;
022import java.net.URI;
023import java.net.URISyntaxException;
024import java.net.URL;
025import java.util.Arrays;
026import java.util.HashSet;
027import java.util.List;
028import java.util.Map;
029import java.util.Set;
030import java.util.concurrent.Callable;
031import javax.xml.bind.Binder;
032import javax.xml.bind.JAXBContext;
033import javax.xml.bind.JAXBException;
034
035import org.w3c.dom.Document;
036import org.w3c.dom.Element;
037import org.w3c.dom.NamedNodeMap;
038import org.w3c.dom.Node;
039import org.w3c.dom.NodeList;
040
041import org.apache.aries.blueprint.BeanProcessor;
042import org.apache.aries.blueprint.ComponentDefinitionRegistry;
043import org.apache.aries.blueprint.ComponentDefinitionRegistryProcessor;
044import org.apache.aries.blueprint.NamespaceHandler;
045import org.apache.aries.blueprint.ParserContext;
046import org.apache.aries.blueprint.PassThroughMetadata;
047import org.apache.aries.blueprint.mutable.MutableBeanMetadata;
048import org.apache.aries.blueprint.mutable.MutablePassThroughMetadata;
049import org.apache.aries.blueprint.mutable.MutableRefMetadata;
050import org.apache.aries.blueprint.mutable.MutableReferenceMetadata;
051import org.apache.camel.BeanInject;
052import org.apache.camel.CamelContext;
053import org.apache.camel.Endpoint;
054import org.apache.camel.EndpointInject;
055import org.apache.camel.Produce;
056import org.apache.camel.PropertyInject;
057import org.apache.camel.blueprint.BlueprintCamelContext;
058import org.apache.camel.blueprint.BlueprintModelJAXBContextFactory;
059import org.apache.camel.blueprint.CamelContextFactoryBean;
060import org.apache.camel.blueprint.CamelEndpointFactoryBean;
061import org.apache.camel.blueprint.CamelRestContextFactoryBean;
062import org.apache.camel.blueprint.CamelRouteContextFactoryBean;
063import org.apache.camel.builder.xml.Namespaces;
064import org.apache.camel.component.properties.PropertiesComponent;
065import org.apache.camel.core.xml.AbstractCamelFactoryBean;
066import org.apache.camel.impl.CamelPostProcessorHelper;
067import org.apache.camel.impl.DefaultCamelContextNameStrategy;
068import org.apache.camel.model.AggregateDefinition;
069import org.apache.camel.model.CatchDefinition;
070import org.apache.camel.model.DataFormatDefinition;
071import org.apache.camel.model.ExpressionNode;
072import org.apache.camel.model.ExpressionSubElementDefinition;
073import org.apache.camel.model.FromDefinition;
074import org.apache.camel.model.MarshalDefinition;
075import org.apache.camel.model.OnExceptionDefinition;
076import org.apache.camel.model.ProcessorDefinition;
077import org.apache.camel.model.ResequenceDefinition;
078import org.apache.camel.model.RouteDefinition;
079import org.apache.camel.model.SendDefinition;
080import org.apache.camel.model.SortDefinition;
081import org.apache.camel.model.ToDefinition;
082import org.apache.camel.model.UnmarshalDefinition;
083import org.apache.camel.model.WireTapDefinition;
084import org.apache.camel.model.language.ExpressionDefinition;
085import org.apache.camel.model.rest.RestDefinition;
086import org.apache.camel.model.rest.VerbDefinition;
087import org.apache.camel.spi.CamelContextNameStrategy;
088import org.apache.camel.spi.ComponentResolver;
089import org.apache.camel.spi.DataFormatResolver;
090import org.apache.camel.spi.LanguageResolver;
091import org.apache.camel.spi.NamespaceAware;
092import org.apache.camel.util.ObjectHelper;
093import org.apache.camel.util.URISupport;
094import org.apache.camel.util.blueprint.KeyStoreParametersFactoryBean;
095import org.apache.camel.util.blueprint.SSLContextParametersFactoryBean;
096import org.apache.camel.util.blueprint.SecureRandomParametersFactoryBean;
097import org.apache.camel.util.jsse.KeyStoreParameters;
098import org.apache.camel.util.jsse.SSLContextParameters;
099import org.apache.camel.util.jsse.SecureRandomParameters;
100import org.osgi.framework.Bundle;
101import org.osgi.service.blueprint.container.BlueprintContainer;
102import org.osgi.service.blueprint.container.ComponentDefinitionException;
103import org.osgi.service.blueprint.reflect.BeanMetadata;
104import org.osgi.service.blueprint.reflect.ComponentMetadata;
105import org.osgi.service.blueprint.reflect.Metadata;
106import org.osgi.service.blueprint.reflect.RefMetadata;
107import org.slf4j.Logger;
108import org.slf4j.LoggerFactory;
109
110
111import static org.osgi.service.blueprint.reflect.ComponentMetadata.ACTIVATION_LAZY;
112import static org.osgi.service.blueprint.reflect.ServiceReferenceMetadata.AVAILABILITY_MANDATORY;
113import static org.osgi.service.blueprint.reflect.ServiceReferenceMetadata.AVAILABILITY_OPTIONAL;
114
115
116/**
117 * Camel {@link NamespaceHandler} to parse the Camel related namespaces.
118 */
119public class CamelNamespaceHandler implements NamespaceHandler {
120
121    public static final String BLUEPRINT_NS = "http://camel.apache.org/schema/blueprint";
122    public static final String SPRING_NS = "http://camel.apache.org/schema/spring";
123
124    private static final String CAMEL_CONTEXT = "camelContext";
125    private static final String ROUTE_CONTEXT = "routeContext";
126    private static final String REST_CONTEXT = "restContext";
127    private static final String ENDPOINT = "endpoint";
128    private static final String KEY_STORE_PARAMETERS = "keyStoreParameters";
129    private static final String SECURE_RANDOM_PARAMETERS = "secureRandomParameters";
130    private static final String SSL_CONTEXT_PARAMETERS = "sslContextParameters";
131
132    private static final Logger LOG = LoggerFactory.getLogger(CamelNamespaceHandler.class);
133
134    private JAXBContext jaxbContext;
135
136    /**
137     * Prepares the nodes before parsing.
138     */
139    public static void doBeforeParse(Node node, String fromNamespace, String toNamespace) {
140        if (node.getNodeType() == Node.ELEMENT_NODE) {
141            Document doc = node.getOwnerDocument();
142            if (node.getNamespaceURI().equals(fromNamespace)) {
143                doc.renameNode(node, toNamespace, node.getLocalName());
144            }
145
146            // remove whitespace noise from uri, xxxUri attributes, eg new lines, and tabs etc, which allows end users to format
147            // their Camel routes in more human readable format, but at runtime those attributes must be trimmed
148            // the parser removes most of the noise, but keeps double spaces in the attribute values
149            NamedNodeMap map = node.getAttributes();
150            for (int i = 0; i < map.getLength(); i++) {
151                Node att = map.item(i);
152                if (att.getNodeName().equals("uri") || att.getNodeName().endsWith("Uri")) {
153                    String value = att.getNodeValue();
154                    // remove all double spaces
155                    String changed = value.replaceAll("\\s{2,}", "");
156
157                    if (!value.equals(changed)) {
158                        LOG.debug("Removed whitespace noise from attribute {} -> {}", value, changed);
159                        att.setNodeValue(changed);
160                    }
161                }
162            }
163        }
164        NodeList list = node.getChildNodes();
165        for (int i = 0; i < list.getLength(); ++i) {
166            doBeforeParse(list.item(i), fromNamespace, toNamespace);
167        }
168    }
169
170    public URL getSchemaLocation(String namespace) {
171        return getClass().getClassLoader().getResource("camel-blueprint.xsd");
172    }
173
174    @SuppressWarnings({"unchecked", "rawtypes"})
175    public Set<Class> getManagedClasses() {
176        return new HashSet<Class>(Arrays.asList(BlueprintCamelContext.class));
177    }
178
179    public Metadata parse(Element element, ParserContext context) {
180        LOG.trace("Parsing element {}", element);
181
182        try {
183            // as the camel-core model namespace is Spring we need to rename from blueprint to spring
184            doBeforeParse(element, BLUEPRINT_NS, SPRING_NS);
185
186            if (element.getLocalName().equals(CAMEL_CONTEXT)) {
187                return parseCamelContextNode(element, context);
188            }
189            if (element.getLocalName().equals(ROUTE_CONTEXT)) {
190                return parseRouteContextNode(element, context);
191            }
192            if (element.getLocalName().equals(REST_CONTEXT)) {
193                return parseRestContextNode(element, context);
194            }
195            if (element.getLocalName().equals(ENDPOINT)) {
196                return parseEndpointNode(element, context);
197            }
198            if (element.getLocalName().equals(KEY_STORE_PARAMETERS)) {
199                return parseKeyStoreParametersNode(element, context);
200            }
201            if (element.getLocalName().equals(SECURE_RANDOM_PARAMETERS)) {
202                return parseSecureRandomParametersNode(element, context);
203            }
204            if (element.getLocalName().equals(SSL_CONTEXT_PARAMETERS)) {
205                return parseSSLContextParametersNode(element, context);
206            }
207        } finally {
208            // make sure to rename back so we leave the DOM as-is
209            doBeforeParse(element, SPRING_NS, BLUEPRINT_NS);
210        }
211
212        return null;
213    }
214
215    private Metadata parseCamelContextNode(Element element, ParserContext context) {
216        LOG.trace("Parsing CamelContext {}", element);
217        // Find the id, generate one if needed
218        String contextId = element.getAttribute("id");
219        boolean implicitId = false;
220
221        // let's avoid folks having to explicitly give an ID to a camel context
222        if (ObjectHelper.isEmpty(contextId)) {
223            // if no explicit id was set then use a default auto generated name
224            CamelContextNameStrategy strategy = new DefaultCamelContextNameStrategy();
225            contextId = strategy.getName();
226            element.setAttributeNS(null, "id", contextId);
227            implicitId = true;
228        }
229
230        // now let's parse the routes with JAXB
231        Binder<Node> binder;
232        try {
233            binder = getJaxbContext().createBinder();
234        } catch (JAXBException e) {
235            throw new ComponentDefinitionException("Failed to create the JAXB binder : " + e, e);
236        }
237        Object value = parseUsingJaxb(element, context, binder);
238        if (!(value instanceof CamelContextFactoryBean)) {
239            throw new ComponentDefinitionException("Expected an instance of " + CamelContextFactoryBean.class);
240        }
241
242        CamelContextFactoryBean ccfb = (CamelContextFactoryBean) value;
243        ccfb.setImplicitId(implicitId);
244
245        // The properties component is always used / created by the CamelContextFactoryBean
246        // so we need to ensure that the resolver is ready to use
247        ComponentMetadata propertiesComponentResolver = getComponentResolverReference(context, "properties");
248
249        MutablePassThroughMetadata factory = context.createMetadata(MutablePassThroughMetadata.class);
250        factory.setId(".camelBlueprint.passThrough." + contextId);
251        factory.setObject(new PassThroughCallable<Object>(value));
252
253        MutableBeanMetadata factory2 = context.createMetadata(MutableBeanMetadata.class);
254        factory2.setId(".camelBlueprint.factory." + contextId);
255        factory2.setFactoryComponent(factory);
256        factory2.setFactoryMethod("call");
257        factory2.setInitMethod("afterPropertiesSet");
258        factory2.setDestroyMethod("destroy");
259        factory2.addProperty("blueprintContainer", createRef(context, "blueprintContainer"));
260        factory2.addProperty("bundleContext", createRef(context, "blueprintBundleContext"));
261        factory2.addDependsOn(propertiesComponentResolver.getId());
262        context.getComponentDefinitionRegistry().registerComponentDefinition(factory2);
263
264        MutableBeanMetadata ctx = context.createMetadata(MutableBeanMetadata.class);
265        ctx.setId(contextId);
266        ctx.setRuntimeClass(BlueprintCamelContext.class);
267        ctx.setFactoryComponent(factory2);
268        ctx.setFactoryMethod("getContext");
269        ctx.setInitMethod("init");
270        ctx.setDestroyMethod("destroy");
271
272        // Register factory beans
273        registerBeans(context, contextId, ccfb.getThreadPools());
274        registerBeans(context, contextId, ccfb.getEndpoints());
275        registerBeans(context, contextId, ccfb.getRedeliveryPolicies());
276        registerBeans(context, contextId, ccfb.getBeans());
277
278        // Register processors
279        MutablePassThroughMetadata beanProcessorFactory = context.createMetadata(MutablePassThroughMetadata.class);
280        beanProcessorFactory.setId(".camelBlueprint.processor.bean.passThrough." + contextId);
281        beanProcessorFactory.setObject(new PassThroughCallable<Object>(new CamelInjector(contextId)));
282
283        MutableBeanMetadata beanProcessor = context.createMetadata(MutableBeanMetadata.class);
284        beanProcessor.setId(".camelBlueprint.processor.bean." + contextId);
285        beanProcessor.setRuntimeClass(CamelInjector.class);
286        beanProcessor.setFactoryComponent(beanProcessorFactory);
287        beanProcessor.setFactoryMethod("call");
288        beanProcessor.setProcessor(true);
289        beanProcessor.addProperty("blueprintContainer", createRef(context, "blueprintContainer"));
290        context.getComponentDefinitionRegistry().registerComponentDefinition(beanProcessor);
291
292        MutablePassThroughMetadata regProcessorFactory = context.createMetadata(MutablePassThroughMetadata.class);
293        regProcessorFactory.setId(".camelBlueprint.processor.registry.passThrough." + contextId);
294        regProcessorFactory.setObject(new PassThroughCallable<Object>(new CamelDependenciesFinder(contextId, context)));
295
296        MutableBeanMetadata regProcessor = context.createMetadata(MutableBeanMetadata.class);
297        regProcessor.setId(".camelBlueprint.processor.registry." + contextId);
298        regProcessor.setRuntimeClass(CamelDependenciesFinder.class);
299        regProcessor.setFactoryComponent(regProcessorFactory);
300        regProcessor.setFactoryMethod("call");
301        regProcessor.setProcessor(true);
302        regProcessor.addDependsOn(".camelBlueprint.processor.bean." + contextId);
303        regProcessor.addProperty("blueprintContainer", createRef(context, "blueprintContainer"));
304        context.getComponentDefinitionRegistry().registerComponentDefinition(regProcessor);
305
306        // lets inject the namespaces into any namespace aware POJOs
307        injectNamespaces(element, binder);
308
309        LOG.trace("Parsing CamelContext done, returning {}", ctx);
310        return ctx;
311    }
312
313    protected void injectNamespaces(Element element, Binder<Node> binder) {
314        NodeList list = element.getChildNodes();
315        Namespaces namespaces = null;
316        int size = list.getLength();
317        for (int i = 0; i < size; i++) {
318            Node child = list.item(i);
319            if (child instanceof Element) {
320                Element childElement = (Element) child;
321                Object object = binder.getJAXBNode(child);
322                if (object instanceof NamespaceAware) {
323                    NamespaceAware namespaceAware = (NamespaceAware) object;
324                    if (namespaces == null) {
325                        namespaces = new Namespaces(element);
326                    }
327                    namespaces.configure(namespaceAware);
328                }
329                injectNamespaces(childElement, binder);
330            }
331        }
332    }
333
334    private Metadata parseRouteContextNode(Element element, ParserContext context) {
335        LOG.trace("Parsing RouteContext {}", element);
336        // now parse the routes with JAXB
337        Binder<Node> binder;
338        try {
339            binder = getJaxbContext().createBinder();
340        } catch (JAXBException e) {
341            throw new ComponentDefinitionException("Failed to create the JAXB binder : " + e, e);
342        }
343        Object value = parseUsingJaxb(element, context, binder);
344        if (!(value instanceof CamelRouteContextFactoryBean)) {
345            throw new ComponentDefinitionException("Expected an instance of " + CamelRouteContextFactoryBean.class);
346        }
347
348        CamelRouteContextFactoryBean rcfb = (CamelRouteContextFactoryBean) value;
349        String id = rcfb.getId();
350
351        MutablePassThroughMetadata factory = context.createMetadata(MutablePassThroughMetadata.class);
352        factory.setId(".camelBlueprint.passThrough." + id);
353        factory.setObject(new PassThroughCallable<Object>(rcfb));
354
355        MutableBeanMetadata factory2 = context.createMetadata(MutableBeanMetadata.class);
356        factory2.setId(".camelBlueprint.factory." + id);
357        factory2.setFactoryComponent(factory);
358        factory2.setFactoryMethod("call");
359
360        MutableBeanMetadata ctx = context.createMetadata(MutableBeanMetadata.class);
361        ctx.setId(id);
362        ctx.setRuntimeClass(List.class);
363        ctx.setFactoryComponent(factory2);
364        ctx.setFactoryMethod("getRoutes");
365        // must be lazy as we want CamelContext to be activated first
366        ctx.setActivation(ACTIVATION_LAZY);
367
368        // lets inject the namespaces into any namespace aware POJOs
369        injectNamespaces(element, binder);
370
371        LOG.trace("Parsing RouteContext done, returning {}", element, ctx);
372        return ctx;
373    }
374
375    private Metadata parseRestContextNode(Element element, ParserContext context) {
376        LOG.trace("Parsing RestContext {}", element);
377        // now parse the rests with JAXB
378        Binder<Node> binder;
379        try {
380            binder = getJaxbContext().createBinder();
381        } catch (JAXBException e) {
382            throw new ComponentDefinitionException("Failed to create the JAXB binder : " + e, e);
383        }
384        Object value = parseUsingJaxb(element, context, binder);
385        if (!(value instanceof CamelRestContextFactoryBean)) {
386            throw new ComponentDefinitionException("Expected an instance of " + CamelRestContextFactoryBean.class);
387        }
388
389        CamelRestContextFactoryBean rcfb = (CamelRestContextFactoryBean) value;
390        String id = rcfb.getId();
391
392        MutablePassThroughMetadata factory = context.createMetadata(MutablePassThroughMetadata.class);
393        factory.setId(".camelBlueprint.passThrough." + id);
394        factory.setObject(new PassThroughCallable<Object>(rcfb));
395
396        MutableBeanMetadata factory2 = context.createMetadata(MutableBeanMetadata.class);
397        factory2.setId(".camelBlueprint.factory." + id);
398        factory2.setFactoryComponent(factory);
399        factory2.setFactoryMethod("call");
400
401        MutableBeanMetadata ctx = context.createMetadata(MutableBeanMetadata.class);
402        ctx.setId(id);
403        ctx.setRuntimeClass(List.class);
404        ctx.setFactoryComponent(factory2);
405        ctx.setFactoryMethod("getRests");
406        // must be lazy as we want CamelContext to be activated first
407        ctx.setActivation(ACTIVATION_LAZY);
408
409        // lets inject the namespaces into any namespace aware POJOs
410        injectNamespaces(element, binder);
411
412        LOG.trace("Parsing RestContext done, returning {}", element, ctx);
413        return ctx;
414    }
415
416    private Metadata parseEndpointNode(Element element, ParserContext context) {
417        LOG.trace("Parsing Endpoint {}", element);
418        // now parse the rests with JAXB
419        Binder<Node> binder;
420        try {
421            binder = getJaxbContext().createBinder();
422        } catch (JAXBException e) {
423            throw new ComponentDefinitionException("Failed to create the JAXB binder : " + e, e);
424        }
425        Object value = parseUsingJaxb(element, context, binder);
426        if (!(value instanceof CamelEndpointFactoryBean)) {
427            throw new ComponentDefinitionException("Expected an instance of " + CamelEndpointFactoryBean.class);
428        }
429
430        CamelEndpointFactoryBean rcfb = (CamelEndpointFactoryBean) value;
431        String id = rcfb.getId();
432
433        MutablePassThroughMetadata factory = context.createMetadata(MutablePassThroughMetadata.class);
434        factory.setId(".camelBlueprint.passThrough." + id);
435        factory.setObject(new PassThroughCallable<Object>(rcfb));
436
437        MutableBeanMetadata factory2 = context.createMetadata(MutableBeanMetadata.class);
438        factory2.setId(".camelBlueprint.factory." + id);
439        factory2.setFactoryComponent(factory);
440        factory2.setFactoryMethod("call");
441        factory2.setInitMethod("afterPropertiesSet");
442        factory2.setDestroyMethod("destroy");
443        factory2.addProperty("blueprintContainer", createRef(context, "blueprintContainer"));
444
445        MutableBeanMetadata ctx = context.createMetadata(MutableBeanMetadata.class);
446        ctx.setId(id);
447        ctx.setRuntimeClass(Endpoint.class);
448        ctx.setFactoryComponent(factory2);
449        ctx.setFactoryMethod("getObject");
450        // must be lazy as we want CamelContext to be activated first
451        ctx.setActivation(ACTIVATION_LAZY);
452
453        LOG.trace("Parsing endpoint done, returning {}", element, ctx);
454        return ctx;
455    }
456
457    private Metadata parseKeyStoreParametersNode(Element element, ParserContext context) {
458        LOG.trace("Parsing KeyStoreParameters {}", element);
459        // now parse the key store parameters with JAXB
460        Binder<Node> binder;
461        try {
462            binder = getJaxbContext().createBinder();
463        } catch (JAXBException e) {
464            throw new ComponentDefinitionException("Failed to create the JAXB binder : " + e, e);
465        }
466        Object value = parseUsingJaxb(element, context, binder);
467        if (!(value instanceof KeyStoreParametersFactoryBean)) {
468            throw new ComponentDefinitionException("Expected an instance of " + KeyStoreParametersFactoryBean.class);
469        }
470
471        KeyStoreParametersFactoryBean kspfb = (KeyStoreParametersFactoryBean) value;
472        String id = kspfb.getId();
473
474        MutablePassThroughMetadata factory = context.createMetadata(MutablePassThroughMetadata.class);
475        factory.setId(".camelBlueprint.passThrough." + id);
476        factory.setObject(new PassThroughCallable<Object>(kspfb));
477
478        MutableBeanMetadata factory2 = context.createMetadata(MutableBeanMetadata.class);
479        factory2.setId(".camelBlueprint.factory." + id);
480        factory2.setFactoryComponent(factory);
481        factory2.setFactoryMethod("call");
482        factory2.setInitMethod("afterPropertiesSet");
483        factory2.setDestroyMethod("destroy");
484        factory2.addProperty("blueprintContainer", createRef(context, "blueprintContainer"));
485
486        MutableBeanMetadata ctx = context.createMetadata(MutableBeanMetadata.class);
487        ctx.setId(id);
488        ctx.setRuntimeClass(KeyStoreParameters.class);
489        ctx.setFactoryComponent(factory2);
490        ctx.setFactoryMethod("getObject");
491        // must be lazy as we want CamelContext to be activated first
492        ctx.setActivation(ACTIVATION_LAZY);
493
494        LOG.trace("Parsing KeyStoreParameters done, returning {}", ctx);
495        return ctx;
496    }
497
498    private Metadata parseSecureRandomParametersNode(Element element, ParserContext context) {
499        LOG.trace("Parsing SecureRandomParameters {}", element);
500        // now parse the key store parameters with JAXB
501        Binder<Node> binder;
502        try {
503            binder = getJaxbContext().createBinder();
504        } catch (JAXBException e) {
505            throw new ComponentDefinitionException("Failed to create the JAXB binder : " + e, e);
506        }
507        Object value = parseUsingJaxb(element, context, binder);
508        if (!(value instanceof SecureRandomParametersFactoryBean)) {
509            throw new ComponentDefinitionException("Expected an instance of " + SecureRandomParametersFactoryBean.class);
510        }
511
512        SecureRandomParametersFactoryBean srfb = (SecureRandomParametersFactoryBean) value;
513        String id = srfb.getId();
514
515        MutablePassThroughMetadata factory = context.createMetadata(MutablePassThroughMetadata.class);
516        factory.setId(".camelBlueprint.passThrough." + id);
517        factory.setObject(new PassThroughCallable<Object>(srfb));
518
519        MutableBeanMetadata factory2 = context.createMetadata(MutableBeanMetadata.class);
520        factory2.setId(".camelBlueprint.factory." + id);
521        factory2.setFactoryComponent(factory);
522        factory2.setFactoryMethod("call");
523        factory2.setInitMethod("afterPropertiesSet");
524        factory2.setDestroyMethod("destroy");
525        factory2.addProperty("blueprintContainer", createRef(context, "blueprintContainer"));
526
527        MutableBeanMetadata ctx = context.createMetadata(MutableBeanMetadata.class);
528        ctx.setId(id);
529        ctx.setRuntimeClass(SecureRandomParameters.class);
530        ctx.setFactoryComponent(factory2);
531        ctx.setFactoryMethod("getObject");
532        // must be lazy as we want CamelContext to be activated first
533        ctx.setActivation(ACTIVATION_LAZY);
534
535        LOG.trace("Parsing SecureRandomParameters done, returning {}", ctx);
536        return ctx;
537    }
538
539    private Metadata parseSSLContextParametersNode(Element element, ParserContext context) {
540        LOG.trace("Parsing SSLContextParameters {}", element);
541        // now parse the key store parameters with JAXB
542        Binder<Node> binder;
543        try {
544            binder = getJaxbContext().createBinder();
545        } catch (JAXBException e) {
546            throw new ComponentDefinitionException("Failed to create the JAXB binder : " + e, e);
547        }
548        Object value = parseUsingJaxb(element, context, binder);
549        if (!(value instanceof SSLContextParametersFactoryBean)) {
550            throw new ComponentDefinitionException("Expected an instance of " + SSLContextParametersFactoryBean.class);
551        }
552
553        SSLContextParametersFactoryBean scpfb = (SSLContextParametersFactoryBean) value;
554        String id = scpfb.getId();
555
556        MutablePassThroughMetadata factory = context.createMetadata(MutablePassThroughMetadata.class);
557        factory.setId(".camelBlueprint.passThrough." + id);
558        factory.setObject(new PassThroughCallable<Object>(scpfb));
559
560        MutableBeanMetadata factory2 = context.createMetadata(MutableBeanMetadata.class);
561        factory2.setId(".camelBlueprint.factory." + id);
562        factory2.setFactoryComponent(factory);
563        factory2.setFactoryMethod("call");
564        factory2.setInitMethod("afterPropertiesSet");
565        factory2.setDestroyMethod("destroy");
566        factory2.addProperty("blueprintContainer", createRef(context, "blueprintContainer"));
567
568        MutableBeanMetadata ctx = context.createMetadata(MutableBeanMetadata.class);
569        ctx.setId(id);
570        ctx.setRuntimeClass(SSLContextParameters.class);
571        ctx.setFactoryComponent(factory2);
572        ctx.setFactoryMethod("getObject");
573        // must be lazy as we want CamelContext to be activated first
574        ctx.setActivation(ACTIVATION_LAZY);
575
576        LOG.trace("Parsing SSLContextParameters done, returning {}", ctx);
577        return ctx;
578    }
579
580    private void registerBeans(ParserContext context, String contextId, List<?> beans) {
581        if (beans != null) {
582            for (Object bean : beans) {
583                if (bean instanceof AbstractCamelFactoryBean) {
584                    registerBean(context, contextId, (AbstractCamelFactoryBean<?>) bean);
585                }
586            }
587        }
588    }
589
590    protected void registerBean(ParserContext context, String contextId, AbstractCamelFactoryBean<?> fact) {
591        String id = fact.getId();
592
593        fact.setCamelContextId(contextId);
594
595        MutablePassThroughMetadata eff = context.createMetadata(MutablePassThroughMetadata.class);
596        eff.setId(".camelBlueprint.bean.passthrough." + id);
597        eff.setObject(new PassThroughCallable<Object>(fact));
598
599        MutableBeanMetadata ef = context.createMetadata(MutableBeanMetadata.class);
600        ef.setId(".camelBlueprint.bean.factory." + id);
601        ef.setFactoryComponent(eff);
602        ef.setFactoryMethod("call");
603        ef.addProperty("blueprintContainer", createRef(context, "blueprintContainer"));
604        ef.setInitMethod("afterPropertiesSet");
605        ef.setDestroyMethod("destroy");
606
607        MutableBeanMetadata e = context.createMetadata(MutableBeanMetadata.class);
608        e.setId(id);
609        e.setRuntimeClass(fact.getObjectType());
610        e.setFactoryComponent(ef);
611        e.setFactoryMethod("getObject");
612        e.addDependsOn(".camelBlueprint.processor.bean." + contextId);
613
614        context.getComponentDefinitionRegistry().registerComponentDefinition(e);
615    }
616
617    protected BlueprintContainer getBlueprintContainer(ParserContext context) {
618        PassThroughMetadata ptm = (PassThroughMetadata) context.getComponentDefinitionRegistry().getComponentDefinition("blueprintContainer");
619        return (BlueprintContainer) ptm.getObject();
620    }
621
622    public ComponentMetadata decorate(Node node, ComponentMetadata component, ParserContext context) {
623        return null;
624    }
625
626    protected Object parseUsingJaxb(Element element, ParserContext parserContext, Binder<Node> binder) {
627        try {
628            return binder.unmarshal(element);
629        } catch (JAXBException e) {
630            throw new ComponentDefinitionException("Failed to parse JAXB element: " + e, e);
631        }
632    }
633
634    public JAXBContext getJaxbContext() throws JAXBException {
635        if (jaxbContext == null) {
636            jaxbContext = new BlueprintModelJAXBContextFactory(getClass().getClassLoader()).newJAXBContext();
637        }
638        return jaxbContext;
639    }
640
641    private RefMetadata createRef(ParserContext context, String value) {
642        MutableRefMetadata r = context.createMetadata(MutableRefMetadata.class);
643        r.setComponentId(value);
644        return r;
645    }
646
647    private static ComponentMetadata getDataformatResolverReference(ParserContext context, String dataformat) {
648        ComponentDefinitionRegistry componentDefinitionRegistry = context.getComponentDefinitionRegistry();
649        ComponentMetadata cm = componentDefinitionRegistry.getComponentDefinition(".camelBlueprint.dataformatResolver." + dataformat);
650        if (cm == null) {
651            MutableReferenceMetadata svc = context.createMetadata(MutableReferenceMetadata.class);
652            svc.setId(".camelBlueprint.dataformatResolver." + dataformat);
653            svc.setFilter("(dataformat=" + dataformat + ")");
654            svc.setAvailability(componentDefinitionRegistry.containsComponentDefinition(dataformat) ? AVAILABILITY_OPTIONAL : AVAILABILITY_MANDATORY);
655            try {
656                // Try to set the runtime interface (only with aries blueprint > 0.1
657                svc.getClass().getMethod("setRuntimeInterface", Class.class).invoke(svc, DataFormatResolver.class);
658            } catch (Throwable t) {
659                // Check if the bundle can see the class
660                try {
661                    PassThroughMetadata ptm = (PassThroughMetadata) componentDefinitionRegistry.getComponentDefinition("blueprintBundle");
662                    Bundle b = (Bundle) ptm.getObject();
663                    if (b.loadClass(DataFormatResolver.class.getName()) != DataFormatResolver.class) {
664                        throw new UnsupportedOperationException();
665                    }
666                    svc.setInterface(DataFormatResolver.class.getName());
667                } catch (Throwable t2) {
668                    throw new UnsupportedOperationException();
669                }
670            }
671            componentDefinitionRegistry.registerComponentDefinition(svc);
672            cm = svc;
673        }
674        return cm;
675    }
676
677    private static ComponentMetadata getLanguageResolverReference(ParserContext context, String language) {
678        ComponentDefinitionRegistry componentDefinitionRegistry = context.getComponentDefinitionRegistry();
679        ComponentMetadata cm = componentDefinitionRegistry.getComponentDefinition(".camelBlueprint.languageResolver." + language);
680        if (cm == null) {
681            MutableReferenceMetadata svc = context.createMetadata(MutableReferenceMetadata.class);
682            svc.setId(".camelBlueprint.languageResolver." + language);
683            svc.setFilter("(language=" + language + ")");
684            svc.setAvailability(componentDefinitionRegistry.containsComponentDefinition(language) ? AVAILABILITY_OPTIONAL : AVAILABILITY_MANDATORY);
685            try {
686                // Try to set the runtime interface (only with aries blueprint > 0.1
687                svc.getClass().getMethod("setRuntimeInterface", Class.class).invoke(svc, LanguageResolver.class);
688            } catch (Throwable t) {
689                // Check if the bundle can see the class
690                try {
691                    PassThroughMetadata ptm = (PassThroughMetadata) componentDefinitionRegistry.getComponentDefinition("blueprintBundle");
692                    Bundle b = (Bundle) ptm.getObject();
693                    if (b.loadClass(LanguageResolver.class.getName()) != LanguageResolver.class) {
694                        throw new UnsupportedOperationException();
695                    }
696                    svc.setInterface(LanguageResolver.class.getName());
697                } catch (Throwable t2) {
698                    throw new UnsupportedOperationException();
699                }
700            }
701            componentDefinitionRegistry.registerComponentDefinition(svc);
702            cm = svc;
703        }
704        return cm;
705    }
706
707    private static ComponentMetadata getComponentResolverReference(ParserContext context, String component) {
708        ComponentDefinitionRegistry componentDefinitionRegistry = context.getComponentDefinitionRegistry();
709        ComponentMetadata cm = componentDefinitionRegistry.getComponentDefinition(".camelBlueprint.componentResolver." + component);
710        if (cm == null) {
711            MutableReferenceMetadata svc = context.createMetadata(MutableReferenceMetadata.class);
712            svc.setId(".camelBlueprint.componentResolver." + component);
713            svc.setFilter("(component=" + component + ")");
714            svc.setAvailability(componentDefinitionRegistry.containsComponentDefinition(component) ? AVAILABILITY_OPTIONAL : AVAILABILITY_MANDATORY);
715            try {
716                // Try to set the runtime interface (only with aries blueprint > 0.1
717                svc.getClass().getMethod("setRuntimeInterface", Class.class).invoke(svc, ComponentResolver.class);
718            } catch (Throwable t) {
719                // Check if the bundle can see the class
720                try {
721                    PassThroughMetadata ptm = (PassThroughMetadata) componentDefinitionRegistry.getComponentDefinition("blueprintBundle");
722                    Bundle b = (Bundle) ptm.getObject();
723                    if (b.loadClass(ComponentResolver.class.getName()) != ComponentResolver.class) {
724                        throw new UnsupportedOperationException();
725                    }
726                    svc.setInterface(ComponentResolver.class.getName());
727                } catch (Throwable t2) {
728                    throw new UnsupportedOperationException();
729                }
730            }
731            componentDefinitionRegistry.registerComponentDefinition(svc);
732            cm = svc;
733        }
734        return cm;
735    }
736
737    public static class PassThroughCallable<T> implements Callable<T> {
738
739        private T value;
740
741        public PassThroughCallable(T value) {
742            this.value = value;
743        }
744
745        public T call() throws Exception {
746            return value;
747        }
748    }
749
750    public static class CamelInjector extends CamelPostProcessorHelper implements BeanProcessor {
751
752        private final String camelContextName;
753        private BlueprintContainer blueprintContainer;
754
755        public CamelInjector(String camelContextName) {
756            this.camelContextName = camelContextName;
757        }
758
759        public void setBlueprintContainer(BlueprintContainer blueprintContainer) {
760            this.blueprintContainer = blueprintContainer;
761        }
762
763        @Override
764        public CamelContext getCamelContext() {
765            if (blueprintContainer != null) {
766                CamelContext answer = (CamelContext) blueprintContainer.getComponentInstance(camelContextName);
767                return answer;
768            }
769            return null;
770        }
771
772        public Object beforeInit(Object bean, String beanName, BeanCreator beanCreator, BeanMetadata beanMetadata) {
773            LOG.trace("Before init of bean: {} -> {}", beanName, bean);
774            // prefer to inject later in afterInit
775            return bean;
776        }
777
778        /**
779         * A strategy method to allow implementations to perform some custom JBI
780         * based injection of the POJO
781         *
782         * @param bean the bean to be injected
783         */
784        protected void injectFields(final Object bean, final String beanName) {
785            Class<?> clazz = bean.getClass();
786            do {
787                Field[] fields = clazz.getDeclaredFields();
788                for (Field field : fields) {
789                    PropertyInject propertyInject = field.getAnnotation(PropertyInject.class);
790                    if (propertyInject != null && matchContext(propertyInject.context())) {
791                        injectFieldProperty(field, propertyInject.value(), propertyInject.defaultValue(), bean, beanName);
792                    }
793
794                    BeanInject beanInject = field.getAnnotation(BeanInject.class);
795                    if (beanInject != null && matchContext(beanInject.context())) {
796                        injectFieldBean(field, beanInject.value(), bean, beanName);
797                    }
798
799                    EndpointInject endpointInject = field.getAnnotation(EndpointInject.class);
800                    if (endpointInject != null && matchContext(endpointInject.context())) {
801                        injectField(field, endpointInject.uri(), endpointInject.ref(), endpointInject.property(), bean, beanName);
802                    }
803
804                    Produce produce = field.getAnnotation(Produce.class);
805                    if (produce != null && matchContext(produce.context())) {
806                        injectField(field, produce.uri(), produce.ref(), produce.property(), bean, beanName);
807                    }
808                }
809                clazz = clazz.getSuperclass();
810            } while (clazz != null && clazz != Object.class);
811        }
812
813        protected void injectField(Field field, String endpointUri, String endpointRef, String endpointProperty, Object bean, String beanName) {
814            setField(field, bean, getInjectionValue(field.getType(), endpointUri, endpointRef, endpointProperty, field.getName(), bean, beanName));
815        }
816
817        protected void injectFieldProperty(Field field, String propertyName, String propertyDefaultValue, Object bean, String beanName) {
818            setField(field, bean, getInjectionPropertyValue(field.getType(), propertyName, propertyDefaultValue, field.getName(), bean, beanName));
819        }
820
821        public void injectFieldBean(Field field, String name, Object bean, String beanName) {
822            setField(field, bean, getInjectionBeanValue(field.getType(), name));
823        }
824
825        protected static void setField(Field field, Object instance, Object value) {
826            try {
827                boolean oldAccessible = field.isAccessible();
828                boolean shouldSetAccessible = !Modifier.isPublic(field.getModifiers()) && !oldAccessible;
829                if (shouldSetAccessible) {
830                    field.setAccessible(true);
831                }
832                field.set(instance, value);
833                if (shouldSetAccessible) {
834                    field.setAccessible(oldAccessible);
835                }
836            } catch (IllegalArgumentException ex) {
837                throw new UnsupportedOperationException("Cannot inject value of class: " + value.getClass() + " into: " + field);
838            } catch (IllegalAccessException ex) {
839                throw new IllegalStateException("Could not access method: " + ex.getMessage());
840            }
841        }
842
843        protected void injectMethods(final Object bean, final String beanName) {
844            Class<?> clazz = bean.getClass();
845            do {
846                Method[] methods = clazz.getDeclaredMethods();
847                for (Method method : methods) {
848                    setterInjection(method, bean, beanName);
849                    consumerInjection(method, bean, beanName);
850                }
851                clazz = clazz.getSuperclass();
852            } while (clazz != null && clazz != Object.class);
853        }
854
855        protected void setterInjection(Method method, Object bean, String beanName) {
856            PropertyInject propertyInject = method.getAnnotation(PropertyInject.class);
857            if (propertyInject != null && matchContext(propertyInject.context())) {
858                setterPropertyInjection(method, propertyInject.value(), propertyInject.defaultValue(), bean, beanName);
859            }
860
861            BeanInject beanInject = method.getAnnotation(BeanInject.class);
862            if (beanInject != null && matchContext(beanInject.context())) {
863                setterBeanInjection(method, beanInject.value(), bean, beanName);
864            }
865
866            EndpointInject endpointInject = method.getAnnotation(EndpointInject.class);
867            if (endpointInject != null && matchContext(endpointInject.context())) {
868                setterInjection(method, bean, beanName, endpointInject.uri(), endpointInject.ref(), endpointInject.property());
869            }
870
871            Produce produce = method.getAnnotation(Produce.class);
872            if (produce != null && matchContext(produce.context())) {
873                setterInjection(method, bean, beanName, produce.uri(), produce.ref(), produce.property());
874            }
875        }
876
877        protected void setterPropertyInjection(Method method, String propertyValue, String propertyDefaultValue, Object bean, String beanName) {
878            Class<?>[] parameterTypes = method.getParameterTypes();
879            if (parameterTypes != null) {
880                if (parameterTypes.length != 1) {
881                    LOG.warn("Ignoring badly annotated method for injection due to incorrect number of parameters: " + method);
882                } else {
883                    String propertyName = ObjectHelper.getPropertyName(method);
884                    Object value = getInjectionPropertyValue(parameterTypes[0], propertyValue, propertyDefaultValue, propertyName, bean, beanName);
885                    ObjectHelper.invokeMethod(method, bean, value);
886                }
887            }
888        }
889
890        protected void setterBeanInjection(Method method, String name, Object bean, String beanName) {
891            Class<?>[] parameterTypes = method.getParameterTypes();
892            if (parameterTypes != null) {
893                if (parameterTypes.length != 1) {
894                    LOG.warn("Ignoring badly annotated method for injection due to incorrect number of parameters: " + method);
895                } else {
896                    Object value = getInjectionBeanValue(parameterTypes[0], name);
897                    ObjectHelper.invokeMethod(method, bean, value);
898                }
899            }
900        }
901
902        protected void setterInjection(Method method, Object bean, String beanName, String endpointUri, String endpointRef, String endpointProperty) {
903            Class<?>[] parameterTypes = method.getParameterTypes();
904            if (parameterTypes != null) {
905                if (parameterTypes.length != 1) {
906                    LOG.warn("Ignoring badly annotated method for injection due to incorrect number of parameters: " + method);
907                } else {
908                    String propertyName = ObjectHelper.getPropertyName(method);
909                    Object value = getInjectionValue(parameterTypes[0], endpointUri, endpointRef, endpointProperty, propertyName, bean, beanName);
910                    ObjectHelper.invokeMethod(method, bean, value);
911                }
912            }
913        }
914
915        public Object afterInit(Object bean, String beanName, BeanCreator beanCreator, BeanMetadata beanMetadata) {
916            LOG.trace("After init of bean: {} -> {}", beanName, bean);
917            // we cannot inject CamelContextAware beans as the CamelContext may not be ready
918            injectFields(bean, beanName);
919            injectMethods(bean, beanName);
920            return bean;
921        }
922
923        public void beforeDestroy(Object bean, String beanName) {
924        }
925
926        public void afterDestroy(Object bean, String beanName) {
927        }
928
929        @Override
930        protected boolean isSingleton(Object bean, String beanName) {
931            ComponentMetadata meta = blueprintContainer.getComponentMetadata(beanName);
932            if (meta != null && meta instanceof BeanMetadata) {
933                String scope = ((BeanMetadata) meta).getScope();
934                if (scope != null) {
935                    return BeanMetadata.SCOPE_SINGLETON.equals(scope);
936                }
937            }
938            // fallback to super, which will assume singleton
939            // for beans not implementing Camel's IsSingleton interface
940            return super.isSingleton(bean, beanName);
941        }
942    }
943
944    public static class CamelDependenciesFinder implements ComponentDefinitionRegistryProcessor {
945
946        private final String camelContextName;
947        private final ParserContext context;
948        private BlueprintContainer blueprintContainer;
949
950        public CamelDependenciesFinder(String camelContextName, ParserContext context) {
951            this.camelContextName = camelContextName;
952            this.context = context;
953        }
954
955        public void setBlueprintContainer(BlueprintContainer blueprintContainer) {
956            this.blueprintContainer = blueprintContainer;
957        }
958
959        @SuppressWarnings("deprecation")
960        public void process(ComponentDefinitionRegistry componentDefinitionRegistry) {
961            CamelContextFactoryBean ccfb = (CamelContextFactoryBean) blueprintContainer.getComponentInstance(".camelBlueprint.factory." + camelContextName);
962            CamelContext camelContext = ccfb.getContext();
963
964            Set<String> components = new HashSet<String>();
965            Set<String> languages = new HashSet<String>();
966            Set<String> dataformats = new HashSet<String>();
967
968            // regular camel routes
969            for (RouteDefinition rd : camelContext.getRouteDefinitions()) {
970                findInputComponents(rd.getInputs(), components, languages, dataformats);
971                findOutputComponents(rd.getOutputs(), components, languages, dataformats);
972            }
973
974            // rest services can have embedded routes or a singular to
975            for (RestDefinition rd : camelContext.getRestDefinitions()) {
976                for (VerbDefinition vd : rd.getVerbs()) {
977                    Object o = vd.getToOrRoute();
978                    if (o instanceof RouteDefinition) {
979                        RouteDefinition route = (RouteDefinition) o;
980                        findInputComponents(route.getInputs(), components, languages, dataformats);
981                        findOutputComponents(route.getOutputs(), components, languages, dataformats);
982                    } else if (o instanceof ToDefinition) {
983                        findUriComponent(((ToDefinition) o).getUri(), components);
984                    }
985                }
986            }
987
988            // We can only add service references to resolvers, but we can't make the factory depends on those
989            // because the factory has already been instantiated
990            try {
991                for (String component : components) {
992                    getComponentResolverReference(context, component);
993                }
994                for (String language : languages) {
995                    getLanguageResolverReference(context, language);
996                }
997                for (String dataformat : dataformats) {
998                    getDataformatResolverReference(context, dataformat);
999                }
1000            } catch (UnsupportedOperationException e) {
1001                LOG.warn("Unable to add dependencies to Camel components OSGi services. "
1002                    + "The Apache Aries blueprint implementation used is too old and the blueprint bundle can not see the org.apache.camel.spi package.");
1003                components.clear();
1004                languages.clear();
1005                dataformats.clear();
1006            }
1007
1008        }
1009
1010        private void findInputComponents(List<FromDefinition> defs, Set<String> components, Set<String> languages, Set<String> dataformats) {
1011            if (defs != null) {
1012                for (FromDefinition def : defs) {
1013                    findUriComponent(def.getUri(), components);
1014                    findSchedulerUriComponent(def.getUri(), components);
1015                }
1016            }
1017        }
1018
1019        @SuppressWarnings({"rawtypes"})
1020        private void findOutputComponents(List<ProcessorDefinition<?>> defs, Set<String> components, Set<String> languages, Set<String> dataformats) {
1021            if (defs != null) {
1022                for (ProcessorDefinition<?> def : defs) {
1023                    if (def instanceof SendDefinition) {
1024                        findUriComponent(((SendDefinition) def).getUri(), components);
1025                    }
1026                    if (def instanceof MarshalDefinition) {
1027                        findDataFormat(((MarshalDefinition) def).getDataFormatType(), dataformats);
1028                    }
1029                    if (def instanceof UnmarshalDefinition) {
1030                        findDataFormat(((UnmarshalDefinition) def).getDataFormatType(), dataformats);
1031                    }
1032                    if (def instanceof ExpressionNode) {
1033                        findLanguage(((ExpressionNode) def).getExpression(), languages);
1034                    }
1035                    if (def instanceof ResequenceDefinition) {
1036                        findLanguage(((ResequenceDefinition) def).getExpression(), languages);
1037                    }
1038                    if (def instanceof AggregateDefinition) {
1039                        findLanguage(((AggregateDefinition) def).getExpression(), languages);
1040                        findLanguage(((AggregateDefinition) def).getCorrelationExpression(), languages);
1041                        findLanguage(((AggregateDefinition) def).getCompletionPredicate(), languages);
1042                        findLanguage(((AggregateDefinition) def).getCompletionTimeoutExpression(), languages);
1043                        findLanguage(((AggregateDefinition) def).getCompletionSizeExpression(), languages);
1044                    }
1045                    if (def instanceof CatchDefinition) {
1046                        findLanguage(((CatchDefinition) def).getHandled(), languages);
1047                    }
1048                    if (def instanceof OnExceptionDefinition) {
1049                        findLanguage(((OnExceptionDefinition) def).getRetryWhile(), languages);
1050                        findLanguage(((OnExceptionDefinition) def).getHandled(), languages);
1051                        findLanguage(((OnExceptionDefinition) def).getContinued(), languages);
1052                    }
1053                    if (def instanceof SortDefinition) {
1054                        findLanguage(((SortDefinition) def).getExpression(), languages);
1055                    }
1056                    if (def instanceof WireTapDefinition) {
1057                        findLanguage(((WireTapDefinition<?>) def).getNewExchangeExpression(), languages);
1058                    }
1059                    findOutputComponents(def.getOutputs(), components, languages, dataformats);
1060                }
1061            }
1062        }
1063
1064        private void findLanguage(ExpressionDefinition expression, Set<String> languages) {
1065            if (expression != null) {
1066                String lang = expression.getLanguage();
1067                if (lang != null && lang.length() > 0) {
1068                    languages.add(lang);
1069                }
1070            }
1071        }
1072
1073        private void findLanguage(ExpressionSubElementDefinition expression, Set<String> languages) {
1074            if (expression != null) {
1075                findLanguage(expression.getExpressionType(), languages);
1076            }
1077        }
1078
1079        private void findDataFormat(DataFormatDefinition dfd, Set<String> dataformats) {
1080            if (dfd != null && dfd.getDataFormatName() != null) {
1081                dataformats.add(dfd.getDataFormatName());
1082            }
1083        }
1084
1085        private void findUriComponent(String uri, Set<String> components) {
1086            // if the uri is a placeholder then skip it
1087            if (uri != null && uri.startsWith(PropertiesComponent.DEFAULT_PREFIX_TOKEN)) {
1088                return;
1089            }
1090
1091            if (uri != null) {
1092                String splitURI[] = ObjectHelper.splitOnCharacter(uri, ":", 2);
1093                if (splitURI[1] != null) {
1094                    String scheme = splitURI[0];
1095                    components.add(scheme);
1096                }
1097            }
1098        }
1099
1100        private void findSchedulerUriComponent(String uri, Set<String> components) {
1101
1102            // the input may use a scheduler which can be quartz or spring
1103            if (uri != null) {
1104                try {
1105                    URI u = new URI(uri);
1106                    Map<String, Object> parameters = URISupport.parseParameters(u);
1107                    Object value = parameters.get("scheduler");
1108                    if (value == null) {
1109                        value = parameters.get("consumer.scheduler");
1110                    }
1111                    if (value != null) {
1112                        // the scheduler can be quartz2 or spring based, so add reference to camel component
1113                        // from these components os blueprint knows about the requirement
1114                        String name = value.toString();
1115                        if ("quartz2".equals(name)) {
1116                            components.add("quartz2");
1117                        } else if ("spring".equals(name)) {
1118                            components.add("spring-event");
1119                        }
1120                    }
1121                } catch (URISyntaxException e) {
1122                    // ignore
1123                }
1124            }
1125        }
1126
1127    }
1128
1129}