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