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