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    public class CamelNamespaceHandler implements NamespaceHandler {
093    
094        private static final String CAMEL_CONTEXT = "camelContext";
095        private static final String ROUTE_CONTEXT = "routeContext";
096    
097        private static final String SPRING_NS = "http://camel.apache.org/schema/spring";
098        private static final String BLUEPRINT_NS = "http://camel.apache.org/schema/blueprint";
099    
100        private static final transient Log LOG = LogFactory.getLog(CamelNamespaceHandler.class);
101    
102        private JAXBContext jaxbContext;
103    
104        public static void renameNamespaceRecursive(Node node) {
105            if (node.getNodeType() == Node.ELEMENT_NODE) {
106                Document doc = node.getOwnerDocument();
107                if (((Element) node).getNamespaceURI().equals(BLUEPRINT_NS)) {
108                    doc.renameNode(node, SPRING_NS, node.getNodeName());
109                }
110            }
111            NodeList list = node.getChildNodes();
112            for (int i = 0; i < list.getLength(); ++i) {
113                renameNamespaceRecursive(list.item(i));
114            }
115        }
116    
117        public URL getSchemaLocation(String namespace) {
118            return getClass().getClassLoader().getResource("camel-blueprint.xsd");
119        }
120    
121        @SuppressWarnings("unchecked")
122        public Set<Class> getManagedClasses() {
123            return new HashSet<Class>(Arrays.asList(
124                    BlueprintCamelContext.class
125            ));
126        }
127    
128        public Metadata parse(Element element, ParserContext context) {
129            renameNamespaceRecursive(element);
130            if (element.getNodeName().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.getNodeName().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                            try {
517                                // Try to set the runtime interface (only with aries blueprint > 0.1
518                                svc.getClass().getMethod("setRuntimeInterface", Class.class).invoke(svc, ComponentResolver.class);
519                            } catch (Throwable t) {
520                                // Check if the bundle can see the class
521                                try {
522                                    PassThroughMetadata ptm = (PassThroughMetadata) componentDefinitionRegistry.getComponentDefinition("blueprintBundle");
523                                    Bundle b = (Bundle) ptm.getObject();
524                                    if (b.loadClass(ComponentResolver.class.getName()) != ComponentResolver.class) {
525                                        throw new UnsupportedOperationException();
526                                    }
527                                    svc.setInterface(ComponentResolver.class.getName());
528                                } catch (Throwable t2) {
529                                    throw new UnsupportedOperationException();
530                                }
531                            }
532                            componentDefinitionRegistry.registerComponentDefinition(svc);
533                            dependsOn.add(svc.getId());
534                        }
535                    }
536                    for (String language : languages) {
537                        ComponentMetadata cm = componentDefinitionRegistry.getComponentDefinition(".camelBlueprint.languageResolver." + language);
538                        if (cm == null) {
539                            MutableReferenceMetadata svc = createMetadata(MutableReferenceMetadata.class);
540                            svc.setId(".camelBlueprint.languageResolver." + language);
541                            svc.setFilter("(language=" + language + ")");
542                            try {
543                                // Try to set the runtime interface (only with aries blueprint > 0.1
544                                svc.getClass().getMethod("setRuntimeInterface", Class.class).invoke(svc, LanguageResolver.class);
545                            } catch (Throwable t) {
546                                // Check if the bundle can see the class
547                                try {
548                                    PassThroughMetadata ptm = (PassThroughMetadata) componentDefinitionRegistry.getComponentDefinition("blueprintBundle");
549                                    Bundle b = (Bundle) ptm.getObject();
550                                    if (b.loadClass(LanguageResolver.class.getName()) != LanguageResolver.class) {
551                                        throw new UnsupportedOperationException();
552                                    }
553                                    svc.setInterface(LanguageResolver.class.getName());
554                                } catch (Throwable t2) {
555                                    throw new UnsupportedOperationException();
556                                }
557                            }
558                            componentDefinitionRegistry.registerComponentDefinition(svc);
559                            dependsOn.add(svc.getId());
560                        }
561                    }
562                    for (String dataformat : dataformats) {
563                        ComponentMetadata cm = componentDefinitionRegistry.getComponentDefinition(".camelBlueprint.dataformatResolver." + dataformat);
564                        if (cm == null) {
565                            MutableReferenceMetadata svc = createMetadata(MutableReferenceMetadata.class);
566                            svc.setId(".camelBlueprint.dataformatResolver." + dataformat);
567                            svc.setFilter("(dataformat=" + dataformat + ")");
568                            try {
569                                // Try to set the runtime interface (only with aries blueprint > 0.1
570                                svc.getClass().getMethod("setRuntimeInterface", Class.class).invoke(svc, DataFormatResolver.class);
571                            } catch (Throwable t) {
572                                // Check if the bundle can see the class
573                                try {
574                                    PassThroughMetadata ptm = (PassThroughMetadata) componentDefinitionRegistry.getComponentDefinition("blueprintBundle");
575                                    Bundle b = (Bundle) ptm.getObject();
576                                    if (b.loadClass(DataFormatResolver.class.getName()) != DataFormatResolver.class) {
577                                        throw new UnsupportedOperationException();
578                                    }
579                                    svc.setInterface(DataFormatResolver.class.getName());
580                                } catch (Throwable t2) {
581                                    throw new UnsupportedOperationException();
582                                }
583                            }
584                            componentDefinitionRegistry.registerComponentDefinition(svc);
585                            dependsOn.add(svc.getId());
586                        }
587                    }
588                } catch (UnsupportedOperationException e) {
589                    LOG.warn("Unable to add dependencies on to camel components OSGi services.  "
590                            + "The Apache Aries blueprint implementation used it too old and the blueprint bundle can not see the org.apache.camel.spi package.");
591                    components.clear();
592                    languages.clear();
593                    dataformats.clear();
594                }
595    
596    
597            }
598    
599            public <T extends org.osgi.service.blueprint.reflect.Metadata> T createMetadata(java.lang.Class<T> tClass) {
600                return context.createMetadata(tClass);
601            }
602    
603            private void findInputComponents(List<FromDefinition> defs, Set<String> components, Set<String> languages, Set<String> dataformats) {
604                if (defs != null) {
605                    for (FromDefinition def : defs) {
606                        findUriComponent(def.getUri(), components);
607                    }
608                }
609            }
610    
611            @SuppressWarnings("unchecked")
612            private void findOutputComponents(List<ProcessorDefinition> defs, Set<String> components, Set<String> languages, Set<String> dataformats) {
613                if (defs != null) {
614                    for (ProcessorDefinition def : defs) {
615                        if (def instanceof SendDefinition) {
616                            findUriComponent(((SendDefinition) def).getUri(), components);
617                        }
618                        if (def instanceof MarshalDefinition) {
619                            findDataFormat(((MarshalDefinition) def).getDataFormatType(), dataformats);
620                        }
621                        if (def instanceof UnmarshalDefinition) {
622                            findDataFormat(((UnmarshalDefinition) def).getDataFormatType(), dataformats);
623                        }
624                        if (def instanceof ExpressionNode) {
625                            findLanguage(((ExpressionNode) def).getExpression(), languages);
626                        }
627                        if (def instanceof ResequenceDefinition) {
628                            findLanguage(((ResequenceDefinition) def).getExpressions(), languages);
629                        }
630                        if (def instanceof AggregateDefinition) {
631                            findLanguage(((AggregateDefinition) def).getExpression(), languages);
632                            findLanguage(((AggregateDefinition) def).getCorrelationExpression(), languages);
633                            findLanguage(((AggregateDefinition) def).getCompletionPredicate(), languages);
634                            findLanguage(((AggregateDefinition) def).getCompletionTimeoutExpression(), languages);
635                            findLanguage(((AggregateDefinition) def).getCompletionSizeExpression(), languages);
636                        }
637                        if (def instanceof CatchDefinition) {
638                            findLanguage(((CatchDefinition) def).getHandled(), languages);
639                        }
640                        if (def instanceof OnExceptionDefinition) {
641                            findLanguage(((OnExceptionDefinition) def).getRetryWhile(), languages);
642                            findLanguage(((OnExceptionDefinition) def).getHandled(), languages);
643                            findLanguage(((OnExceptionDefinition) def).getContinued(), languages);
644                        }
645                        if (def instanceof SortDefinition) {
646                            findLanguage(((SortDefinition) def).getExpression(), languages);
647                        }
648                        if (def instanceof WireTapDefinition) {
649                            findLanguage(((WireTapDefinition) def).getNewExchangeExpression(), languages);
650                        }
651                        findOutputComponents(def.getOutputs(), components, languages, dataformats);
652                    }
653                }
654            }
655    
656            private void findLanguage(ExpressionDefinition expression, Set<String> languages) {
657                if (expression != null) {
658                    String lang = expression.getLanguage();
659                    if (lang != null && lang.length() > 0) {
660                        languages.add(lang);
661                    }
662                }
663            }
664    
665            private void findLanguage(List<ExpressionDefinition> expressions, Set<String> languages) {
666                if (expressions != null) {
667                    for (ExpressionDefinition e : expressions) {
668                        findLanguage(e, languages);
669                    }
670                }
671            }
672    
673            private void findLanguage(ExpressionSubElementDefinition expression, Set<String> languages) {
674                if (expression != null) {
675                    findLanguage(expression.getExpressionType(), languages);
676                }
677            }
678    
679            private void findDataFormat(DataFormatDefinition dfd, Set<String> dataformats) {
680                if (dfd != null && dfd.getDataFormatName() != null) {
681                    dataformats.add(dfd.getDataFormatName());
682                }
683            }
684    
685            private void findUriComponent(String uri, Set<String> components) {
686                if (uri != null) {
687                    String splitURI[] = ObjectHelper.splitOnCharacter(uri, ":", 2);
688                    if (splitURI[1] != null) {
689                        String scheme = splitURI[0];
690                        components.add(scheme);
691                    }
692                }
693            }
694    
695        }
696    
697    }