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