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 }