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 }