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