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