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.ToDynamicDefinition;
083import org.apache.camel.model.UnmarshalDefinition;
084import org.apache.camel.model.WireTapDefinition;
085import org.apache.camel.model.language.ExpressionDefinition;
086import org.apache.camel.model.rest.RestBindingMode;
087import org.apache.camel.model.rest.RestDefinition;
088import org.apache.camel.model.rest.VerbDefinition;
089import org.apache.camel.spi.CamelContextNameStrategy;
090import org.apache.camel.spi.ComponentResolver;
091import org.apache.camel.spi.DataFormatResolver;
092import org.apache.camel.spi.LanguageResolver;
093import org.apache.camel.spi.NamespaceAware;
094import org.apache.camel.util.ObjectHelper;
095import org.apache.camel.util.URISupport;
096import org.apache.camel.util.blueprint.KeyStoreParametersFactoryBean;
097import org.apache.camel.util.blueprint.SSLContextParametersFactoryBean;
098import org.apache.camel.util.blueprint.SecureRandomParametersFactoryBean;
099import org.apache.camel.util.jsse.KeyStoreParameters;
100import org.apache.camel.util.jsse.SSLContextParameters;
101import org.apache.camel.util.jsse.SecureRandomParameters;
102import org.osgi.framework.Bundle;
103import org.osgi.service.blueprint.container.BlueprintContainer;
104import org.osgi.service.blueprint.container.ComponentDefinitionException;
105import org.osgi.service.blueprint.reflect.BeanMetadata;
106import org.osgi.service.blueprint.reflect.ComponentMetadata;
107import org.osgi.service.blueprint.reflect.Metadata;
108import org.osgi.service.blueprint.reflect.RefMetadata;
109import org.slf4j.Logger;
110import org.slf4j.LoggerFactory;
111
112import static org.osgi.service.blueprint.reflect.ComponentMetadata.ACTIVATION_LAZY;
113import static org.osgi.service.blueprint.reflect.ServiceReferenceMetadata.AVAILABILITY_MANDATORY;
114import static org.osgi.service.blueprint.reflect.ServiceReferenceMetadata.AVAILABILITY_OPTIONAL;
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        // We need to add other components which the camel context dependsOn
263        if (ObjectHelper.isNotEmpty(ccfb.getDependsOn())) {
264            factory2.setDependsOn(Arrays.asList(ccfb.getDependsOn().split(" |,")));
265        }
266        context.getComponentDefinitionRegistry().registerComponentDefinition(factory2);
267
268        MutableBeanMetadata ctx = context.createMetadata(MutableBeanMetadata.class);
269        ctx.setId(contextId);
270        ctx.setRuntimeClass(BlueprintCamelContext.class);
271        ctx.setFactoryComponent(factory2);
272        ctx.setFactoryMethod("getContext");
273        ctx.setInitMethod("init");
274        ctx.setDestroyMethod("destroy");
275
276        // Register factory beans
277        registerBeans(context, contextId, ccfb.getThreadPools());
278        registerBeans(context, contextId, ccfb.getEndpoints());
279        registerBeans(context, contextId, ccfb.getRedeliveryPolicies());
280        registerBeans(context, contextId, ccfb.getBeans());
281
282        // Register processors
283        MutablePassThroughMetadata beanProcessorFactory = context.createMetadata(MutablePassThroughMetadata.class);
284        beanProcessorFactory.setId(".camelBlueprint.processor.bean.passThrough." + contextId);
285        beanProcessorFactory.setObject(new PassThroughCallable<Object>(new CamelInjector(contextId)));
286
287        MutableBeanMetadata beanProcessor = context.createMetadata(MutableBeanMetadata.class);
288        beanProcessor.setId(".camelBlueprint.processor.bean." + contextId);
289        beanProcessor.setRuntimeClass(CamelInjector.class);
290        beanProcessor.setFactoryComponent(beanProcessorFactory);
291        beanProcessor.setFactoryMethod("call");
292        beanProcessor.setProcessor(true);
293        beanProcessor.addProperty("blueprintContainer", createRef(context, "blueprintContainer"));
294        context.getComponentDefinitionRegistry().registerComponentDefinition(beanProcessor);
295
296        MutablePassThroughMetadata regProcessorFactory = context.createMetadata(MutablePassThroughMetadata.class);
297        regProcessorFactory.setId(".camelBlueprint.processor.registry.passThrough." + contextId);
298        regProcessorFactory.setObject(new PassThroughCallable<Object>(new CamelDependenciesFinder(contextId, context)));
299
300        MutableBeanMetadata regProcessor = context.createMetadata(MutableBeanMetadata.class);
301        regProcessor.setId(".camelBlueprint.processor.registry." + contextId);
302        regProcessor.setRuntimeClass(CamelDependenciesFinder.class);
303        regProcessor.setFactoryComponent(regProcessorFactory);
304        regProcessor.setFactoryMethod("call");
305        regProcessor.setProcessor(true);
306        regProcessor.addDependsOn(".camelBlueprint.processor.bean." + contextId);
307        regProcessor.addProperty("blueprintContainer", createRef(context, "blueprintContainer"));
308        context.getComponentDefinitionRegistry().registerComponentDefinition(regProcessor);
309
310        // lets inject the namespaces into any namespace aware POJOs
311        injectNamespaces(element, binder);
312
313        LOG.trace("Parsing CamelContext done, returning {}", ctx);
314        return ctx;
315    }
316
317    protected void injectNamespaces(Element element, Binder<Node> binder) {
318        NodeList list = element.getChildNodes();
319        Namespaces namespaces = null;
320        int size = list.getLength();
321        for (int i = 0; i < size; i++) {
322            Node child = list.item(i);
323            if (child instanceof Element) {
324                Element childElement = (Element) child;
325                Object object = binder.getJAXBNode(child);
326                if (object instanceof NamespaceAware) {
327                    NamespaceAware namespaceAware = (NamespaceAware) object;
328                    if (namespaces == null) {
329                        namespaces = new Namespaces(element);
330                    }
331                    namespaces.configure(namespaceAware);
332                }
333                injectNamespaces(childElement, binder);
334            }
335        }
336    }
337
338    private Metadata parseRouteContextNode(Element element, ParserContext context) {
339        LOG.trace("Parsing RouteContext {}", element);
340        // now parse the routes with JAXB
341        Binder<Node> binder;
342        try {
343            binder = getJaxbContext().createBinder();
344        } catch (JAXBException e) {
345
346            throw new ComponentDefinitionException("Failed to create the JAXB binder : " + e, e);
347        }
348        Object value = parseUsingJaxb(element, context, binder);
349        if (!(value instanceof CamelRouteContextFactoryBean)) {
350            throw new ComponentDefinitionException("Expected an instance of " + CamelRouteContextFactoryBean.class);
351        }
352
353        CamelRouteContextFactoryBean rcfb = (CamelRouteContextFactoryBean) value;
354        String id = rcfb.getId();
355
356        MutablePassThroughMetadata factory = context.createMetadata(MutablePassThroughMetadata.class);
357        factory.setId(".camelBlueprint.passThrough." + id);
358        factory.setObject(new PassThroughCallable<Object>(rcfb));
359
360        MutableBeanMetadata factory2 = context.createMetadata(MutableBeanMetadata.class);
361        factory2.setId(".camelBlueprint.factory." + id);
362        factory2.setFactoryComponent(factory);
363        factory2.setFactoryMethod("call");
364
365        MutableBeanMetadata ctx = context.createMetadata(MutableBeanMetadata.class);
366        ctx.setId(id);
367        ctx.setRuntimeClass(List.class);
368        ctx.setFactoryComponent(factory2);
369        ctx.setFactoryMethod("getRoutes");
370        // must be lazy as we want CamelContext to be activated first
371        ctx.setActivation(ACTIVATION_LAZY);
372
373        // lets inject the namespaces into any namespace aware POJOs
374        injectNamespaces(element, binder);
375
376        LOG.trace("Parsing RouteContext done, returning {}", element, ctx);
377        return ctx;
378    }
379
380    private Metadata parseRestContextNode(Element element, ParserContext context) {
381        LOG.trace("Parsing RestContext {}", element);
382        // now parse the rests with JAXB
383        Binder<Node> binder;
384        try {
385            binder = getJaxbContext().createBinder();
386        } catch (JAXBException e) {
387            throw new ComponentDefinitionException("Failed to create the JAXB binder : " + e, e);
388        }
389        Object value = parseUsingJaxb(element, context, binder);
390        if (!(value instanceof CamelRestContextFactoryBean)) {
391            throw new ComponentDefinitionException("Expected an instance of " + CamelRestContextFactoryBean.class);
392        }
393
394        CamelRestContextFactoryBean rcfb = (CamelRestContextFactoryBean) value;
395        String id = rcfb.getId();
396
397        MutablePassThroughMetadata factory = context.createMetadata(MutablePassThroughMetadata.class);
398        factory.setId(".camelBlueprint.passThrough." + id);
399        factory.setObject(new PassThroughCallable<Object>(rcfb));
400
401        MutableBeanMetadata factory2 = context.createMetadata(MutableBeanMetadata.class);
402        factory2.setId(".camelBlueprint.factory." + id);
403        factory2.setFactoryComponent(factory);
404        factory2.setFactoryMethod("call");
405
406        MutableBeanMetadata ctx = context.createMetadata(MutableBeanMetadata.class);
407        ctx.setId(id);
408        ctx.setRuntimeClass(List.class);
409        ctx.setFactoryComponent(factory2);
410        ctx.setFactoryMethod("getRests");
411        // must be lazy as we want CamelContext to be activated first
412        ctx.setActivation(ACTIVATION_LAZY);
413
414        // lets inject the namespaces into any namespace aware POJOs
415        injectNamespaces(element, binder);
416
417        LOG.trace("Parsing RestContext done, returning {}", element, ctx);
418        return ctx;
419    }
420
421    private Metadata parseEndpointNode(Element element, ParserContext context) {
422        LOG.trace("Parsing Endpoint {}", element);
423        // now parse the rests with JAXB
424        Binder<Node> binder;
425        try {
426            binder = getJaxbContext().createBinder();
427        } catch (JAXBException e) {
428            throw new ComponentDefinitionException("Failed to create the JAXB binder : " + e, e);
429        }
430        Object value = parseUsingJaxb(element, context, binder);
431        if (!(value instanceof CamelEndpointFactoryBean)) {
432            throw new ComponentDefinitionException("Expected an instance of " + CamelEndpointFactoryBean.class);
433        }
434
435        CamelEndpointFactoryBean rcfb = (CamelEndpointFactoryBean) value;
436        String id = rcfb.getId();
437
438        MutablePassThroughMetadata factory = context.createMetadata(MutablePassThroughMetadata.class);
439        factory.setId(".camelBlueprint.passThrough." + id);
440        factory.setObject(new PassThroughCallable<Object>(rcfb));
441
442        MutableBeanMetadata factory2 = context.createMetadata(MutableBeanMetadata.class);
443        factory2.setId(".camelBlueprint.factory." + id);
444        factory2.setFactoryComponent(factory);
445        factory2.setFactoryMethod("call");
446        factory2.setInitMethod("afterPropertiesSet");
447        factory2.setDestroyMethod("destroy");
448        factory2.addProperty("blueprintContainer", createRef(context, "blueprintContainer"));
449
450        MutableBeanMetadata ctx = context.createMetadata(MutableBeanMetadata.class);
451        ctx.setId(id);
452        ctx.setRuntimeClass(Endpoint.class);
453        ctx.setFactoryComponent(factory2);
454        ctx.setFactoryMethod("getObject");
455        // must be lazy as we want CamelContext to be activated first
456        ctx.setActivation(ACTIVATION_LAZY);
457
458        LOG.trace("Parsing endpoint done, returning {}", element, ctx);
459        return ctx;
460    }
461
462    private Metadata parseKeyStoreParametersNode(Element element, ParserContext context) {
463        LOG.trace("Parsing KeyStoreParameters {}", element);
464        // now parse the key store parameters with JAXB
465        Binder<Node> binder;
466        try {
467            binder = getJaxbContext().createBinder();
468        } catch (JAXBException e) {
469            throw new ComponentDefinitionException("Failed to create the JAXB binder : " + e, e);
470        }
471        Object value = parseUsingJaxb(element, context, binder);
472        if (!(value instanceof KeyStoreParametersFactoryBean)) {
473            throw new ComponentDefinitionException("Expected an instance of " + KeyStoreParametersFactoryBean.class);
474        }
475
476        KeyStoreParametersFactoryBean kspfb = (KeyStoreParametersFactoryBean) value;
477        String id = kspfb.getId();
478
479        MutablePassThroughMetadata factory = context.createMetadata(MutablePassThroughMetadata.class);
480        factory.setId(".camelBlueprint.passThrough." + id);
481        factory.setObject(new PassThroughCallable<Object>(kspfb));
482
483        MutableBeanMetadata factory2 = context.createMetadata(MutableBeanMetadata.class);
484        factory2.setId(".camelBlueprint.factory." + id);
485        factory2.setFactoryComponent(factory);
486        factory2.setFactoryMethod("call");
487        factory2.setInitMethod("afterPropertiesSet");
488        factory2.setDestroyMethod("destroy");
489        factory2.addProperty("blueprintContainer", createRef(context, "blueprintContainer"));
490
491        MutableBeanMetadata ctx = context.createMetadata(MutableBeanMetadata.class);
492        ctx.setId(id);
493        ctx.setRuntimeClass(KeyStoreParameters.class);
494        ctx.setFactoryComponent(factory2);
495        ctx.setFactoryMethod("getObject");
496        // must be lazy as we want CamelContext to be activated first
497        ctx.setActivation(ACTIVATION_LAZY);
498
499        LOG.trace("Parsing KeyStoreParameters done, returning {}", ctx);
500        return ctx;
501    }
502
503    private Metadata parseSecureRandomParametersNode(Element element, ParserContext context) {
504        LOG.trace("Parsing SecureRandomParameters {}", element);
505        // now parse the key store parameters with JAXB
506        Binder<Node> binder;
507        try {
508            binder = getJaxbContext().createBinder();
509        } catch (JAXBException e) {
510            throw new ComponentDefinitionException("Failed to create the JAXB binder : " + e, e);
511        }
512        Object value = parseUsingJaxb(element, context, binder);
513        if (!(value instanceof SecureRandomParametersFactoryBean)) {
514            throw new ComponentDefinitionException("Expected an instance of " + SecureRandomParametersFactoryBean.class);
515        }
516
517        SecureRandomParametersFactoryBean srfb = (SecureRandomParametersFactoryBean) value;
518        String id = srfb.getId();
519
520        MutablePassThroughMetadata factory = context.createMetadata(MutablePassThroughMetadata.class);
521        factory.setId(".camelBlueprint.passThrough." + id);
522        factory.setObject(new PassThroughCallable<Object>(srfb));
523
524        MutableBeanMetadata factory2 = context.createMetadata(MutableBeanMetadata.class);
525        factory2.setId(".camelBlueprint.factory." + id);
526        factory2.setFactoryComponent(factory);
527        factory2.setFactoryMethod("call");
528        factory2.setInitMethod("afterPropertiesSet");
529        factory2.setDestroyMethod("destroy");
530        factory2.addProperty("blueprintContainer", createRef(context, "blueprintContainer"));
531
532        MutableBeanMetadata ctx = context.createMetadata(MutableBeanMetadata.class);
533        ctx.setId(id);
534        ctx.setRuntimeClass(SecureRandomParameters.class);
535        ctx.setFactoryComponent(factory2);
536        ctx.setFactoryMethod("getObject");
537        // must be lazy as we want CamelContext to be activated first
538        ctx.setActivation(ACTIVATION_LAZY);
539
540        LOG.trace("Parsing SecureRandomParameters done, returning {}", ctx);
541        return ctx;
542    }
543
544    private Metadata parseSSLContextParametersNode(Element element, ParserContext context) {
545        LOG.trace("Parsing SSLContextParameters {}", element);
546        // now parse the key store parameters with JAXB
547        Binder<Node> binder;
548        try {
549            binder = getJaxbContext().createBinder();
550        } catch (JAXBException e) {
551            throw new ComponentDefinitionException("Failed to create the JAXB binder : " + e, e);
552        }
553        Object value = parseUsingJaxb(element, context, binder);
554        if (!(value instanceof SSLContextParametersFactoryBean)) {
555            throw new ComponentDefinitionException("Expected an instance of " + SSLContextParametersFactoryBean.class);
556        }
557
558        SSLContextParametersFactoryBean scpfb = (SSLContextParametersFactoryBean) value;
559        String id = scpfb.getId();
560
561        MutablePassThroughMetadata factory = context.createMetadata(MutablePassThroughMetadata.class);
562        factory.setId(".camelBlueprint.passThrough." + id);
563        factory.setObject(new PassThroughCallable<Object>(scpfb));
564
565        MutableBeanMetadata factory2 = context.createMetadata(MutableBeanMetadata.class);
566        factory2.setId(".camelBlueprint.factory." + id);
567        factory2.setFactoryComponent(factory);
568        factory2.setFactoryMethod("call");
569        factory2.setInitMethod("afterPropertiesSet");
570        factory2.setDestroyMethod("destroy");
571        factory2.addProperty("blueprintContainer", createRef(context, "blueprintContainer"));
572
573        MutableBeanMetadata ctx = context.createMetadata(MutableBeanMetadata.class);
574        ctx.setId(id);
575        ctx.setRuntimeClass(SSLContextParameters.class);
576        ctx.setFactoryComponent(factory2);
577        ctx.setFactoryMethod("getObject");
578        // must be lazy as we want CamelContext to be activated first
579        ctx.setActivation(ACTIVATION_LAZY);
580
581        LOG.trace("Parsing SSLContextParameters done, returning {}", ctx);
582        return ctx;
583    }
584
585    private void registerBeans(ParserContext context, String contextId, List<?> beans) {
586        if (beans != null) {
587            for (Object bean : beans) {
588                if (bean instanceof AbstractCamelFactoryBean) {
589                    registerBean(context, contextId, (AbstractCamelFactoryBean<?>) bean);
590                }
591            }
592        }
593    }
594
595    protected void registerBean(ParserContext context, String contextId, AbstractCamelFactoryBean<?> fact) {
596        String id = fact.getId();
597
598        fact.setCamelContextId(contextId);
599
600        MutablePassThroughMetadata eff = context.createMetadata(MutablePassThroughMetadata.class);
601        eff.setId(".camelBlueprint.bean.passthrough." + id);
602        eff.setObject(new PassThroughCallable<Object>(fact));
603
604        MutableBeanMetadata ef = context.createMetadata(MutableBeanMetadata.class);
605        ef.setId(".camelBlueprint.bean.factory." + id);
606        ef.setFactoryComponent(eff);
607        ef.setFactoryMethod("call");
608        ef.addProperty("blueprintContainer", createRef(context, "blueprintContainer"));
609        ef.setInitMethod("afterPropertiesSet");
610        ef.setDestroyMethod("destroy");
611
612        MutableBeanMetadata e = context.createMetadata(MutableBeanMetadata.class);
613        e.setId(id);
614        e.setRuntimeClass(fact.getObjectType());
615        e.setFactoryComponent(ef);
616        e.setFactoryMethod("getObject");
617        e.addDependsOn(".camelBlueprint.processor.bean." + contextId);
618
619        context.getComponentDefinitionRegistry().registerComponentDefinition(e);
620    }
621
622    protected BlueprintContainer getBlueprintContainer(ParserContext context) {
623        PassThroughMetadata ptm = (PassThroughMetadata) context.getComponentDefinitionRegistry().getComponentDefinition("blueprintContainer");
624        return (BlueprintContainer) ptm.getObject();
625    }
626
627    public ComponentMetadata decorate(Node node, ComponentMetadata component, ParserContext context) {
628        return null;
629    }
630
631    protected Object parseUsingJaxb(Element element, ParserContext parserContext, Binder<Node> binder) {
632        try {
633            return binder.unmarshal(element);
634        } catch (JAXBException e) {
635            throw new ComponentDefinitionException("Failed to parse JAXB element: " + e, e);
636        }
637    }
638
639    public JAXBContext getJaxbContext() throws JAXBException {
640        if (jaxbContext == null) {
641            jaxbContext = new BlueprintModelJAXBContextFactory(getClass().getClassLoader()).newJAXBContext();
642        }
643        return jaxbContext;
644    }
645
646    private RefMetadata createRef(ParserContext context, String value) {
647        MutableRefMetadata r = context.createMetadata(MutableRefMetadata.class);
648        r.setComponentId(value);
649        return r;
650    }
651
652    private static ComponentMetadata getDataformatResolverReference(ParserContext context, String dataformat) {
653        // we cannot resolve dataformat names using property placeholders at this point in time
654        if (dataformat.startsWith(PropertiesComponent.DEFAULT_PREFIX_TOKEN)) {
655            return null;
656        }
657        ComponentDefinitionRegistry componentDefinitionRegistry = context.getComponentDefinitionRegistry();
658        ComponentMetadata cm = componentDefinitionRegistry.getComponentDefinition(".camelBlueprint.dataformatResolver." + dataformat);
659        if (cm == null) {
660            MutableReferenceMetadata svc = context.createMetadata(MutableReferenceMetadata.class);
661            svc.setId(".camelBlueprint.dataformatResolver." + dataformat);
662            svc.setFilter("(dataformat=" + dataformat + ")");
663            svc.setAvailability(componentDefinitionRegistry.containsComponentDefinition(dataformat) ? AVAILABILITY_OPTIONAL : AVAILABILITY_MANDATORY);
664            try {
665                // Try to set the runtime interface (only with aries blueprint > 0.1
666                svc.getClass().getMethod("setRuntimeInterface", Class.class).invoke(svc, DataFormatResolver.class);
667            } catch (Throwable t) {
668                // Check if the bundle can see the class
669                try {
670                    PassThroughMetadata ptm = (PassThroughMetadata) componentDefinitionRegistry.getComponentDefinition("blueprintBundle");
671                    Bundle b = (Bundle) ptm.getObject();
672                    if (b.loadClass(DataFormatResolver.class.getName()) != DataFormatResolver.class) {
673                        throw new UnsupportedOperationException();
674                    }
675                    svc.setInterface(DataFormatResolver.class.getName());
676                } catch (Throwable t2) {
677                    throw new UnsupportedOperationException();
678                }
679            }
680            componentDefinitionRegistry.registerComponentDefinition(svc);
681            cm = svc;
682        }
683        return cm;
684    }
685
686    private static ComponentMetadata getLanguageResolverReference(ParserContext context, String language) {
687        // we cannot resolve language names using property placeholders at this point in time
688        if (language.startsWith(PropertiesComponent.DEFAULT_PREFIX_TOKEN)) {
689            return null;
690        }
691        ComponentDefinitionRegistry componentDefinitionRegistry = context.getComponentDefinitionRegistry();
692        ComponentMetadata cm = componentDefinitionRegistry.getComponentDefinition(".camelBlueprint.languageResolver." + language);
693        if (cm == null) {
694            MutableReferenceMetadata svc = context.createMetadata(MutableReferenceMetadata.class);
695            svc.setId(".camelBlueprint.languageResolver." + language);
696            svc.setFilter("(language=" + language + ")");
697            svc.setAvailability(componentDefinitionRegistry.containsComponentDefinition(language) ? AVAILABILITY_OPTIONAL : AVAILABILITY_MANDATORY);
698            try {
699                // Try to set the runtime interface (only with aries blueprint > 0.1
700                svc.getClass().getMethod("setRuntimeInterface", Class.class).invoke(svc, LanguageResolver.class);
701            } catch (Throwable t) {
702                // Check if the bundle can see the class
703                try {
704                    PassThroughMetadata ptm = (PassThroughMetadata) componentDefinitionRegistry.getComponentDefinition("blueprintBundle");
705                    Bundle b = (Bundle) ptm.getObject();
706                    if (b.loadClass(LanguageResolver.class.getName()) != LanguageResolver.class) {
707                        throw new UnsupportedOperationException();
708                    }
709                    svc.setInterface(LanguageResolver.class.getName());
710                } catch (Throwable t2) {
711                    throw new UnsupportedOperationException();
712                }
713            }
714            componentDefinitionRegistry.registerComponentDefinition(svc);
715            cm = svc;
716        }
717        return cm;
718    }
719
720    private static ComponentMetadata getComponentResolverReference(ParserContext context, String component) {
721        // we cannot resolve component names using property placeholders at this point in time
722        if (component.startsWith(PropertiesComponent.DEFAULT_PREFIX_TOKEN)) {
723            return null;
724        }
725        ComponentDefinitionRegistry componentDefinitionRegistry = context.getComponentDefinitionRegistry();
726        ComponentMetadata cm = componentDefinitionRegistry.getComponentDefinition(".camelBlueprint.componentResolver." + component);
727        if (cm == null) {
728            MutableReferenceMetadata svc = context.createMetadata(MutableReferenceMetadata.class);
729            svc.setId(".camelBlueprint.componentResolver." + component);
730            svc.setFilter("(component=" + component + ")");
731            svc.setAvailability(componentDefinitionRegistry.containsComponentDefinition(component) ? AVAILABILITY_OPTIONAL : AVAILABILITY_MANDATORY);
732            try {
733                // Try to set the runtime interface (only with aries blueprint > 0.1
734                svc.getClass().getMethod("setRuntimeInterface", Class.class).invoke(svc, ComponentResolver.class);
735            } catch (Throwable t) {
736                // Check if the bundle can see the class
737                try {
738                    PassThroughMetadata ptm = (PassThroughMetadata) componentDefinitionRegistry.getComponentDefinition("blueprintBundle");
739                    Bundle b = (Bundle) ptm.getObject();
740                    if (b.loadClass(ComponentResolver.class.getName()) != ComponentResolver.class) {
741                        throw new UnsupportedOperationException();
742                    }
743                    svc.setInterface(ComponentResolver.class.getName());
744                } catch (Throwable t2) {
745                    throw new UnsupportedOperationException();
746                }
747            }
748            componentDefinitionRegistry.registerComponentDefinition(svc);
749            cm = svc;
750        }
751        return cm;
752    }
753
754    public static class PassThroughCallable<T> implements Callable<T> {
755
756        private T value;
757
758        public PassThroughCallable(T value) {
759            this.value = value;
760        }
761
762        public T call() throws Exception {
763            return value;
764        }
765    }
766
767    public static class CamelInjector extends CamelPostProcessorHelper implements BeanProcessor {
768
769        private final String camelContextName;
770        private BlueprintContainer blueprintContainer;
771
772        public CamelInjector(String camelContextName) {
773            this.camelContextName = camelContextName;
774        }
775
776        public void setBlueprintContainer(BlueprintContainer blueprintContainer) {
777            this.blueprintContainer = blueprintContainer;
778        }
779
780        @Override
781        public CamelContext getCamelContext() {
782            if (blueprintContainer != null) {
783                CamelContext answer = (CamelContext) blueprintContainer.getComponentInstance(camelContextName);
784                return answer;
785            }
786            return null;
787        }
788
789        public Object beforeInit(Object bean, String beanName, BeanCreator beanCreator, BeanMetadata beanMetadata) {
790            LOG.trace("Before init of bean: {} -> {}", beanName, bean);
791            // prefer to inject later in afterInit
792            return bean;
793        }
794
795        /**
796         * A strategy method to allow implementations to perform some custom JBI
797         * based injection of the POJO
798         *
799         * @param bean the bean to be injected
800         */
801        protected void injectFields(final Object bean, final String beanName) {
802            Class<?> clazz = bean.getClass();
803            do {
804                Field[] fields = clazz.getDeclaredFields();
805                for (Field field : fields) {
806                    PropertyInject propertyInject = field.getAnnotation(PropertyInject.class);
807                    if (propertyInject != null && matchContext(propertyInject.context())) {
808                        injectFieldProperty(field, propertyInject.value(), propertyInject.defaultValue(), bean, beanName);
809                    }
810
811                    BeanInject beanInject = field.getAnnotation(BeanInject.class);
812                    if (beanInject != null && matchContext(beanInject.context())) {
813                        injectFieldBean(field, beanInject.value(), bean, beanName);
814                    }
815
816                    EndpointInject endpointInject = field.getAnnotation(EndpointInject.class);
817                    if (endpointInject != null && matchContext(endpointInject.context())) {
818                        injectField(field, endpointInject.uri(), endpointInject.ref(), endpointInject.property(), bean, beanName);
819                    }
820
821                    Produce produce = field.getAnnotation(Produce.class);
822                    if (produce != null && matchContext(produce.context())) {
823                        injectField(field, produce.uri(), produce.ref(), produce.property(), bean, beanName);
824                    }
825                }
826                clazz = clazz.getSuperclass();
827            } while (clazz != null && clazz != Object.class);
828        }
829
830        protected void injectField(Field field, String endpointUri, String endpointRef, String endpointProperty, Object bean, String beanName) {
831            setField(field, bean, getInjectionValue(field.getType(), endpointUri, endpointRef, endpointProperty, field.getName(), bean, beanName));
832        }
833
834        protected void injectFieldProperty(Field field, String propertyName, String propertyDefaultValue, Object bean, String beanName) {
835            setField(field, bean, getInjectionPropertyValue(field.getType(), propertyName, propertyDefaultValue, field.getName(), bean, beanName));
836        }
837
838        public void injectFieldBean(Field field, String name, Object bean, String beanName) {
839            setField(field, bean, getInjectionBeanValue(field.getType(), name));
840        }
841
842        protected static void setField(Field field, Object instance, Object value) {
843            try {
844                boolean oldAccessible = field.isAccessible();
845                boolean shouldSetAccessible = !Modifier.isPublic(field.getModifiers()) && !oldAccessible;
846                if (shouldSetAccessible) {
847                    field.setAccessible(true);
848                }
849                field.set(instance, value);
850                if (shouldSetAccessible) {
851                    field.setAccessible(oldAccessible);
852                }
853            } catch (IllegalArgumentException ex) {
854                throw new UnsupportedOperationException("Cannot inject value of class: " + value.getClass() + " into: " + field);
855            } catch (IllegalAccessException ex) {
856                throw new IllegalStateException("Could not access method: " + ex.getMessage());
857            }
858        }
859
860        protected void injectMethods(final Object bean, final String beanName) {
861            Class<?> clazz = bean.getClass();
862            do {
863                Method[] methods = clazz.getDeclaredMethods();
864                for (Method method : methods) {
865                    setterInjection(method, bean, beanName);
866                    consumerInjection(method, bean, beanName);
867                }
868                clazz = clazz.getSuperclass();
869            } while (clazz != null && clazz != Object.class);
870        }
871
872        protected void setterInjection(Method method, Object bean, String beanName) {
873            PropertyInject propertyInject = method.getAnnotation(PropertyInject.class);
874            if (propertyInject != null && matchContext(propertyInject.context())) {
875                setterPropertyInjection(method, propertyInject.value(), propertyInject.defaultValue(), bean, beanName);
876            }
877
878            BeanInject beanInject = method.getAnnotation(BeanInject.class);
879            if (beanInject != null && matchContext(beanInject.context())) {
880                setterBeanInjection(method, beanInject.value(), bean, beanName);
881            }
882
883            EndpointInject endpointInject = method.getAnnotation(EndpointInject.class);
884            if (endpointInject != null && matchContext(endpointInject.context())) {
885                setterInjection(method, bean, beanName, endpointInject.uri(), endpointInject.ref(), endpointInject.property());
886            }
887
888            Produce produce = method.getAnnotation(Produce.class);
889            if (produce != null && matchContext(produce.context())) {
890                setterInjection(method, bean, beanName, produce.uri(), produce.ref(), produce.property());
891            }
892        }
893
894        protected void setterPropertyInjection(Method method, String propertyValue, String propertyDefaultValue, Object bean, String beanName) {
895            Class<?>[] parameterTypes = method.getParameterTypes();
896            if (parameterTypes != null) {
897                if (parameterTypes.length != 1) {
898                    LOG.warn("Ignoring badly annotated method for injection due to incorrect number of parameters: " + method);
899                } else {
900                    String propertyName = ObjectHelper.getPropertyName(method);
901                    Object value = getInjectionPropertyValue(parameterTypes[0], propertyValue, propertyDefaultValue, propertyName, bean, beanName);
902                    ObjectHelper.invokeMethod(method, bean, value);
903                }
904            }
905        }
906
907        protected void setterBeanInjection(Method method, String name, Object bean, String beanName) {
908            Class<?>[] parameterTypes = method.getParameterTypes();
909            if (parameterTypes != null) {
910                if (parameterTypes.length != 1) {
911                    LOG.warn("Ignoring badly annotated method for injection due to incorrect number of parameters: " + method);
912                } else {
913                    Object value = getInjectionBeanValue(parameterTypes[0], name);
914                    ObjectHelper.invokeMethod(method, bean, value);
915                }
916            }
917        }
918
919        protected void setterInjection(Method method, Object bean, String beanName, String endpointUri, String endpointRef, String endpointProperty) {
920            Class<?>[] parameterTypes = method.getParameterTypes();
921            if (parameterTypes != null) {
922                if (parameterTypes.length != 1) {
923                    LOG.warn("Ignoring badly annotated method for injection due to incorrect number of parameters: " + method);
924                } else {
925                    String propertyName = ObjectHelper.getPropertyName(method);
926                    Object value = getInjectionValue(parameterTypes[0], endpointUri, endpointRef, endpointProperty, propertyName, bean, beanName);
927                    ObjectHelper.invokeMethod(method, bean, value);
928                }
929            }
930        }
931
932        public Object afterInit(Object bean, String beanName, BeanCreator beanCreator, BeanMetadata beanMetadata) {
933            LOG.trace("After init of bean: {} -> {}", beanName, bean);
934            // we cannot inject CamelContextAware beans as the CamelContext may not be ready
935            injectFields(bean, beanName);
936            injectMethods(bean, beanName);
937            return bean;
938        }
939
940        public void beforeDestroy(Object bean, String beanName) {
941        }
942
943        public void afterDestroy(Object bean, String beanName) {
944        }
945
946        @Override
947        protected boolean isSingleton(Object bean, String beanName) {
948            if (beanName != null) {
949                ComponentMetadata meta = blueprintContainer.getComponentMetadata(beanName);
950                if (meta != null && meta instanceof BeanMetadata) {
951                    String scope = ((BeanMetadata) meta).getScope();
952                    if (scope != null) {
953                        return BeanMetadata.SCOPE_SINGLETON.equals(scope);
954                    }
955                }
956            }
957            // fallback to super, which will assume singleton
958            // for beans not implementing Camel's IsSingleton interface
959            return super.isSingleton(bean, beanName);
960        }
961    }
962
963    public static class CamelDependenciesFinder implements ComponentDefinitionRegistryProcessor {
964
965        private final String camelContextName;
966        private final ParserContext context;
967        private BlueprintContainer blueprintContainer;
968
969        public CamelDependenciesFinder(String camelContextName, ParserContext context) {
970            this.camelContextName = camelContextName;
971            this.context = context;
972        }
973
974        public void setBlueprintContainer(BlueprintContainer blueprintContainer) {
975            this.blueprintContainer = blueprintContainer;
976        }
977
978        @SuppressWarnings("deprecation")
979        public void process(ComponentDefinitionRegistry componentDefinitionRegistry) {
980            CamelContextFactoryBean ccfb = (CamelContextFactoryBean) blueprintContainer.getComponentInstance(".camelBlueprint.factory." + camelContextName);
981            CamelContext camelContext = ccfb.getContext();
982
983            Set<String> components = new HashSet<String>();
984            Set<String> languages = new HashSet<String>();
985            Set<String> dataformats = new HashSet<String>();
986
987            // regular camel routes
988            for (RouteDefinition rd : camelContext.getRouteDefinitions()) {
989                findInputComponents(rd.getInputs(), components, languages, dataformats);
990                findOutputComponents(rd.getOutputs(), components, languages, dataformats);
991            }
992
993            // rest services can have embedded routes or a singular to
994            for (RestDefinition rd : camelContext.getRestDefinitions()) {
995                for (VerbDefinition vd : rd.getVerbs()) {
996                    Object o = vd.getToOrRoute();
997                    if (o instanceof RouteDefinition) {
998                        RouteDefinition route = (RouteDefinition) o;
999                        findInputComponents(route.getInputs(), components, languages, dataformats);
1000                        findOutputComponents(route.getOutputs(), components, languages, dataformats);
1001                    } else if (o instanceof ToDefinition) {
1002                        findUriComponent(((ToDefinition) o).getUri(), components);
1003                    } else if (o instanceof ToDynamicDefinition) {
1004                        findUriComponent(((ToDynamicDefinition) o).getUri(), components);
1005                    }
1006                }
1007            }
1008
1009            if (ccfb.getRestConfiguration() != null) {
1010                // rest configuration may refer to a component to use
1011                String component = ccfb.getRestConfiguration().getComponent();
1012                if (component != null) {
1013                    components.add(component);
1014                }
1015                component = ccfb.getRestConfiguration().getApiComponent();
1016                if (component != null) {
1017                    components.add(component);
1018                }
1019
1020                // check what data formats are used in binding mode
1021                RestBindingMode mode = ccfb.getRestConfiguration().getBindingMode();
1022                String json = ccfb.getRestConfiguration().getJsonDataFormat();
1023                if (json == null && mode != null) {
1024                    if (RestBindingMode.json.equals(mode) || RestBindingMode.json_xml.equals(mode)) {
1025                        // jackson is the default json data format
1026                        json = "json-jackson";
1027                    }
1028                }
1029                if (json != null) {
1030                    dataformats.add(json);
1031                }
1032                String xml = ccfb.getRestConfiguration().getXmlDataFormat();
1033                if (xml == null && mode != null) {
1034                    if (RestBindingMode.xml.equals(mode) || RestBindingMode.json_xml.equals(mode)) {
1035                        // jaxb is the default xml data format
1036                        dataformats.add("jaxb");
1037                    }
1038                }
1039                if (xml != null) {
1040                    dataformats.add(xml);
1041                }
1042            }
1043
1044            // We can only add service references to resolvers, but we can't make the factory depends on those
1045            // because the factory has already been instantiated
1046            try {
1047                for (String component : components) {
1048                    getComponentResolverReference(context, component);
1049                }
1050                for (String language : languages) {
1051                    getLanguageResolverReference(context, language);
1052                }
1053                for (String dataformat : dataformats) {
1054                    getDataformatResolverReference(context, dataformat);
1055                }
1056            } catch (UnsupportedOperationException e) {
1057                LOG.warn("Unable to add dependencies to Camel components OSGi services. "
1058                    + "The Apache Aries blueprint implementation used is too old and the blueprint bundle cannot see the org.apache.camel.spi package.");
1059                components.clear();
1060                languages.clear();
1061                dataformats.clear();
1062            }
1063
1064        }
1065
1066        private void findInputComponents(List<FromDefinition> defs, Set<String> components, Set<String> languages, Set<String> dataformats) {
1067            if (defs != null) {
1068                for (FromDefinition def : defs) {
1069                    findUriComponent(def.getUri(), components);
1070                    findSchedulerUriComponent(def.getUri(), components);
1071                }
1072            }
1073        }
1074
1075        @SuppressWarnings({"rawtypes"})
1076        private void findOutputComponents(List<ProcessorDefinition<?>> defs, Set<String> components, Set<String> languages, Set<String> dataformats) {
1077            if (defs != null) {
1078                for (ProcessorDefinition<?> def : defs) {
1079                    if (def instanceof SendDefinition) {
1080                        findUriComponent(((SendDefinition) def).getUri(), components);
1081                    }
1082                    if (def instanceof MarshalDefinition) {
1083                        findDataFormat(((MarshalDefinition) def).getDataFormatType(), dataformats);
1084                    }
1085                    if (def instanceof UnmarshalDefinition) {
1086                        findDataFormat(((UnmarshalDefinition) def).getDataFormatType(), dataformats);
1087                    }
1088                    if (def instanceof ExpressionNode) {
1089                        findLanguage(((ExpressionNode) def).getExpression(), languages);
1090                    }
1091                    if (def instanceof ResequenceDefinition) {
1092                        findLanguage(((ResequenceDefinition) def).getExpression(), languages);
1093                    }
1094                    if (def instanceof AggregateDefinition) {
1095                        findLanguage(((AggregateDefinition) def).getExpression(), languages);
1096                        findLanguage(((AggregateDefinition) def).getCorrelationExpression(), languages);
1097                        findLanguage(((AggregateDefinition) def).getCompletionPredicate(), languages);
1098                        findLanguage(((AggregateDefinition) def).getCompletionTimeoutExpression(), languages);
1099                        findLanguage(((AggregateDefinition) def).getCompletionSizeExpression(), languages);
1100                    }
1101                    if (def instanceof CatchDefinition) {
1102                        findLanguage(((CatchDefinition) def).getHandled(), languages);
1103                    }
1104                    if (def instanceof OnExceptionDefinition) {
1105                        findLanguage(((OnExceptionDefinition) def).getRetryWhile(), languages);
1106                        findLanguage(((OnExceptionDefinition) def).getHandled(), languages);
1107                        findLanguage(((OnExceptionDefinition) def).getContinued(), languages);
1108                    }
1109                    if (def instanceof SortDefinition) {
1110                        findLanguage(((SortDefinition) def).getExpression(), languages);
1111                    }
1112                    if (def instanceof WireTapDefinition) {
1113                        findLanguage(((WireTapDefinition<?>) def).getNewExchangeExpression(), languages);
1114                    }
1115                    findOutputComponents(def.getOutputs(), components, languages, dataformats);
1116                }
1117            }
1118        }
1119
1120        private void findLanguage(ExpressionDefinition expression, Set<String> languages) {
1121            if (expression != null) {
1122                String lang = expression.getLanguage();
1123                if (lang != null && lang.length() > 0) {
1124                    languages.add(lang);
1125                }
1126            }
1127        }
1128
1129        private void findLanguage(ExpressionSubElementDefinition expression, Set<String> languages) {
1130            if (expression != null) {
1131                findLanguage(expression.getExpressionType(), languages);
1132            }
1133        }
1134
1135        private void findDataFormat(DataFormatDefinition dfd, Set<String> dataformats) {
1136            if (dfd != null && dfd.getDataFormatName() != null) {
1137                dataformats.add(dfd.getDataFormatName());
1138            }
1139        }
1140
1141        private void findUriComponent(String uri, Set<String> components) {
1142            // if the uri is a placeholder then skip it
1143            if (uri != null && uri.startsWith(PropertiesComponent.DEFAULT_PREFIX_TOKEN)) {
1144                return;
1145            }
1146
1147            if (uri != null) {
1148                String splitURI[] = ObjectHelper.splitOnCharacter(uri, ":", 2);
1149                if (splitURI[1] != null) {
1150                    String scheme = splitURI[0];
1151                    components.add(scheme);
1152                }
1153            }
1154        }
1155
1156        private void findSchedulerUriComponent(String uri, Set<String> components) {
1157
1158            // the input may use a scheduler which can be quartz or spring
1159            if (uri != null) {
1160                try {
1161                    URI u = new URI(uri);
1162                    Map<String, Object> parameters = URISupport.parseParameters(u);
1163                    Object value = parameters.get("scheduler");
1164                    if (value == null) {
1165                        value = parameters.get("consumer.scheduler");
1166                    }
1167                    if (value != null) {
1168                        // the scheduler can be quartz2 or spring based, so add reference to camel component
1169                        // from these components os blueprint knows about the requirement
1170                        String name = value.toString();
1171                        if ("quartz2".equals(name)) {
1172                            components.add("quartz2");
1173                        } else if ("spring".equals(name)) {
1174                            components.add("spring-event");
1175                        }
1176                    }
1177                } catch (URISyntaxException e) {
1178                    // ignore
1179                }
1180            }
1181        }
1182
1183    }
1184
1185}