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 */ 017package org.apache.camel.blueprint.handler; 018 019import java.io.UnsupportedEncodingException; 020import java.lang.reflect.Field; 021import java.lang.reflect.Method; 022import java.lang.reflect.Modifier; 023import java.net.URI; 024import java.net.URISyntaxException; 025import java.net.URL; 026import java.util.Arrays; 027import java.util.HashSet; 028import java.util.List; 029import java.util.Map; 030import java.util.Set; 031import java.util.concurrent.Callable; 032import javax.xml.bind.Binder; 033import javax.xml.bind.JAXBContext; 034import javax.xml.bind.JAXBException; 035 036import org.w3c.dom.Document; 037import org.w3c.dom.Element; 038import org.w3c.dom.NamedNodeMap; 039import org.w3c.dom.Node; 040import org.w3c.dom.NodeList; 041 042import org.apache.aries.blueprint.BeanProcessor; 043import org.apache.aries.blueprint.ComponentDefinitionRegistry; 044import org.apache.aries.blueprint.ComponentDefinitionRegistryProcessor; 045import org.apache.aries.blueprint.NamespaceHandler; 046import org.apache.aries.blueprint.ParserContext; 047import org.apache.aries.blueprint.PassThroughMetadata; 048import org.apache.aries.blueprint.mutable.MutableBeanMetadata; 049import org.apache.aries.blueprint.mutable.MutablePassThroughMetadata; 050import org.apache.aries.blueprint.mutable.MutableRefMetadata; 051import org.apache.aries.blueprint.mutable.MutableReferenceMetadata; 052import org.apache.camel.BeanInject; 053import org.apache.camel.CamelContext; 054import org.apache.camel.Endpoint; 055import org.apache.camel.EndpointInject; 056import org.apache.camel.Produce; 057import org.apache.camel.PropertyInject; 058import org.apache.camel.blueprint.BlueprintCamelContext; 059import org.apache.camel.blueprint.BlueprintCamelStateService; 060import org.apache.camel.blueprint.BlueprintModelJAXBContextFactory; 061import org.apache.camel.blueprint.CamelContextFactoryBean; 062import org.apache.camel.blueprint.CamelEndpointFactoryBean; 063import org.apache.camel.blueprint.CamelRestContextFactoryBean; 064import org.apache.camel.blueprint.CamelRouteContextFactoryBean; 065import org.apache.camel.builder.xml.Namespaces; 066import org.apache.camel.component.properties.PropertiesComponent; 067import org.apache.camel.core.xml.AbstractCamelFactoryBean; 068import org.apache.camel.impl.CamelPostProcessorHelper; 069import org.apache.camel.impl.DefaultCamelContextNameStrategy; 070import org.apache.camel.model.AggregateDefinition; 071import org.apache.camel.model.CatchDefinition; 072import org.apache.camel.model.DataFormatDefinition; 073import org.apache.camel.model.ExpressionNode; 074import org.apache.camel.model.ExpressionSubElementDefinition; 075import org.apache.camel.model.FromDefinition; 076import org.apache.camel.model.MarshalDefinition; 077import org.apache.camel.model.OnExceptionDefinition; 078import org.apache.camel.model.ProcessorDefinition; 079import org.apache.camel.model.ResequenceDefinition; 080import org.apache.camel.model.RouteDefinition; 081import org.apache.camel.model.SendDefinition; 082import org.apache.camel.model.SortDefinition; 083import org.apache.camel.model.ToDefinition; 084import org.apache.camel.model.ToDynamicDefinition; 085import org.apache.camel.model.UnmarshalDefinition; 086import org.apache.camel.model.WireTapDefinition; 087import org.apache.camel.model.language.ExpressionDefinition; 088import org.apache.camel.model.rest.RestBindingMode; 089import org.apache.camel.model.rest.RestDefinition; 090import org.apache.camel.model.rest.VerbDefinition; 091import org.apache.camel.spi.CamelContextNameStrategy; 092import org.apache.camel.spi.ComponentResolver; 093import org.apache.camel.spi.DataFormatResolver; 094import org.apache.camel.spi.LanguageResolver; 095import org.apache.camel.spi.NamespaceAware; 096import org.apache.camel.util.ObjectHelper; 097import org.apache.camel.util.URISupport; 098import org.apache.camel.util.blueprint.KeyStoreParametersFactoryBean; 099import org.apache.camel.util.blueprint.SSLContextParametersFactoryBean; 100import org.apache.camel.util.blueprint.SecureRandomParametersFactoryBean; 101import org.apache.camel.util.jsse.KeyStoreParameters; 102import org.apache.camel.util.jsse.SSLContextParameters; 103import org.apache.camel.util.jsse.SecureRandomParameters; 104import org.osgi.framework.Bundle; 105import org.osgi.service.blueprint.container.BlueprintContainer; 106import org.osgi.service.blueprint.container.ComponentDefinitionException; 107import org.osgi.service.blueprint.reflect.BeanMetadata; 108import org.osgi.service.blueprint.reflect.ComponentMetadata; 109import org.osgi.service.blueprint.reflect.Metadata; 110import org.osgi.service.blueprint.reflect.RefMetadata; 111import org.slf4j.Logger; 112import org.slf4j.LoggerFactory; 113 114import static org.osgi.service.blueprint.reflect.ComponentMetadata.ACTIVATION_LAZY; 115import static org.osgi.service.blueprint.reflect.ServiceReferenceMetadata.AVAILABILITY_MANDATORY; 116import static org.osgi.service.blueprint.reflect.ServiceReferenceMetadata.AVAILABILITY_OPTIONAL; 117 118/** 119 * Camel {@link NamespaceHandler} to parse the Camel related namespaces. 120 */ 121public class CamelNamespaceHandler implements NamespaceHandler { 122 123 public static final String BLUEPRINT_NS = "http://camel.apache.org/schema/blueprint"; 124 public static final String SPRING_NS = "http://camel.apache.org/schema/spring"; 125 126 private static final String CAMEL_CONTEXT = "camelContext"; 127 private static final String ROUTE_CONTEXT = "routeContext"; 128 private static final String REST_CONTEXT = "restContext"; 129 private static final String ENDPOINT = "endpoint"; 130 private static final String KEY_STORE_PARAMETERS = "keyStoreParameters"; 131 private static final String SECURE_RANDOM_PARAMETERS = "secureRandomParameters"; 132 private static final String SSL_CONTEXT_PARAMETERS = "sslContextParameters"; 133 134 private static final Logger LOG = LoggerFactory.getLogger(CamelNamespaceHandler.class); 135 136 private JAXBContext jaxbContext; 137 138 /** 139 * Prepares the nodes before parsing. 140 */ 141 public static void doBeforeParse(Node node, String fromNamespace, String toNamespace) { 142 if (node.getNodeType() == Node.ELEMENT_NODE) { 143 Document doc = node.getOwnerDocument(); 144 if (node.getNamespaceURI().equals(fromNamespace)) { 145 doc.renameNode(node, toNamespace, node.getLocalName()); 146 } 147 148 // remove whitespace noise from uri, xxxUri attributes, eg new lines, and tabs etc, which allows end users to format 149 // their Camel routes in more human readable format, but at runtime those attributes must be trimmed 150 // the parser removes most of the noise, but keeps double spaces in the attribute values 151 NamedNodeMap map = node.getAttributes(); 152 for (int i = 0; i < map.getLength(); i++) { 153 Node att = map.item(i); 154 if (att.getNodeName().equals("uri") || att.getNodeName().endsWith("Uri")) { 155 final String value = att.getNodeValue(); 156 String before = ObjectHelper.before(value, "?"); 157 String after = ObjectHelper.after(value, "?"); 158 159 if (before != null && after != null) { 160 // remove all double spaces in the uri parameters 161 String changed = after.replaceAll("\\s{2,}", ""); 162 if (!after.equals(changed)) { 163 String newAtr = before.trim() + "?" + changed.trim(); 164 LOG.debug("Removed whitespace noise from attribute {} -> {}", value, newAtr); 165 att.setNodeValue(newAtr); 166 } 167 } 168 } 169 } 170 } 171 NodeList list = node.getChildNodes(); 172 for (int i = 0; i < list.getLength(); ++i) { 173 doBeforeParse(list.item(i), fromNamespace, toNamespace); 174 } 175 } 176 177 public URL getSchemaLocation(String namespace) { 178 if (BLUEPRINT_NS.equals(namespace)) { 179 return getClass().getClassLoader().getResource("camel-blueprint.xsd"); 180 } 181 return null; 182 } 183 184 @SuppressWarnings({"rawtypes"}) 185 public Set<Class> getManagedClasses() { 186 return new HashSet<Class>(Arrays.asList(BlueprintCamelContext.class)); 187 } 188 189 public Metadata parse(Element element, ParserContext context) { 190 LOG.trace("Parsing element {}", element); 191 192 try { 193 // as the camel-core model namespace is Spring we need to rename from blueprint to spring 194 doBeforeParse(element, BLUEPRINT_NS, SPRING_NS); 195 196 if (element.getLocalName().equals(CAMEL_CONTEXT)) { 197 return parseCamelContextNode(element, context); 198 } 199 if (element.getLocalName().equals(ROUTE_CONTEXT)) { 200 return parseRouteContextNode(element, context); 201 } 202 if (element.getLocalName().equals(REST_CONTEXT)) { 203 return parseRestContextNode(element, context); 204 } 205 if (element.getLocalName().equals(ENDPOINT)) { 206 return parseEndpointNode(element, context); 207 } 208 if (element.getLocalName().equals(KEY_STORE_PARAMETERS)) { 209 return parseKeyStoreParametersNode(element, context); 210 } 211 if (element.getLocalName().equals(SECURE_RANDOM_PARAMETERS)) { 212 return parseSecureRandomParametersNode(element, context); 213 } 214 if (element.getLocalName().equals(SSL_CONTEXT_PARAMETERS)) { 215 return parseSSLContextParametersNode(element, context); 216 } 217 } finally { 218 // make sure to rename back so we leave the DOM as-is 219 doBeforeParse(element, SPRING_NS, BLUEPRINT_NS); 220 } 221 222 return null; 223 } 224 225 private Metadata parseCamelContextNode(Element element, ParserContext context) { 226 LOG.trace("Parsing CamelContext {}", element); 227 // Find the id, generate one if needed 228 String contextId = element.getAttribute("id"); 229 boolean implicitId = false; 230 231 // let's avoid folks having to explicitly give an ID to a camel context 232 if (ObjectHelper.isEmpty(contextId)) { 233 // if no explicit id was set then use a default auto generated name 234 CamelContextNameStrategy strategy = new DefaultCamelContextNameStrategy(); 235 contextId = strategy.getName(); 236 element.setAttributeNS(null, "id", contextId); 237 implicitId = true; 238 } 239 240 // now let's parse the routes with JAXB 241 Binder<Node> binder; 242 try { 243 binder = getJaxbContext().createBinder(); 244 } catch (JAXBException e) { 245 throw new ComponentDefinitionException("Failed to create the JAXB binder : " + e, e); 246 } 247 Object value = parseUsingJaxb(element, context, binder); 248 if (!(value instanceof CamelContextFactoryBean)) { 249 throw new ComponentDefinitionException("Expected an instance of " + CamelContextFactoryBean.class); 250 } 251 252 CamelContextFactoryBean ccfb = (CamelContextFactoryBean) value; 253 ccfb.setImplicitId(implicitId); 254 255 // The properties component is always used / created by the CamelContextFactoryBean 256 // so we need to ensure that the resolver is ready to use 257 ComponentMetadata propertiesComponentResolver = getComponentResolverReference(context, "properties"); 258 259 MutablePassThroughMetadata factory = context.createMetadata(MutablePassThroughMetadata.class); 260 factory.setId(".camelBlueprint.passThrough." + contextId); 261 factory.setObject(new PassThroughCallable<Object>(value)); 262 263 MutableBeanMetadata factory2 = context.createMetadata(MutableBeanMetadata.class); 264 factory2.setId(".camelBlueprint.factory." + contextId); 265 factory2.setFactoryComponent(factory); 266 factory2.setFactoryMethod("call"); 267 factory2.setInitMethod("afterPropertiesSet"); 268 factory2.setDestroyMethod("destroy"); 269 factory2.addProperty("blueprintContainer", createRef(context, "blueprintContainer")); 270 factory2.addProperty("bundleContext", createRef(context, "blueprintBundleContext")); 271 factory2.addDependsOn(propertiesComponentResolver.getId()); 272 // We need to add other components which the camel context dependsOn 273 if (ObjectHelper.isNotEmpty(ccfb.getDependsOn())) { 274 factory2.setDependsOn(Arrays.asList(ccfb.getDependsOn().split(" |,"))); 275 } 276 context.getComponentDefinitionRegistry().registerComponentDefinition(factory2); 277 278 MutableBeanMetadata ctx = context.createMetadata(MutableBeanMetadata.class); 279 ctx.setId(contextId); 280 ctx.setRuntimeClass(BlueprintCamelContext.class); 281 ctx.setFactoryComponent(factory2); 282 ctx.setFactoryMethod("getContext"); 283 ctx.addProperty("bundleStateService", createRef(context, ".camelBlueprint.bundleStateService")); 284 ctx.setInitMethod("init"); 285 ctx.setDestroyMethod("destroy"); 286 287 // Register factory beans 288 registerBeans(context, contextId, ccfb.getThreadPools()); 289 registerBeans(context, contextId, ccfb.getEndpoints()); 290 registerBeans(context, contextId, ccfb.getRedeliveryPolicies()); 291 registerBeans(context, contextId, ccfb.getBeansFactory()); 292 293 // Register single CamelBundleStateService - shared for all bundles and all Blueprint Camel contexts 294 registerBundleStateService(context); 295 296 // Register processors 297 MutablePassThroughMetadata beanProcessorFactory = context.createMetadata(MutablePassThroughMetadata.class); 298 beanProcessorFactory.setId(".camelBlueprint.processor.bean.passThrough." + contextId); 299 beanProcessorFactory.setObject(new PassThroughCallable<Object>(new CamelInjector(contextId))); 300 301 MutableBeanMetadata beanProcessor = context.createMetadata(MutableBeanMetadata.class); 302 beanProcessor.setId(".camelBlueprint.processor.bean." + contextId); 303 beanProcessor.setRuntimeClass(CamelInjector.class); 304 beanProcessor.setFactoryComponent(beanProcessorFactory); 305 beanProcessor.setFactoryMethod("call"); 306 beanProcessor.setProcessor(true); 307 beanProcessor.addProperty("blueprintContainer", createRef(context, "blueprintContainer")); 308 context.getComponentDefinitionRegistry().registerComponentDefinition(beanProcessor); 309 310 MutablePassThroughMetadata regProcessorFactory = context.createMetadata(MutablePassThroughMetadata.class); 311 regProcessorFactory.setId(".camelBlueprint.processor.registry.passThrough." + contextId); 312 regProcessorFactory.setObject(new PassThroughCallable<Object>(new CamelDependenciesFinder(contextId, context))); 313 314 MutableBeanMetadata regProcessor = context.createMetadata(MutableBeanMetadata.class); 315 regProcessor.setId(".camelBlueprint.processor.registry." + contextId); 316 regProcessor.setRuntimeClass(CamelDependenciesFinder.class); 317 regProcessor.setFactoryComponent(regProcessorFactory); 318 regProcessor.setFactoryMethod("call"); 319 regProcessor.setProcessor(true); 320 regProcessor.addDependsOn(".camelBlueprint.processor.bean." + contextId); 321 regProcessor.addProperty("blueprintContainer", createRef(context, "blueprintContainer")); 322 context.getComponentDefinitionRegistry().registerComponentDefinition(regProcessor); 323 324 // lets inject the namespaces into any namespace aware POJOs 325 injectNamespaces(element, binder); 326 327 LOG.trace("Parsing CamelContext done, returning {}", ctx); 328 return ctx; 329 } 330 331 protected void injectNamespaces(Element element, Binder<Node> binder) { 332 NodeList list = element.getChildNodes(); 333 Namespaces namespaces = null; 334 int size = list.getLength(); 335 for (int i = 0; i < size; i++) { 336 Node child = list.item(i); 337 if (child instanceof Element) { 338 Element childElement = (Element) child; 339 Object object = binder.getJAXBNode(child); 340 if (object instanceof NamespaceAware) { 341 NamespaceAware namespaceAware = (NamespaceAware) object; 342 if (namespaces == null) { 343 namespaces = new Namespaces(element); 344 } 345 namespaces.configure(namespaceAware); 346 } 347 injectNamespaces(childElement, binder); 348 } 349 } 350 } 351 352 private Metadata parseRouteContextNode(Element element, ParserContext context) { 353 LOG.trace("Parsing RouteContext {}", element); 354 // now parse the routes with JAXB 355 Binder<Node> binder; 356 try { 357 binder = getJaxbContext().createBinder(); 358 } catch (JAXBException e) { 359 360 throw new ComponentDefinitionException("Failed to create the JAXB binder : " + e, e); 361 } 362 Object value = parseUsingJaxb(element, context, binder); 363 if (!(value instanceof CamelRouteContextFactoryBean)) { 364 throw new ComponentDefinitionException("Expected an instance of " + CamelRouteContextFactoryBean.class); 365 } 366 367 CamelRouteContextFactoryBean rcfb = (CamelRouteContextFactoryBean) value; 368 String id = rcfb.getId(); 369 370 MutablePassThroughMetadata factory = context.createMetadata(MutablePassThroughMetadata.class); 371 factory.setId(".camelBlueprint.passThrough." + id); 372 factory.setObject(new PassThroughCallable<Object>(rcfb)); 373 374 MutableBeanMetadata factory2 = context.createMetadata(MutableBeanMetadata.class); 375 factory2.setId(".camelBlueprint.factory." + id); 376 factory2.setFactoryComponent(factory); 377 factory2.setFactoryMethod("call"); 378 379 MutableBeanMetadata ctx = context.createMetadata(MutableBeanMetadata.class); 380 ctx.setId(id); 381 ctx.setRuntimeClass(List.class); 382 ctx.setFactoryComponent(factory2); 383 ctx.setFactoryMethod("getRoutes"); 384 // must be lazy as we want CamelContext to be activated first 385 ctx.setActivation(ACTIVATION_LAZY); 386 387 // lets inject the namespaces into any namespace aware POJOs 388 injectNamespaces(element, binder); 389 390 LOG.trace("Parsing RouteContext done, returning {}", element, ctx); 391 return ctx; 392 } 393 394 private Metadata parseRestContextNode(Element element, ParserContext context) { 395 LOG.trace("Parsing RestContext {}", element); 396 // now parse the rests with JAXB 397 Binder<Node> binder; 398 try { 399 binder = getJaxbContext().createBinder(); 400 } catch (JAXBException e) { 401 throw new ComponentDefinitionException("Failed to create the JAXB binder : " + e, e); 402 } 403 Object value = parseUsingJaxb(element, context, binder); 404 if (!(value instanceof CamelRestContextFactoryBean)) { 405 throw new ComponentDefinitionException("Expected an instance of " + CamelRestContextFactoryBean.class); 406 } 407 408 CamelRestContextFactoryBean rcfb = (CamelRestContextFactoryBean) value; 409 String id = rcfb.getId(); 410 411 MutablePassThroughMetadata factory = context.createMetadata(MutablePassThroughMetadata.class); 412 factory.setId(".camelBlueprint.passThrough." + id); 413 factory.setObject(new PassThroughCallable<Object>(rcfb)); 414 415 MutableBeanMetadata factory2 = context.createMetadata(MutableBeanMetadata.class); 416 factory2.setId(".camelBlueprint.factory." + id); 417 factory2.setFactoryComponent(factory); 418 factory2.setFactoryMethod("call"); 419 420 MutableBeanMetadata ctx = context.createMetadata(MutableBeanMetadata.class); 421 ctx.setId(id); 422 ctx.setRuntimeClass(List.class); 423 ctx.setFactoryComponent(factory2); 424 ctx.setFactoryMethod("getRests"); 425 // must be lazy as we want CamelContext to be activated first 426 ctx.setActivation(ACTIVATION_LAZY); 427 428 // lets inject the namespaces into any namespace aware POJOs 429 injectNamespaces(element, binder); 430 431 LOG.trace("Parsing RestContext done, returning {}", element, ctx); 432 return ctx; 433 } 434 435 private Metadata parseEndpointNode(Element element, ParserContext context) { 436 LOG.trace("Parsing Endpoint {}", element); 437 // now parse the rests with JAXB 438 Binder<Node> binder; 439 try { 440 binder = getJaxbContext().createBinder(); 441 } catch (JAXBException e) { 442 throw new ComponentDefinitionException("Failed to create the JAXB binder : " + e, e); 443 } 444 Object value = parseUsingJaxb(element, context, binder); 445 if (!(value instanceof CamelEndpointFactoryBean)) { 446 throw new ComponentDefinitionException("Expected an instance of " + CamelEndpointFactoryBean.class); 447 } 448 449 CamelEndpointFactoryBean rcfb = (CamelEndpointFactoryBean) value; 450 String id = rcfb.getId(); 451 452 MutablePassThroughMetadata factory = context.createMetadata(MutablePassThroughMetadata.class); 453 factory.setId(".camelBlueprint.passThrough." + id); 454 factory.setObject(new PassThroughCallable<Object>(rcfb)); 455 456 MutableBeanMetadata factory2 = context.createMetadata(MutableBeanMetadata.class); 457 factory2.setId(".camelBlueprint.factory." + id); 458 factory2.setFactoryComponent(factory); 459 factory2.setFactoryMethod("call"); 460 factory2.setInitMethod("afterPropertiesSet"); 461 factory2.setDestroyMethod("destroy"); 462 factory2.addProperty("blueprintContainer", createRef(context, "blueprintContainer")); 463 464 MutableBeanMetadata ctx = context.createMetadata(MutableBeanMetadata.class); 465 ctx.setId(id); 466 ctx.setRuntimeClass(Endpoint.class); 467 ctx.setFactoryComponent(factory2); 468 ctx.setFactoryMethod("getObject"); 469 // must be lazy as we want CamelContext to be activated first 470 ctx.setActivation(ACTIVATION_LAZY); 471 472 LOG.trace("Parsing endpoint done, returning {}", element, ctx); 473 return ctx; 474 } 475 476 private Metadata parseKeyStoreParametersNode(Element element, ParserContext context) { 477 LOG.trace("Parsing KeyStoreParameters {}", element); 478 // now parse the key store parameters with JAXB 479 Binder<Node> binder; 480 try { 481 binder = getJaxbContext().createBinder(); 482 } catch (JAXBException e) { 483 throw new ComponentDefinitionException("Failed to create the JAXB binder : " + e, e); 484 } 485 Object value = parseUsingJaxb(element, context, binder); 486 if (!(value instanceof KeyStoreParametersFactoryBean)) { 487 throw new ComponentDefinitionException("Expected an instance of " + KeyStoreParametersFactoryBean.class); 488 } 489 490 KeyStoreParametersFactoryBean kspfb = (KeyStoreParametersFactoryBean) value; 491 String id = kspfb.getId(); 492 493 MutablePassThroughMetadata factory = context.createMetadata(MutablePassThroughMetadata.class); 494 factory.setId(".camelBlueprint.passThrough." + id); 495 factory.setObject(new PassThroughCallable<Object>(kspfb)); 496 497 MutableBeanMetadata factory2 = context.createMetadata(MutableBeanMetadata.class); 498 factory2.setId(".camelBlueprint.factory." + id); 499 factory2.setFactoryComponent(factory); 500 factory2.setFactoryMethod("call"); 501 factory2.setInitMethod("afterPropertiesSet"); 502 factory2.setDestroyMethod("destroy"); 503 factory2.addProperty("blueprintContainer", createRef(context, "blueprintContainer")); 504 505 MutableBeanMetadata ctx = context.createMetadata(MutableBeanMetadata.class); 506 ctx.setId(id); 507 ctx.setRuntimeClass(KeyStoreParameters.class); 508 ctx.setFactoryComponent(factory2); 509 ctx.setFactoryMethod("getObject"); 510 // must be lazy as we want CamelContext to be activated first 511 ctx.setActivation(ACTIVATION_LAZY); 512 513 LOG.trace("Parsing KeyStoreParameters done, returning {}", ctx); 514 return ctx; 515 } 516 517 private Metadata parseSecureRandomParametersNode(Element element, ParserContext context) { 518 LOG.trace("Parsing SecureRandomParameters {}", element); 519 // now parse the key store parameters with JAXB 520 Binder<Node> binder; 521 try { 522 binder = getJaxbContext().createBinder(); 523 } catch (JAXBException e) { 524 throw new ComponentDefinitionException("Failed to create the JAXB binder : " + e, e); 525 } 526 Object value = parseUsingJaxb(element, context, binder); 527 if (!(value instanceof SecureRandomParametersFactoryBean)) { 528 throw new ComponentDefinitionException("Expected an instance of " + SecureRandomParametersFactoryBean.class); 529 } 530 531 SecureRandomParametersFactoryBean srfb = (SecureRandomParametersFactoryBean) value; 532 String id = srfb.getId(); 533 534 MutablePassThroughMetadata factory = context.createMetadata(MutablePassThroughMetadata.class); 535 factory.setId(".camelBlueprint.passThrough." + id); 536 factory.setObject(new PassThroughCallable<Object>(srfb)); 537 538 MutableBeanMetadata factory2 = context.createMetadata(MutableBeanMetadata.class); 539 factory2.setId(".camelBlueprint.factory." + id); 540 factory2.setFactoryComponent(factory); 541 factory2.setFactoryMethod("call"); 542 factory2.setInitMethod("afterPropertiesSet"); 543 factory2.setDestroyMethod("destroy"); 544 factory2.addProperty("blueprintContainer", createRef(context, "blueprintContainer")); 545 546 MutableBeanMetadata ctx = context.createMetadata(MutableBeanMetadata.class); 547 ctx.setId(id); 548 ctx.setRuntimeClass(SecureRandomParameters.class); 549 ctx.setFactoryComponent(factory2); 550 ctx.setFactoryMethod("getObject"); 551 // must be lazy as we want CamelContext to be activated first 552 ctx.setActivation(ACTIVATION_LAZY); 553 554 LOG.trace("Parsing SecureRandomParameters done, returning {}", ctx); 555 return ctx; 556 } 557 558 private Metadata parseSSLContextParametersNode(Element element, ParserContext context) { 559 LOG.trace("Parsing SSLContextParameters {}", element); 560 // now parse the key store parameters with JAXB 561 Binder<Node> binder; 562 try { 563 binder = getJaxbContext().createBinder(); 564 } catch (JAXBException e) { 565 throw new ComponentDefinitionException("Failed to create the JAXB binder : " + e, e); 566 } 567 Object value = parseUsingJaxb(element, context, binder); 568 if (!(value instanceof SSLContextParametersFactoryBean)) { 569 throw new ComponentDefinitionException("Expected an instance of " + SSLContextParametersFactoryBean.class); 570 } 571 572 SSLContextParametersFactoryBean scpfb = (SSLContextParametersFactoryBean) value; 573 String id = scpfb.getId(); 574 575 MutablePassThroughMetadata factory = context.createMetadata(MutablePassThroughMetadata.class); 576 factory.setId(".camelBlueprint.passThrough." + id); 577 factory.setObject(new PassThroughCallable<Object>(scpfb)); 578 579 MutableBeanMetadata factory2 = context.createMetadata(MutableBeanMetadata.class); 580 factory2.setId(".camelBlueprint.factory." + id); 581 factory2.setFactoryComponent(factory); 582 factory2.setFactoryMethod("call"); 583 factory2.setInitMethod("afterPropertiesSet"); 584 factory2.setDestroyMethod("destroy"); 585 factory2.addProperty("blueprintContainer", createRef(context, "blueprintContainer")); 586 587 MutableBeanMetadata ctx = context.createMetadata(MutableBeanMetadata.class); 588 ctx.setId(id); 589 ctx.setRuntimeClass(SSLContextParameters.class); 590 ctx.setFactoryComponent(factory2); 591 ctx.setFactoryMethod("getObject"); 592 // must be lazy as we want CamelContext to be activated first 593 ctx.setActivation(ACTIVATION_LAZY); 594 595 LOG.trace("Parsing SSLContextParameters done, returning {}", ctx); 596 return ctx; 597 } 598 599 private void registerBeans(ParserContext context, String contextId, List<?> beans) { 600 if (beans != null) { 601 for (Object bean : beans) { 602 if (bean instanceof AbstractCamelFactoryBean) { 603 registerBean(context, contextId, (AbstractCamelFactoryBean<?>) bean); 604 } 605 } 606 } 607 } 608 609 protected void registerBean(ParserContext context, String contextId, AbstractCamelFactoryBean<?> fact) { 610 String id = fact.getId(); 611 612 fact.setCamelContextId(contextId); 613 614 MutablePassThroughMetadata eff = context.createMetadata(MutablePassThroughMetadata.class); 615 eff.setId(".camelBlueprint.bean.passthrough." + id); 616 eff.setObject(new PassThroughCallable<Object>(fact)); 617 618 MutableBeanMetadata ef = context.createMetadata(MutableBeanMetadata.class); 619 ef.setId(".camelBlueprint.bean.factory." + id); 620 ef.setFactoryComponent(eff); 621 ef.setFactoryMethod("call"); 622 ef.addProperty("blueprintContainer", createRef(context, "blueprintContainer")); 623 ef.setInitMethod("afterPropertiesSet"); 624 ef.setDestroyMethod("destroy"); 625 626 MutableBeanMetadata e = context.createMetadata(MutableBeanMetadata.class); 627 e.setId(id); 628 e.setRuntimeClass(fact.getObjectType()); 629 e.setFactoryComponent(ef); 630 e.setFactoryMethod("getObject"); 631 e.addDependsOn(".camelBlueprint.processor.bean." + contextId); 632 633 context.getComponentDefinitionRegistry().registerComponentDefinition(e); 634 } 635 636 /** 637 * There's single instance of {@link BlueprintCamelStateService} that's used by all Blueprint Camel contexts 638 * to inform about state of Camel contexts. If Karaf is available, this information will propagate to 639 * <em>extended bundle info</em>. 640 * See CAMEL-12980 641 * @param context 642 */ 643 private void registerBundleStateService(ParserContext context) { 644 ComponentDefinitionRegistry componentDefinitionRegistry = context.getComponentDefinitionRegistry(); 645 ComponentMetadata cm = componentDefinitionRegistry.getComponentDefinition(".camelBlueprint.bundleStateService"); 646 if (cm == null) { 647 MutableBeanMetadata ssm = context.createMetadata(MutableBeanMetadata.class); 648 ssm.setId(".camelBlueprint.bundleStateService"); 649 ssm.setRuntimeClass(BlueprintCamelStateService.class); 650 ssm.addProperty("bundleContext", createRef(context, "blueprintBundleContext")); 651 ssm.setInitMethod("init"); 652 ssm.setDestroyMethod("destroy"); 653 componentDefinitionRegistry.registerComponentDefinition(ssm); 654 } 655 } 656 657 protected BlueprintContainer getBlueprintContainer(ParserContext context) { 658 PassThroughMetadata ptm = (PassThroughMetadata) context.getComponentDefinitionRegistry().getComponentDefinition("blueprintContainer"); 659 return (BlueprintContainer) ptm.getObject(); 660 } 661 662 public ComponentMetadata decorate(Node node, ComponentMetadata component, ParserContext context) { 663 return null; 664 } 665 666 protected Object parseUsingJaxb(Element element, ParserContext parserContext, Binder<Node> binder) { 667 try { 668 return binder.unmarshal(element); 669 } catch (JAXBException e) { 670 throw new ComponentDefinitionException("Failed to parse JAXB element: " + e, e); 671 } 672 } 673 674 public JAXBContext getJaxbContext() throws JAXBException { 675 if (jaxbContext == null) { 676 jaxbContext = new BlueprintModelJAXBContextFactory(getClass().getClassLoader()).newJAXBContext(); 677 } 678 return jaxbContext; 679 } 680 681 private RefMetadata createRef(ParserContext context, String value) { 682 MutableRefMetadata r = context.createMetadata(MutableRefMetadata.class); 683 r.setComponentId(value); 684 return r; 685 } 686 687 private static ComponentMetadata getDataformatResolverReference(ParserContext context, String dataformat) { 688 // we cannot resolve dataformat names using property placeholders at this point in time 689 if (dataformat.startsWith(PropertiesComponent.DEFAULT_PREFIX_TOKEN)) { 690 return null; 691 } 692 ComponentDefinitionRegistry componentDefinitionRegistry = context.getComponentDefinitionRegistry(); 693 ComponentMetadata cm = componentDefinitionRegistry.getComponentDefinition(".camelBlueprint.dataformatResolver." + dataformat); 694 if (cm == null) { 695 MutableReferenceMetadata svc = context.createMetadata(MutableReferenceMetadata.class); 696 svc.setId(".camelBlueprint.dataformatResolver." + dataformat); 697 svc.setFilter("(dataformat=" + dataformat + ")"); 698 svc.setAvailability(componentDefinitionRegistry.containsComponentDefinition(dataformat) ? AVAILABILITY_OPTIONAL : AVAILABILITY_MANDATORY); 699 try { 700 // Try to set the runtime interface (only with aries blueprint > 0.1 701 svc.getClass().getMethod("setRuntimeInterface", Class.class).invoke(svc, DataFormatResolver.class); 702 } catch (Throwable t) { 703 // Check if the bundle can see the class 704 try { 705 PassThroughMetadata ptm = (PassThroughMetadata) componentDefinitionRegistry.getComponentDefinition("blueprintBundle"); 706 Bundle b = (Bundle) ptm.getObject(); 707 if (b.loadClass(DataFormatResolver.class.getName()) != DataFormatResolver.class) { 708 throw new UnsupportedOperationException(); 709 } 710 svc.setInterface(DataFormatResolver.class.getName()); 711 } catch (Throwable t2) { 712 throw new UnsupportedOperationException(); 713 } 714 } 715 componentDefinitionRegistry.registerComponentDefinition(svc); 716 cm = svc; 717 } 718 return cm; 719 } 720 721 private static ComponentMetadata getLanguageResolverReference(ParserContext context, String language) { 722 // we cannot resolve language names using property placeholders at this point in time 723 if (language.startsWith(PropertiesComponent.DEFAULT_PREFIX_TOKEN)) { 724 return null; 725 } 726 ComponentDefinitionRegistry componentDefinitionRegistry = context.getComponentDefinitionRegistry(); 727 ComponentMetadata cm = componentDefinitionRegistry.getComponentDefinition(".camelBlueprint.languageResolver." + language); 728 if (cm == null) { 729 MutableReferenceMetadata svc = context.createMetadata(MutableReferenceMetadata.class); 730 svc.setId(".camelBlueprint.languageResolver." + language); 731 svc.setFilter("(language=" + language + ")"); 732 svc.setAvailability(componentDefinitionRegistry.containsComponentDefinition(language) ? AVAILABILITY_OPTIONAL : AVAILABILITY_MANDATORY); 733 try { 734 // Try to set the runtime interface (only with aries blueprint > 0.1 735 svc.getClass().getMethod("setRuntimeInterface", Class.class).invoke(svc, LanguageResolver.class); 736 } catch (Throwable t) { 737 // Check if the bundle can see the class 738 try { 739 PassThroughMetadata ptm = (PassThroughMetadata) componentDefinitionRegistry.getComponentDefinition("blueprintBundle"); 740 Bundle b = (Bundle) ptm.getObject(); 741 if (b.loadClass(LanguageResolver.class.getName()) != LanguageResolver.class) { 742 throw new UnsupportedOperationException(); 743 } 744 svc.setInterface(LanguageResolver.class.getName()); 745 } catch (Throwable t2) { 746 throw new UnsupportedOperationException(); 747 } 748 } 749 componentDefinitionRegistry.registerComponentDefinition(svc); 750 cm = svc; 751 } 752 return cm; 753 } 754 755 private static ComponentMetadata getComponentResolverReference(ParserContext context, String component) { 756 // we cannot resolve component names using property placeholders at this point in time 757 if (component.startsWith(PropertiesComponent.DEFAULT_PREFIX_TOKEN)) { 758 return null; 759 } 760 ComponentDefinitionRegistry componentDefinitionRegistry = context.getComponentDefinitionRegistry(); 761 ComponentMetadata cm = componentDefinitionRegistry.getComponentDefinition(".camelBlueprint.componentResolver." + component); 762 if (cm == null) { 763 MutableReferenceMetadata svc = context.createMetadata(MutableReferenceMetadata.class); 764 svc.setId(".camelBlueprint.componentResolver." + component); 765 svc.setFilter("(component=" + component + ")"); 766 svc.setAvailability(componentDefinitionRegistry.containsComponentDefinition(component) ? AVAILABILITY_OPTIONAL : AVAILABILITY_MANDATORY); 767 try { 768 // Try to set the runtime interface (only with aries blueprint > 0.1 769 svc.getClass().getMethod("setRuntimeInterface", Class.class).invoke(svc, ComponentResolver.class); 770 } catch (Throwable t) { 771 // Check if the bundle can see the class 772 try { 773 PassThroughMetadata ptm = (PassThroughMetadata) componentDefinitionRegistry.getComponentDefinition("blueprintBundle"); 774 Bundle b = (Bundle) ptm.getObject(); 775 if (b.loadClass(ComponentResolver.class.getName()) != ComponentResolver.class) { 776 throw new UnsupportedOperationException(); 777 } 778 svc.setInterface(ComponentResolver.class.getName()); 779 } catch (Throwable t2) { 780 throw new UnsupportedOperationException(); 781 } 782 } 783 componentDefinitionRegistry.registerComponentDefinition(svc); 784 cm = svc; 785 } 786 return cm; 787 } 788 789 public static class PassThroughCallable<T> implements Callable<T> { 790 791 private T value; 792 793 public PassThroughCallable(T value) { 794 this.value = value; 795 } 796 797 public T call() throws Exception { 798 return value; 799 } 800 } 801 802 public static class CamelInjector extends CamelPostProcessorHelper implements BeanProcessor { 803 804 private final String camelContextName; 805 private BlueprintContainer blueprintContainer; 806 807 public CamelInjector(String camelContextName) { 808 this.camelContextName = camelContextName; 809 } 810 811 public void setBlueprintContainer(BlueprintContainer blueprintContainer) { 812 this.blueprintContainer = blueprintContainer; 813 } 814 815 @Override 816 public CamelContext getCamelContext() { 817 if (blueprintContainer != null) { 818 CamelContext answer = (CamelContext) blueprintContainer.getComponentInstance(camelContextName); 819 return answer; 820 } 821 return null; 822 } 823 824 public Object beforeInit(Object bean, String beanName, BeanCreator beanCreator, BeanMetadata beanMetadata) { 825 LOG.trace("Before init of bean: {} -> {}", beanName, bean); 826 // prefer to inject later in afterInit 827 return bean; 828 } 829 830 /** 831 * A strategy method to allow implementations to perform some custom JBI 832 * based injection of the POJO 833 * 834 * @param bean the bean to be injected 835 */ 836 protected void injectFields(final Object bean, final String beanName) { 837 Class<?> clazz = bean.getClass(); 838 do { 839 Field[] fields = clazz.getDeclaredFields(); 840 for (Field field : fields) { 841 PropertyInject propertyInject = field.getAnnotation(PropertyInject.class); 842 if (propertyInject != null && matchContext(propertyInject.context())) { 843 injectFieldProperty(field, propertyInject.value(), propertyInject.defaultValue(), bean, beanName); 844 } 845 846 BeanInject beanInject = field.getAnnotation(BeanInject.class); 847 if (beanInject != null && matchContext(beanInject.context())) { 848 injectFieldBean(field, beanInject.value(), bean, beanName); 849 } 850 851 EndpointInject endpointInject = field.getAnnotation(EndpointInject.class); 852 if (endpointInject != null && matchContext(endpointInject.context())) { 853 injectField(field, endpointInject.uri(), endpointInject.ref(), endpointInject.property(), bean, beanName); 854 } 855 856 Produce produce = field.getAnnotation(Produce.class); 857 if (produce != null && matchContext(produce.context())) { 858 injectField(field, produce.uri(), produce.ref(), produce.property(), bean, beanName); 859 } 860 } 861 clazz = clazz.getSuperclass(); 862 } while (clazz != null && clazz != Object.class); 863 } 864 865 protected void injectField(Field field, String endpointUri, String endpointRef, String endpointProperty, Object bean, String beanName) { 866 setField(field, bean, getInjectionValue(field.getType(), endpointUri, endpointRef, endpointProperty, field.getName(), bean, beanName)); 867 } 868 869 protected void injectFieldProperty(Field field, String propertyName, String propertyDefaultValue, Object bean, String beanName) { 870 setField(field, bean, getInjectionPropertyValue(field.getType(), propertyName, propertyDefaultValue, field.getName(), bean, beanName)); 871 } 872 873 public void injectFieldBean(Field field, String name, Object bean, String beanName) { 874 setField(field, bean, getInjectionBeanValue(field.getType(), name)); 875 } 876 877 protected static void setField(Field field, Object instance, Object value) { 878 try { 879 boolean oldAccessible = field.isAccessible(); 880 boolean shouldSetAccessible = !Modifier.isPublic(field.getModifiers()) && !oldAccessible; 881 if (shouldSetAccessible) { 882 field.setAccessible(true); 883 } 884 field.set(instance, value); 885 if (shouldSetAccessible) { 886 field.setAccessible(oldAccessible); 887 } 888 } catch (IllegalArgumentException ex) { 889 throw new UnsupportedOperationException("Cannot inject value of class: " + value.getClass() + " into: " + field); 890 } catch (IllegalAccessException ex) { 891 throw new IllegalStateException("Could not access method: " + ex.getMessage()); 892 } 893 } 894 895 protected void injectMethods(final Object bean, final String beanName) { 896 Class<?> clazz = bean.getClass(); 897 do { 898 Method[] methods = clazz.getDeclaredMethods(); 899 for (Method method : methods) { 900 setterInjection(method, bean, beanName); 901 consumerInjection(method, bean, beanName); 902 } 903 clazz = clazz.getSuperclass(); 904 } while (clazz != null && clazz != Object.class); 905 } 906 907 protected void setterInjection(Method method, Object bean, String beanName) { 908 PropertyInject propertyInject = method.getAnnotation(PropertyInject.class); 909 if (propertyInject != null && matchContext(propertyInject.context())) { 910 setterPropertyInjection(method, propertyInject.value(), propertyInject.defaultValue(), bean, beanName); 911 } 912 913 BeanInject beanInject = method.getAnnotation(BeanInject.class); 914 if (beanInject != null && matchContext(beanInject.context())) { 915 setterBeanInjection(method, beanInject.value(), bean, beanName); 916 } 917 918 EndpointInject endpointInject = method.getAnnotation(EndpointInject.class); 919 if (endpointInject != null && matchContext(endpointInject.context())) { 920 setterInjection(method, bean, beanName, endpointInject.uri(), endpointInject.ref(), endpointInject.property()); 921 } 922 923 Produce produce = method.getAnnotation(Produce.class); 924 if (produce != null && matchContext(produce.context())) { 925 setterInjection(method, bean, beanName, produce.uri(), produce.ref(), produce.property()); 926 } 927 } 928 929 protected void setterPropertyInjection(Method method, String propertyValue, String propertyDefaultValue, Object bean, String beanName) { 930 Class<?>[] parameterTypes = method.getParameterTypes(); 931 if (parameterTypes != null) { 932 if (parameterTypes.length != 1) { 933 LOG.warn("Ignoring badly annotated method for injection due to incorrect number of parameters: " + method); 934 } else { 935 String propertyName = ObjectHelper.getPropertyName(method); 936 Object value = getInjectionPropertyValue(parameterTypes[0], propertyValue, propertyDefaultValue, propertyName, bean, beanName); 937 ObjectHelper.invokeMethod(method, bean, value); 938 } 939 } 940 } 941 942 protected void setterBeanInjection(Method method, String name, Object bean, String beanName) { 943 Class<?>[] parameterTypes = method.getParameterTypes(); 944 if (parameterTypes != null) { 945 if (parameterTypes.length != 1) { 946 LOG.warn("Ignoring badly annotated method for injection due to incorrect number of parameters: " + method); 947 } else { 948 Object value = getInjectionBeanValue(parameterTypes[0], name); 949 ObjectHelper.invokeMethod(method, bean, value); 950 } 951 } 952 } 953 954 protected void setterInjection(Method method, Object bean, String beanName, String endpointUri, String endpointRef, String endpointProperty) { 955 Class<?>[] parameterTypes = method.getParameterTypes(); 956 if (parameterTypes != null) { 957 if (parameterTypes.length != 1) { 958 LOG.warn("Ignoring badly annotated method for injection due to incorrect number of parameters: " + method); 959 } else { 960 String propertyName = ObjectHelper.getPropertyName(method); 961 Object value = getInjectionValue(parameterTypes[0], endpointUri, endpointRef, endpointProperty, propertyName, bean, beanName); 962 ObjectHelper.invokeMethod(method, bean, value); 963 } 964 } 965 } 966 967 public Object afterInit(Object bean, String beanName, BeanCreator beanCreator, BeanMetadata beanMetadata) { 968 LOG.trace("After init of bean: {} -> {}", beanName, bean); 969 // we cannot inject CamelContextAware beans as the CamelContext may not be ready 970 injectFields(bean, beanName); 971 injectMethods(bean, beanName); 972 return bean; 973 } 974 975 public void beforeDestroy(Object bean, String beanName) { 976 } 977 978 public void afterDestroy(Object bean, String beanName) { 979 } 980 981 @Override 982 protected boolean isSingleton(Object bean, String beanName) { 983 if (beanName != null) { 984 ComponentMetadata meta = blueprintContainer.getComponentMetadata(beanName); 985 if (meta instanceof BeanMetadata) { 986 String scope = ((BeanMetadata) meta).getScope(); 987 if (scope != null) { 988 return BeanMetadata.SCOPE_SINGLETON.equals(scope); 989 } 990 } 991 } 992 // fallback to super, which will assume singleton 993 // for beans not implementing Camel's IsSingleton interface 994 return super.isSingleton(bean, beanName); 995 } 996 } 997 998 public static class CamelDependenciesFinder implements ComponentDefinitionRegistryProcessor { 999 1000 private final String camelContextName; 1001 private final ParserContext context; 1002 private BlueprintContainer blueprintContainer; 1003 1004 public CamelDependenciesFinder(String camelContextName, ParserContext context) { 1005 this.camelContextName = camelContextName; 1006 this.context = context; 1007 } 1008 1009 public void setBlueprintContainer(BlueprintContainer blueprintContainer) { 1010 this.blueprintContainer = blueprintContainer; 1011 } 1012 1013 public void process(ComponentDefinitionRegistry componentDefinitionRegistry) { 1014 CamelContextFactoryBean ccfb = (CamelContextFactoryBean) blueprintContainer.getComponentInstance(".camelBlueprint.factory." + camelContextName); 1015 CamelContext camelContext = ccfb.getContext(); 1016 1017 Set<String> components = new HashSet<>(); 1018 Set<String> languages = new HashSet<>(); 1019 Set<String> dataformats = new HashSet<>(); 1020 1021 // regular camel routes 1022 for (RouteDefinition rd : camelContext.getRouteDefinitions()) { 1023 findInputComponents(rd.getInputs(), components, languages, dataformats); 1024 findOutputComponents(rd.getOutputs(), components, languages, dataformats); 1025 } 1026 1027 // rest services can have embedded routes or a singular to 1028 for (RestDefinition rd : camelContext.getRestDefinitions()) { 1029 for (VerbDefinition vd : rd.getVerbs()) { 1030 Object o = vd.getToOrRoute(); 1031 if (o instanceof RouteDefinition) { 1032 RouteDefinition route = (RouteDefinition) o; 1033 findInputComponents(route.getInputs(), components, languages, dataformats); 1034 findOutputComponents(route.getOutputs(), components, languages, dataformats); 1035 } else if (o instanceof ToDefinition) { 1036 findUriComponent(((ToDefinition) o).getUri(), components); 1037 } else if (o instanceof ToDynamicDefinition) { 1038 findUriComponent(((ToDynamicDefinition) o).getUri(), components); 1039 } 1040 } 1041 } 1042 1043 if (ccfb.getRestConfiguration() != null) { 1044 // rest configuration may refer to a component to use 1045 String component = ccfb.getRestConfiguration().getComponent(); 1046 if (component != null) { 1047 components.add(component); 1048 } 1049 component = ccfb.getRestConfiguration().getApiComponent(); 1050 if (component != null) { 1051 components.add(component); 1052 } 1053 1054 // check what data formats are used in binding mode 1055 RestBindingMode mode = ccfb.getRestConfiguration().getBindingMode(); 1056 String json = ccfb.getRestConfiguration().getJsonDataFormat(); 1057 if (json == null && mode != null) { 1058 if (RestBindingMode.json.equals(mode) || RestBindingMode.json_xml.equals(mode)) { 1059 // jackson is the default json data format 1060 json = "json-jackson"; 1061 } 1062 } 1063 if (json != null) { 1064 dataformats.add(json); 1065 } 1066 String xml = ccfb.getRestConfiguration().getXmlDataFormat(); 1067 if (xml == null && mode != null) { 1068 if (RestBindingMode.xml.equals(mode) || RestBindingMode.json_xml.equals(mode)) { 1069 // jaxb is the default xml data format 1070 dataformats.add("jaxb"); 1071 } 1072 } 1073 if (xml != null) { 1074 dataformats.add(xml); 1075 } 1076 } 1077 1078 // We can only add service references to resolvers, but we can't make the factory depends on those 1079 // because the factory has already been instantiated 1080 try { 1081 for (String component : components) { 1082 if (camelContext.getComponent(component, false) == null) { 1083 // component not already in camel-context so resolve an OSGi reference to it 1084 getComponentResolverReference(context, component); 1085 } else { 1086 LOG.debug("Not creating a service reference for component {} because a component already exists in the Camel Context", component); 1087 } 1088 } 1089 for (String language : languages) { 1090 getLanguageResolverReference(context, language); 1091 } 1092 for (String dataformat : dataformats) { 1093 getDataformatResolverReference(context, dataformat); 1094 } 1095 } catch (UnsupportedOperationException e) { 1096 LOG.warn("Unable to add dependencies to Camel components OSGi services. " 1097 + "The Apache Aries blueprint implementation used is too old and the blueprint bundle cannot see the org.apache.camel.spi package."); 1098 components.clear(); 1099 languages.clear(); 1100 dataformats.clear(); 1101 } 1102 1103 } 1104 1105 private void findInputComponents(List<FromDefinition> defs, Set<String> components, Set<String> languages, Set<String> dataformats) { 1106 if (defs != null) { 1107 for (FromDefinition def : defs) { 1108 findUriComponent(def.getUri(), components); 1109 findSchedulerUriComponent(def.getUri(), components); 1110 } 1111 } 1112 } 1113 1114 @SuppressWarnings({"rawtypes"}) 1115 private void findOutputComponents(List<ProcessorDefinition<?>> defs, Set<String> components, Set<String> languages, Set<String> dataformats) { 1116 if (defs != null) { 1117 for (ProcessorDefinition<?> def : defs) { 1118 if (def instanceof SendDefinition) { 1119 findUriComponent(((SendDefinition) def).getUri(), components); 1120 } 1121 if (def instanceof MarshalDefinition) { 1122 findDataFormat(((MarshalDefinition) def).getDataFormatType(), dataformats); 1123 } 1124 if (def instanceof UnmarshalDefinition) { 1125 findDataFormat(((UnmarshalDefinition) def).getDataFormatType(), dataformats); 1126 } 1127 if (def instanceof ExpressionNode) { 1128 findLanguage(((ExpressionNode) def).getExpression(), languages); 1129 } 1130 if (def instanceof ResequenceDefinition) { 1131 findLanguage(((ResequenceDefinition) def).getExpression(), languages); 1132 } 1133 if (def instanceof AggregateDefinition) { 1134 findLanguage(((AggregateDefinition) def).getExpression(), languages); 1135 findLanguage(((AggregateDefinition) def).getCorrelationExpression(), languages); 1136 findLanguage(((AggregateDefinition) def).getCompletionPredicate(), languages); 1137 findLanguage(((AggregateDefinition) def).getCompletionTimeoutExpression(), languages); 1138 findLanguage(((AggregateDefinition) def).getCompletionSizeExpression(), languages); 1139 } 1140 if (def instanceof CatchDefinition) { 1141 findLanguage(((CatchDefinition) def).getHandled(), languages); 1142 } 1143 if (def instanceof OnExceptionDefinition) { 1144 findLanguage(((OnExceptionDefinition) def).getRetryWhile(), languages); 1145 findLanguage(((OnExceptionDefinition) def).getHandled(), languages); 1146 findLanguage(((OnExceptionDefinition) def).getContinued(), languages); 1147 } 1148 if (def instanceof SortDefinition) { 1149 findLanguage(((SortDefinition) def).getExpression(), languages); 1150 } 1151 if (def instanceof WireTapDefinition) { 1152 findLanguage(((WireTapDefinition<?>) def).getNewExchangeExpression(), languages); 1153 } 1154 findOutputComponents(def.getOutputs(), components, languages, dataformats); 1155 } 1156 } 1157 } 1158 1159 private void findLanguage(ExpressionDefinition expression, Set<String> languages) { 1160 if (expression != null) { 1161 String lang = expression.getLanguage(); 1162 if (lang != null && lang.length() > 0) { 1163 languages.add(lang); 1164 } 1165 } 1166 } 1167 1168 private void findLanguage(ExpressionSubElementDefinition expression, Set<String> languages) { 1169 if (expression != null) { 1170 findLanguage(expression.getExpressionType(), languages); 1171 } 1172 } 1173 1174 private void findDataFormat(DataFormatDefinition dfd, Set<String> dataformats) { 1175 if (dfd != null && dfd.getDataFormatName() != null) { 1176 dataformats.add(dfd.getDataFormatName()); 1177 } 1178 } 1179 1180 private void findUriComponent(String uri, Set<String> components) { 1181 // if the uri is a placeholder then skip it 1182 if (uri == null || uri.startsWith(PropertiesComponent.DEFAULT_PREFIX_TOKEN)) { 1183 return; 1184 } 1185 1186 // validate uri here up-front so a meaningful error can be logged for blueprint 1187 // it will also speed up tests in case of failure 1188 if (!validateUri(uri)) { 1189 return; 1190 } 1191 1192 String splitURI[] = ObjectHelper.splitOnCharacter(uri, ":", 2); 1193 if (splitURI[1] != null) { 1194 String scheme = splitURI[0]; 1195 components.add(scheme); 1196 } 1197 } 1198 1199 private void findSchedulerUriComponent(String uri, Set<String> components) { 1200 1201 // the input may use a scheduler which can be quartz or spring 1202 if (uri != null) { 1203 try { 1204 URI u = new URI(uri); 1205 Map<String, Object> parameters = URISupport.parseParameters(u); 1206 Object value = parameters.get("scheduler"); 1207 if (value == null) { 1208 value = parameters.get("consumer.scheduler"); 1209 } 1210 if (value != null) { 1211 // the scheduler can be quartz2 or spring based, so add reference to camel component 1212 // from these components os blueprint knows about the requirement 1213 String name = value.toString(); 1214 if ("quartz2".equals(name)) { 1215 components.add("quartz2"); 1216 } else if ("spring".equals(name)) { 1217 components.add("spring-event"); 1218 } 1219 } 1220 } catch (URISyntaxException e) { 1221 // ignore as uri should be already validated at findUriComponent method 1222 } 1223 } 1224 } 1225 1226 private static boolean validateUri(String uri) { 1227 try { 1228 // the same validation as done in DefaultCamelContext#normalizeEndpointUri(String) 1229 URISupport.normalizeUri(uri); 1230 } catch (URISyntaxException | UnsupportedEncodingException e) { 1231 LOG.error("Endpoint URI '" + uri + "' is not valid due to: " + e.getMessage(), e); 1232 return false; 1233 } 1234 return true; 1235 } 1236 } 1237 1238}