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