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