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     */
017    package org.apache.camel.blueprint.handler;
018    
019    import java.lang.reflect.Field;
020    import java.lang.reflect.Method;
021    import java.lang.reflect.Modifier;
022    import java.net.URL;
023    import java.util.Arrays;
024    import java.util.HashSet;
025    import java.util.List;
026    import java.util.Set;
027    import java.util.concurrent.Callable;
028    import javax.xml.bind.Binder;
029    import javax.xml.bind.JAXBContext;
030    import javax.xml.bind.JAXBException;
031    
032    import org.w3c.dom.Document;
033    import org.w3c.dom.Element;
034    import org.w3c.dom.Node;
035    import org.w3c.dom.NodeList;
036    
037    import org.apache.aries.blueprint.BeanProcessor;
038    import org.apache.aries.blueprint.ComponentDefinitionRegistry;
039    import org.apache.aries.blueprint.ComponentDefinitionRegistryProcessor;
040    import org.apache.aries.blueprint.NamespaceHandler;
041    import org.apache.aries.blueprint.ParserContext;
042    import org.apache.aries.blueprint.PassThroughMetadata;
043    import org.apache.aries.blueprint.mutable.MutableBeanMetadata;
044    import org.apache.aries.blueprint.mutable.MutablePassThroughMetadata;
045    import org.apache.aries.blueprint.mutable.MutableRefMetadata;
046    import org.apache.aries.blueprint.mutable.MutableReferenceMetadata;
047    import org.apache.aries.blueprint.mutable.MutableValueMetadata;
048    import org.apache.camel.CamelContext;
049    import org.apache.camel.CamelContextAware;
050    import org.apache.camel.EndpointInject;
051    import org.apache.camel.Produce;
052    import org.apache.camel.blueprint.BlueprintCamelContext;
053    import org.apache.camel.blueprint.CamelContextFactoryBean;
054    import org.apache.camel.blueprint.CamelRouteContextFactoryBean;
055    import org.apache.camel.core.xml.AbstractCamelContextFactoryBean;
056    import org.apache.camel.core.xml.AbstractCamelFactoryBean;
057    import org.apache.camel.impl.CamelPostProcessorHelper;
058    import org.apache.camel.impl.DefaultCamelContextNameStrategy;
059    import org.apache.camel.model.AggregateDefinition;
060    import org.apache.camel.model.CatchDefinition;
061    import org.apache.camel.model.DataFormatDefinition;
062    import org.apache.camel.model.ExpressionNode;
063    import org.apache.camel.model.ExpressionSubElementDefinition;
064    import org.apache.camel.model.FromDefinition;
065    import org.apache.camel.model.MarshalDefinition;
066    import org.apache.camel.model.OnExceptionDefinition;
067    import org.apache.camel.model.ProcessorDefinition;
068    import org.apache.camel.model.ResequenceDefinition;
069    import org.apache.camel.model.RouteDefinition;
070    import org.apache.camel.model.SendDefinition;
071    import org.apache.camel.model.SortDefinition;
072    import org.apache.camel.model.UnmarshalDefinition;
073    import org.apache.camel.model.WireTapDefinition;
074    import org.apache.camel.model.language.ExpressionDefinition;
075    import org.apache.camel.spi.CamelContextNameStrategy;
076    import org.apache.camel.spi.ComponentResolver;
077    import org.apache.camel.spi.DataFormatResolver;
078    import org.apache.camel.spi.LanguageResolver;
079    import org.apache.camel.util.ObjectHelper;
080    import org.apache.commons.logging.Log;
081    import org.apache.commons.logging.LogFactory;
082    
083    import org.osgi.framework.Bundle;
084    import org.osgi.service.blueprint.container.BlueprintContainer;
085    import org.osgi.service.blueprint.container.ComponentDefinitionException;
086    import org.osgi.service.blueprint.reflect.BeanMetadata;
087    import org.osgi.service.blueprint.reflect.ComponentMetadata;
088    import org.osgi.service.blueprint.reflect.Metadata;
089    import org.osgi.service.blueprint.reflect.RefMetadata;
090    import org.osgi.service.blueprint.reflect.ValueMetadata;
091    
092    import static org.osgi.service.blueprint.reflect.ServiceReferenceMetadata.AVAILABILITY_MANDATORY;
093    import static org.osgi.service.blueprint.reflect.ServiceReferenceMetadata.AVAILABILITY_OPTIONAL;
094    
095    public class CamelNamespaceHandler implements NamespaceHandler {
096    
097        private static final String CAMEL_CONTEXT = "camelContext";
098        private static final String ROUTE_CONTEXT = "routeContext";
099    
100        private static final String SPRING_NS = "http://camel.apache.org/schema/spring";
101        private static final String BLUEPRINT_NS = "http://camel.apache.org/schema/blueprint";
102    
103        private static final transient Log LOG = LogFactory.getLog(CamelNamespaceHandler.class);
104    
105        private JAXBContext jaxbContext;
106    
107        public static void renameNamespaceRecursive(Node node) {
108            if (node.getNodeType() == Node.ELEMENT_NODE) {
109                Document doc = node.getOwnerDocument();
110                if (((Element) node).getNamespaceURI().equals(BLUEPRINT_NS)) {
111                    doc.renameNode(node, SPRING_NS, node.getNodeName());
112                }
113            }
114            NodeList list = node.getChildNodes();
115            for (int i = 0; i < list.getLength(); ++i) {
116                renameNamespaceRecursive(list.item(i));
117            }
118        }
119    
120        public URL getSchemaLocation(String namespace) {
121            return getClass().getClassLoader().getResource("camel-blueprint.xsd");
122        }
123    
124        @SuppressWarnings("unchecked")
125        public Set<Class> getManagedClasses() {
126            return new HashSet<Class>(Arrays.asList(
127                    BlueprintCamelContext.class
128            ));
129        }
130    
131        public Metadata parse(Element element, ParserContext context) {
132            renameNamespaceRecursive(element);
133            if (element.getNodeName().equals(CAMEL_CONTEXT)) {
134                // Find the id, generate one if needed
135                String contextId = element.getAttribute("id");
136                boolean implicitId = false;
137    
138                // lets avoid folks having to explicitly give an ID to a camel context
139                if (ObjectHelper.isEmpty(contextId)) {
140                    // if no explicit id was set then use a default auto generated name
141                    CamelContextNameStrategy strategy = new DefaultCamelContextNameStrategy();
142                    contextId = strategy.getName();
143                    element.setAttribute("id", contextId);
144                    implicitId = true;
145                }
146    
147                // now lets parse the routes with JAXB
148                Binder<Node> binder;
149                try {
150                    binder = getJaxbContext().createBinder();
151                } catch (JAXBException e) {
152                    throw new ComponentDefinitionException("Failed to create the JAXB binder : " + e, e);
153                }
154                Object value = parseUsingJaxb(element, context, binder);
155                if (!(value instanceof CamelContextFactoryBean)) {
156                    throw new ComponentDefinitionException("Expected an instance of " + CamelContextFactoryBean.class);
157                }
158    
159                CamelContextFactoryBean ccfb = (CamelContextFactoryBean) value;
160                ccfb.setImplicitId(implicitId);
161    
162                MutablePassThroughMetadata factory = context.createMetadata(MutablePassThroughMetadata.class);
163                factory.setId(".camelBlueprint.passThrough." + contextId);
164                factory.setObject(new PassThroughCallable<Object>(value));
165    
166                MutableBeanMetadata factory2 = context.createMetadata(MutableBeanMetadata.class);
167                factory2.setId(".camelBlueprint.factory." + contextId);
168                factory2.setFactoryComponent(factory);
169                factory2.setFactoryMethod("call");
170                factory2.setInitMethod("afterPropertiesSet");
171                factory2.setDestroyMethod("destroy");
172                factory2.addProperty("blueprintContainer", createRef(context, "blueprintContainer"));
173                factory2.addProperty("bundleContext", createRef(context, "blueprintBundleContext"));
174    
175                MutableBeanMetadata ctx = context.createMetadata(MutableBeanMetadata.class);
176                ctx.setId(contextId);
177                ctx.setRuntimeClass(BlueprintCamelContext.class);
178                ctx.setFactoryComponent(factory2);
179                ctx.setFactoryMethod("getContext");
180                ctx.setInitMethod("init");
181                ctx.setDestroyMethod("destroy");
182    
183                // Register objects
184                registerBeans(context, contextId, ccfb.getEndpoints());
185                registerBeans(context, contextId, ccfb.getThreadPools());
186                registerBeans(context, contextId, ccfb.getBeans());
187    
188                // Register processors
189                MutablePassThroughMetadata beanProcessorFactory = context.createMetadata(MutablePassThroughMetadata.class);
190                beanProcessorFactory.setId(".camelBlueprint.processor.bean.passThrough." + contextId);
191                beanProcessorFactory.setObject(new PassThroughCallable<Object>(new CamelInjector(contextId)));
192    
193                MutableBeanMetadata beanProcessor = context.createMetadata(MutableBeanMetadata.class);
194                beanProcessor.setId(".camelBlueprint.processor.bean." + contextId);
195                beanProcessor.setRuntimeClass(CamelInjector.class);
196                beanProcessor.setFactoryComponent(beanProcessorFactory);
197                beanProcessor.setFactoryMethod("call");
198                beanProcessor.setProcessor(true);
199                beanProcessor.addProperty("blueprintContainer", createRef(context, "blueprintContainer"));
200                context.getComponentDefinitionRegistry().registerComponentDefinition(beanProcessor);
201    
202                MutablePassThroughMetadata regProcessorFactory = context.createMetadata(MutablePassThroughMetadata.class);
203                regProcessorFactory.setId(".camelBlueprint.processor.registry.passThrough." + contextId);
204                regProcessorFactory.setObject(new PassThroughCallable<Object>(new CamelDependenciesFinder(contextId, context)));
205    
206                MutableBeanMetadata regProcessor = context.createMetadata(MutableBeanMetadata.class);
207                regProcessor.setId(".camelBlueprint.processor.registry." + contextId);
208                regProcessor.setRuntimeClass(CamelDependenciesFinder.class);
209                regProcessor.setFactoryComponent(regProcessorFactory);
210                regProcessor.setFactoryMethod("call");
211                regProcessor.setProcessor(true);
212                regProcessor.addDependsOn(".camelBlueprint.processor.bean." + contextId);
213                regProcessor.addProperty("blueprintContainer", createRef(context, "blueprintContainer"));
214                context.getComponentDefinitionRegistry().registerComponentDefinition(regProcessor);
215    
216                return ctx;
217            }
218            if (element.getNodeName().equals(ROUTE_CONTEXT)) {
219                // now lets parse the routes with JAXB
220                Binder<Node> binder;
221                try {
222                    binder = getJaxbContext().createBinder();
223                } catch (JAXBException e) {
224                    throw new ComponentDefinitionException("Failed to create the JAXB binder : " + e, e);
225                }
226                Object value = parseUsingJaxb(element, context, binder);
227                if (!(value instanceof CamelRouteContextFactoryBean)) {
228                    throw new ComponentDefinitionException("Expected an instance of " + CamelRouteContextFactoryBean.class);
229                }
230    
231                CamelRouteContextFactoryBean rcfb = (CamelRouteContextFactoryBean) value;
232                String id = rcfb.getId();
233    
234                MutablePassThroughMetadata factory = context.createMetadata(MutablePassThroughMetadata.class);
235                factory.setId(".camelBlueprint.passThrough." + id);
236                factory.setObject(new PassThroughCallable<Object>(rcfb));
237    
238                MutableBeanMetadata factory2 = context.createMetadata(MutableBeanMetadata.class);
239                factory2.setId(".camelBlueprint.factory." + id);
240                factory2.setFactoryComponent(factory);
241                factory2.setFactoryMethod("call");
242    
243                MutableBeanMetadata ctx = context.createMetadata(MutableBeanMetadata.class);
244                ctx.setId(id);
245                ctx.setRuntimeClass(List.class);
246                ctx.setFactoryComponent(factory2);
247                ctx.setFactoryMethod("getRoutes");
248    
249                return ctx;
250            }
251            return null;
252        }
253    
254        private void registerBeans(ParserContext context, String contextId, List<?> beans) {
255            if (beans != null) {
256                for (Object bean : beans) {
257                    if (bean instanceof AbstractCamelFactoryBean) {
258                        registerBean(context, contextId, (AbstractCamelFactoryBean) bean);
259                    }
260                }
261            }
262        }
263    
264        protected void registerBean(ParserContext context, String contextId, AbstractCamelFactoryBean<?> fact) {
265            String id = fact.getId();
266    
267            fact.setCamelContextId(contextId);
268    
269            MutablePassThroughMetadata eff = context.createMetadata(MutablePassThroughMetadata.class);
270            eff.setId(".camelBlueprint.bean.passthrough." + id);
271            eff.setObject(new PassThroughCallable<Object>(fact));
272    
273            MutableBeanMetadata ef = context.createMetadata(MutableBeanMetadata.class);
274            ef.setId(".camelBlueprint.bean.factory." + id);
275            ef.setFactoryComponent(eff);
276            ef.setFactoryMethod("call");
277            ef.addProperty("blueprintContainer", createRef(context, "blueprintContainer"));
278            ef.setInitMethod("afterPropertiesSet");
279            ef.setDestroyMethod("destroy");
280    
281            MutableBeanMetadata e = context.createMetadata(MutableBeanMetadata.class);
282            e.setId(id);
283            e.setRuntimeClass(fact.getObjectType());
284            e.setFactoryComponent(ef);
285            e.setFactoryMethod("getObject");
286    
287            context.getComponentDefinitionRegistry().registerComponentDefinition(e);
288        }
289    
290        protected BlueprintContainer getBlueprintContainer(ParserContext context) {
291            PassThroughMetadata ptm = (PassThroughMetadata) context.getComponentDefinitionRegistry().getComponentDefinition("blueprintContainer");
292            return (BlueprintContainer) ptm.getObject();
293        }
294    
295        public ComponentMetadata decorate(Node node, ComponentMetadata component, ParserContext context) {
296            return null;
297        }
298    
299        protected Object parseUsingJaxb(Element element, ParserContext parserContext, Binder<Node> binder) {
300            try {
301                return binder.unmarshal(element);
302            } catch (JAXBException e) {
303                throw new ComponentDefinitionException("Failed to parse JAXB element: " + e, e);
304            }
305        }
306    
307        public JAXBContext getJaxbContext() throws JAXBException {
308            if (jaxbContext == null) {
309                jaxbContext = createJaxbContext();
310            }
311            return jaxbContext;
312        }
313    
314        protected JAXBContext createJaxbContext() throws JAXBException {
315            StringBuilder packages = new StringBuilder();
316            for (Class cl : getJaxbPackages()) {
317                if (packages.length() > 0) {
318                    packages.append(":");
319                }
320                packages.append(cl.getName().substring(0, cl.getName().lastIndexOf('.')));
321            }
322            return JAXBContext.newInstance(packages.toString(), getClass().getClassLoader());
323        }
324    
325        protected Set<Class> getJaxbPackages() {
326            Set<Class> classes = new HashSet<Class>();
327            classes.add(CamelContextFactoryBean.class);
328            classes.add(AbstractCamelContextFactoryBean.class);
329            classes.add(org.apache.camel.ExchangePattern.class);
330            classes.add(org.apache.camel.model.RouteDefinition.class);
331            classes.add(org.apache.camel.model.config.StreamResequencerConfig.class);
332            classes.add(org.apache.camel.model.dataformat.DataFormatsDefinition.class);
333            classes.add(org.apache.camel.model.language.ExpressionDefinition.class);
334            classes.add(org.apache.camel.model.loadbalancer.RoundRobinLoadBalancerDefinition.class);
335            return classes;
336        }
337    
338        private ValueMetadata createValue(ParserContext context, String value) {
339            MutableValueMetadata v = context.createMetadata(MutableValueMetadata.class);
340            v.setStringValue(value);
341            return v;
342        }
343    
344        private RefMetadata createRef(ParserContext context, String value) {
345            MutableRefMetadata r = context.createMetadata(MutableRefMetadata.class);
346            r.setComponentId(value);
347            return r;
348        }
349    
350        public static class PassThroughCallable<T> implements Callable<T> {
351    
352            private T value;
353    
354            public PassThroughCallable(T value) {
355                this.value = value;
356            }
357    
358            public T call() throws Exception {
359                return value;
360            }
361        }
362    
363        public static class CamelInjector extends CamelPostProcessorHelper implements BeanProcessor {
364    
365            private final String camelContextName;
366            private BlueprintContainer blueprintContainer;
367    
368            public CamelInjector(String camelContextName) {
369                this.camelContextName = camelContextName;
370            }
371    
372            public void setBlueprintContainer(BlueprintContainer blueprintContainer) {
373                this.blueprintContainer = blueprintContainer;
374            }
375    
376            public Object beforeInit(Object bean, String beanName, BeanCreator beanCreator, BeanMetadata beanMetadata) {
377                injectFields(bean, beanName);
378                injectMethods(bean, beanName);
379                if (bean instanceof CamelContextAware) {
380                    ((CamelContextAware) bean).setCamelContext(getCamelContext());
381                }
382                return bean;
383            }
384    
385            @Override
386            public CamelContext getCamelContext() {
387                return (CamelContext) blueprintContainer.getComponentInstance(camelContextName);
388            }
389    
390            /**
391             * A strategy method to allow implementations to perform some custom JBI
392             * based injection of the POJO
393             *
394             * @param bean the bean to be injected
395             */
396            protected void injectFields(final Object bean, final String beanName) {
397                Class clazz = bean.getClass();
398                do {
399                    Field[] fields = clazz.getDeclaredFields();
400                    for (Field field : fields) {
401                        EndpointInject endpointInject = field.getAnnotation(EndpointInject.class);
402                        if (endpointInject != null && matchContext(endpointInject.context())) {
403                            injectField(field, endpointInject.uri(), endpointInject.ref(), bean, beanName);
404                        }
405    
406                        Produce produce = field.getAnnotation(Produce.class);
407                        if (produce != null && matchContext(produce.context())) {
408                            injectField(field, produce.uri(), produce.ref(), bean, beanName);
409                        }
410                    }
411                    clazz = clazz.getSuperclass();
412                } while (clazz != null && clazz != Object.class);
413            }
414    
415            protected void injectField(Field field, String endpointUri, String endpointRef, Object bean, String beanName) {
416                setField(field, bean, getInjectionValue(field.getType(), endpointUri, endpointRef, field.getName(), bean, beanName));
417            }
418    
419            protected static void setField(Field field, Object instance, Object value) {
420                try {
421                    boolean oldAccessible = field.isAccessible();
422                    boolean shouldSetAccessible = !Modifier.isPublic(field.getModifiers()) && !oldAccessible;
423                    if (shouldSetAccessible) {
424                        field.setAccessible(true);
425                    }
426                    field.set(instance, value);
427                    if (shouldSetAccessible) {
428                        field.setAccessible(oldAccessible);
429                    }
430                } catch (IllegalArgumentException ex) {
431                    throw new UnsupportedOperationException("Cannot inject value of class: " + value.getClass() + " into: " + field);
432                } catch (IllegalAccessException ex) {
433                    throw new IllegalStateException("Could not access method: " + ex.getMessage());
434                }
435            }
436    
437            protected void injectMethods(final Object bean, final String beanName) {
438                Class clazz = bean.getClass();
439                do {
440                    Method[] methods = clazz.getDeclaredMethods();
441                    for (Method method : methods) {
442                        setterInjection(method, bean, beanName);
443                        consumerInjection(method, bean, beanName);
444                    }
445                    clazz = clazz.getSuperclass();
446                } while (clazz != null && clazz != Object.class);
447            }
448    
449            protected void setterInjection(Method method, Object bean, String beanName) {
450                EndpointInject endpointInject = method.getAnnotation(EndpointInject.class);
451                if (endpointInject != null && matchContext(endpointInject.context())) {
452                    setterInjection(method, bean, beanName, endpointInject.uri(), endpointInject.ref());
453                }
454    
455                Produce produce = method.getAnnotation(Produce.class);
456                if (produce != null && matchContext(produce.context())) {
457                    setterInjection(method, bean, beanName, produce.uri(), produce.ref());
458                }
459            }
460    
461            protected void setterInjection(Method method, Object bean, String beanName, String endpointUri, String endpointRef) {
462                Class<?>[] parameterTypes = method.getParameterTypes();
463                if (parameterTypes != null) {
464                    if (parameterTypes.length != 1) {
465                        LOG.warn("Ignoring badly annotated method for injection due to incorrect number of parameters: " + method);
466                    } else {
467                        String propertyName = ObjectHelper.getPropertyName(method);
468                        Object value = getInjectionValue(parameterTypes[0], endpointUri, endpointRef, propertyName, bean, beanName);
469                        ObjectHelper.invokeMethod(method, bean, value);
470                    }
471                }
472            }
473    
474            public Object afterInit(Object o, String s, BeanCreator beanCreator, BeanMetadata beanMetadata) {
475                return o;
476            }
477    
478            public void beforeDestroy(Object o, String s) {
479            }
480    
481            public void afterDestroy(Object o, String s) {
482            }
483    
484        }
485    
486        public static class CamelDependenciesFinder implements ComponentDefinitionRegistryProcessor {
487    
488            private final String camelContextName;
489            private final ParserContext context;
490            private BlueprintContainer blueprintContainer;
491    
492            public CamelDependenciesFinder(String camelContextName, ParserContext context) {
493                this.camelContextName = camelContextName;
494                this.context = context;
495            }
496    
497            public void setBlueprintContainer(BlueprintContainer blueprintContainer) {
498                this.blueprintContainer = blueprintContainer;
499            }
500    
501            public void process(ComponentDefinitionRegistry componentDefinitionRegistry) {
502                CamelContext camelContext = (CamelContext) blueprintContainer.getComponentInstance(camelContextName);
503    
504                Set<String> components = new HashSet<String>();
505                Set<String> languages = new HashSet<String>();
506                Set<String> dataformats = new HashSet<String>();
507                Set<String> dependsOn = new HashSet<String>();
508                for (RouteDefinition rd : camelContext.getRouteDefinitions()) {
509                    findInputComponents(rd.getInputs(), components, languages, dataformats);
510                    findOutputComponents(rd.getOutputs(), components, languages, dataformats);
511                }
512                try {
513                    for (String component : components) {
514                        ComponentMetadata cm = componentDefinitionRegistry.getComponentDefinition(".camelBlueprint.componentResolver." + component);
515                        if (cm == null) {
516                            MutableReferenceMetadata svc = createMetadata(MutableReferenceMetadata.class);
517                            svc.setId(".camelBlueprint.componentResolver." + component);
518                            svc.setFilter("(component=" + component + ")");
519                            svc.setAvailability(componentDefinitionRegistry.containsComponentDefinition(component) ? AVAILABILITY_OPTIONAL : AVAILABILITY_MANDATORY);
520                            try {
521                                // Try to set the runtime interface (only with aries blueprint > 0.1
522                                svc.getClass().getMethod("setRuntimeInterface", Class.class).invoke(svc, ComponentResolver.class);
523                            } catch (Throwable t) {
524                                // Check if the bundle can see the class
525                                try {
526                                    PassThroughMetadata ptm = (PassThroughMetadata) componentDefinitionRegistry.getComponentDefinition("blueprintBundle");
527                                    Bundle b = (Bundle) ptm.getObject();
528                                    if (b.loadClass(ComponentResolver.class.getName()) != ComponentResolver.class) {
529                                        throw new UnsupportedOperationException();
530                                    }
531                                    svc.setInterface(ComponentResolver.class.getName());
532                                } catch (Throwable t2) {
533                                    throw new UnsupportedOperationException();
534                                }
535                            }
536                            componentDefinitionRegistry.registerComponentDefinition(svc);
537                            dependsOn.add(svc.getId());
538                        }
539                    }
540                    for (String language : languages) {
541                        ComponentMetadata cm = componentDefinitionRegistry.getComponentDefinition(".camelBlueprint.languageResolver." + language);
542                        if (cm == null) {
543                            MutableReferenceMetadata svc = createMetadata(MutableReferenceMetadata.class);
544                            svc.setId(".camelBlueprint.languageResolver." + language);
545                            svc.setFilter("(language=" + language + ")");
546                            svc.setAvailability(componentDefinitionRegistry.containsComponentDefinition(language) ? AVAILABILITY_OPTIONAL : AVAILABILITY_MANDATORY);
547                            try {
548                                // Try to set the runtime interface (only with aries blueprint > 0.1
549                                svc.getClass().getMethod("setRuntimeInterface", Class.class).invoke(svc, LanguageResolver.class);
550                            } catch (Throwable t) {
551                                // Check if the bundle can see the class
552                                try {
553                                    PassThroughMetadata ptm = (PassThroughMetadata) componentDefinitionRegistry.getComponentDefinition("blueprintBundle");
554                                    Bundle b = (Bundle) ptm.getObject();
555                                    if (b.loadClass(LanguageResolver.class.getName()) != LanguageResolver.class) {
556                                        throw new UnsupportedOperationException();
557                                    }
558                                    svc.setInterface(LanguageResolver.class.getName());
559                                } catch (Throwable t2) {
560                                    throw new UnsupportedOperationException();
561                                }
562                            }
563                            componentDefinitionRegistry.registerComponentDefinition(svc);
564                            dependsOn.add(svc.getId());
565                        }
566                    }
567                    for (String dataformat : dataformats) {
568                        ComponentMetadata cm = componentDefinitionRegistry.getComponentDefinition(".camelBlueprint.dataformatResolver." + dataformat);
569                        if (cm == null) {
570                            MutableReferenceMetadata svc = createMetadata(MutableReferenceMetadata.class);
571                            svc.setId(".camelBlueprint.dataformatResolver." + dataformat);
572                            svc.setFilter("(dataformat=" + dataformat + ")");
573                            svc.setAvailability(componentDefinitionRegistry.containsComponentDefinition(dataformat) ? AVAILABILITY_OPTIONAL : AVAILABILITY_MANDATORY);
574                            try {
575                                // Try to set the runtime interface (only with aries blueprint > 0.1
576                                svc.getClass().getMethod("setRuntimeInterface", Class.class).invoke(svc, DataFormatResolver.class);
577                            } catch (Throwable t) {
578                                // Check if the bundle can see the class
579                                try {
580                                    PassThroughMetadata ptm = (PassThroughMetadata) componentDefinitionRegistry.getComponentDefinition("blueprintBundle");
581                                    Bundle b = (Bundle) ptm.getObject();
582                                    if (b.loadClass(DataFormatResolver.class.getName()) != DataFormatResolver.class) {
583                                        throw new UnsupportedOperationException();
584                                    }
585                                    svc.setInterface(DataFormatResolver.class.getName());
586                                } catch (Throwable t2) {
587                                    throw new UnsupportedOperationException();
588                                }
589                            }
590                            componentDefinitionRegistry.registerComponentDefinition(svc);
591                            dependsOn.add(svc.getId());
592                        }
593                    }
594                } catch (UnsupportedOperationException e) {
595                    LOG.warn("Unable to add dependencies on to camel components OSGi services.  "
596                            + "The Apache Aries blueprint implementation used it too old and the blueprint bundle can not see the org.apache.camel.spi package.");
597                    components.clear();
598                    languages.clear();
599                    dataformats.clear();
600                }
601    
602    
603            }
604    
605            public <T extends org.osgi.service.blueprint.reflect.Metadata> T createMetadata(java.lang.Class<T> tClass) {
606                return context.createMetadata(tClass);
607            }
608    
609            private void findInputComponents(List<FromDefinition> defs, Set<String> components, Set<String> languages, Set<String> dataformats) {
610                if (defs != null) {
611                    for (FromDefinition def : defs) {
612                        findUriComponent(def.getUri(), components);
613                    }
614                }
615            }
616    
617            @SuppressWarnings("unchecked")
618            private void findOutputComponents(List<ProcessorDefinition> defs, Set<String> components, Set<String> languages, Set<String> dataformats) {
619                if (defs != null) {
620                    for (ProcessorDefinition def : defs) {
621                        if (def instanceof SendDefinition) {
622                            findUriComponent(((SendDefinition) def).getUri(), components);
623                        }
624                        if (def instanceof MarshalDefinition) {
625                            findDataFormat(((MarshalDefinition) def).getDataFormatType(), dataformats);
626                        }
627                        if (def instanceof UnmarshalDefinition) {
628                            findDataFormat(((UnmarshalDefinition) def).getDataFormatType(), dataformats);
629                        }
630                        if (def instanceof ExpressionNode) {
631                            findLanguage(((ExpressionNode) def).getExpression(), languages);
632                        }
633                        if (def instanceof ResequenceDefinition) {
634                            findLanguage(((ResequenceDefinition) def).getExpressions(), languages);
635                        }
636                        if (def instanceof AggregateDefinition) {
637                            findLanguage(((AggregateDefinition) def).getExpression(), languages);
638                            findLanguage(((AggregateDefinition) def).getCorrelationExpression(), languages);
639                            findLanguage(((AggregateDefinition) def).getCompletionPredicate(), languages);
640                            findLanguage(((AggregateDefinition) def).getCompletionTimeoutExpression(), languages);
641                            findLanguage(((AggregateDefinition) def).getCompletionSizeExpression(), languages);
642                        }
643                        if (def instanceof CatchDefinition) {
644                            findLanguage(((CatchDefinition) def).getHandled(), languages);
645                        }
646                        if (def instanceof OnExceptionDefinition) {
647                            findLanguage(((OnExceptionDefinition) def).getRetryWhile(), languages);
648                            findLanguage(((OnExceptionDefinition) def).getHandled(), languages);
649                            findLanguage(((OnExceptionDefinition) def).getContinued(), languages);
650                        }
651                        if (def instanceof SortDefinition) {
652                            findLanguage(((SortDefinition) def).getExpression(), languages);
653                        }
654                        if (def instanceof WireTapDefinition) {
655                            findLanguage(((WireTapDefinition) def).getNewExchangeExpression(), languages);
656                        }
657                        findOutputComponents(def.getOutputs(), components, languages, dataformats);
658                    }
659                }
660            }
661    
662            private void findLanguage(ExpressionDefinition expression, Set<String> languages) {
663                if (expression != null) {
664                    String lang = expression.getLanguage();
665                    if (lang != null && lang.length() > 0) {
666                        languages.add(lang);
667                    }
668                }
669            }
670    
671            private void findLanguage(List<ExpressionDefinition> expressions, Set<String> languages) {
672                if (expressions != null) {
673                    for (ExpressionDefinition e : expressions) {
674                        findLanguage(e, languages);
675                    }
676                }
677            }
678    
679            private void findLanguage(ExpressionSubElementDefinition expression, Set<String> languages) {
680                if (expression != null) {
681                    findLanguage(expression.getExpressionType(), languages);
682                }
683            }
684    
685            private void findDataFormat(DataFormatDefinition dfd, Set<String> dataformats) {
686                if (dfd != null && dfd.getDataFormatName() != null) {
687                    dataformats.add(dfd.getDataFormatName());
688                }
689            }
690    
691            private void findUriComponent(String uri, Set<String> components) {
692                if (uri != null) {
693                    String splitURI[] = ObjectHelper.splitOnCharacter(uri, ":", 2);
694                    if (splitURI[1] != null) {
695                        String scheme = splitURI[0];
696                        components.add(scheme);
697                    }
698                }
699            }
700    
701        }
702    
703    }