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.model.cloud; 018 019import java.util.Optional; 020import java.util.function.Function; 021import java.util.function.Supplier; 022import javax.xml.bind.annotation.XmlAccessType; 023import javax.xml.bind.annotation.XmlAccessorType; 024import javax.xml.bind.annotation.XmlAttribute; 025import javax.xml.bind.annotation.XmlElement; 026import javax.xml.bind.annotation.XmlElements; 027import javax.xml.bind.annotation.XmlRootElement; 028import javax.xml.bind.annotation.XmlTransient; 029 030import org.apache.camel.CamelContext; 031import org.apache.camel.CamelContextAware; 032import org.apache.camel.ExchangePattern; 033import org.apache.camel.Expression; 034import org.apache.camel.Processor; 035import org.apache.camel.builder.ExpressionClause; 036import org.apache.camel.cloud.ServiceChooser; 037import org.apache.camel.cloud.ServiceChooserAware; 038import org.apache.camel.cloud.ServiceDiscovery; 039import org.apache.camel.cloud.ServiceDiscoveryAware; 040import org.apache.camel.cloud.ServiceExpressionFactory; 041import org.apache.camel.cloud.ServiceFilter; 042import org.apache.camel.cloud.ServiceFilterAware; 043import org.apache.camel.cloud.ServiceLoadBalancer; 044import org.apache.camel.impl.cloud.DefaultServiceCallExpression; 045import org.apache.camel.impl.cloud.DefaultServiceCallProcessor; 046import org.apache.camel.impl.cloud.DefaultServiceLoadBalancer; 047import org.apache.camel.impl.cloud.HealthyServiceFilter; 048import org.apache.camel.impl.cloud.PassThroughServiceFilter; 049import org.apache.camel.impl.cloud.RandomServiceChooser; 050import org.apache.camel.impl.cloud.RoundRobinServiceChooser; 051import org.apache.camel.model.NoOutputDefinition; 052import org.apache.camel.spi.Metadata; 053import org.apache.camel.spi.RouteContext; 054import org.apache.camel.util.CamelContextHelper; 055import org.apache.camel.util.ObjectHelper; 056import org.apache.camel.util.function.Suppliers; 057 058import static org.apache.camel.util.CamelContextHelper.findByType; 059import static org.apache.camel.util.CamelContextHelper.lookup; 060 061/** 062 * To call remote services 063 */ 064@Metadata(label = "eip,routing") 065@XmlRootElement(name = "serviceCall") 066@XmlAccessorType(XmlAccessType.FIELD) 067public class ServiceCallDefinition extends NoOutputDefinition<ServiceCallDefinition> { 068 @XmlAttribute @Metadata(required = "true") 069 private String name; 070 @XmlAttribute 071 private String uri; 072 @XmlAttribute @Metadata(defaultValue = ServiceCallDefinitionConstants.DEFAULT_COMPONENT) 073 private String component; 074 @XmlAttribute 075 private ExchangePattern pattern; 076 @XmlAttribute 077 private String configurationRef; 078 @XmlAttribute 079 private String serviceDiscoveryRef; 080 @XmlTransient 081 private ServiceDiscovery serviceDiscovery; 082 @XmlAttribute 083 private String serviceFilterRef; 084 @XmlTransient 085 private ServiceFilter serviceFilter; 086 @XmlAttribute 087 private String serviceChooserRef; 088 @XmlTransient 089 private ServiceChooser serviceChooser; 090 @XmlAttribute 091 private String loadBalancerRef; 092 @XmlTransient 093 private ServiceLoadBalancer loadBalancer; 094 @XmlAttribute 095 private String expressionRef; 096 @XmlTransient 097 private Expression expression; 098 099 @XmlElements({ 100 @XmlElement(name = "cachingServiceDiscovery", type = CachingServiceCallServiceDiscoveryConfiguration.class), 101 @XmlElement(name = "aggregatingServiceDiscovery", type = AggregatingServiceCallServiceDiscoveryConfiguration.class), 102 @XmlElement(name = "consulServiceDiscovery", type = ConsulServiceCallServiceDiscoveryConfiguration.class), 103 @XmlElement(name = "dnsServiceDiscovery", type = DnsServiceCallServiceDiscoveryConfiguration.class), 104 @XmlElement(name = "etcdServiceDiscovery", type = EtcdServiceCallServiceDiscoveryConfiguration.class), 105 @XmlElement(name = "kubernetesServiceDiscovery", type = KubernetesServiceCallServiceDiscoveryConfiguration.class), 106 @XmlElement(name = "staticServiceDiscovery", type = StaticServiceCallServiceDiscoveryConfiguration.class)} 107 ) 108 private ServiceCallServiceDiscoveryConfiguration serviceDiscoveryConfiguration; 109 110 @XmlElements({ 111 @XmlElement(name = "blacklistServiceFilter", type = BlacklistServiceCallServiceFilterConfiguration.class), 112 @XmlElement(name = "chainedServiceFilter", type = ChainedServiceCallServiceFilterConfiguration.class), 113 @XmlElement(name = "customServiceFilter", type = CustomServiceCallServiceFilterConfiguration.class), 114 @XmlElement(name = "healthyServiceFilter", type = HealthyServiceCallServiceFilterConfiguration.class), 115 @XmlElement(name = "passThroughServiceFilter", type = PassThroughServiceCallServiceFilterConfiguration.class)} 116 ) 117 private ServiceCallServiceFilterConfiguration serviceFilterConfiguration; 118 119 @XmlElements({ 120 @XmlElement(name = "ribbonLoadBalancer", type = RibbonServiceCallServiceLoadBalancerConfiguration.class), 121 @XmlElement(name = "defaultLoadBalancer", type = DefaultServiceCallServiceLoadBalancerConfiguration.class) } 122 ) 123 private ServiceCallServiceLoadBalancerConfiguration loadBalancerConfiguration; 124 125 @XmlElements({ 126 @XmlElement(name = "expressionConfiguration", type = ServiceCallExpressionConfiguration.class)} 127 ) 128 private ServiceCallExpressionConfiguration expressionConfiguration; 129 130 public ServiceCallDefinition() { 131 } 132 133 @Override 134 public String toString() { 135 return "ServiceCall[" + name + "]"; 136 } 137 138 @Override 139 public String getLabel() { 140 return "serviceCall"; 141 } 142 143 // ***************************** 144 // Properties 145 // ***************************** 146 147 public String getName() { 148 return name; 149 } 150 151 /** 152 * Sets the name of the service to use 153 */ 154 public void setName(String name) { 155 this.name = name; 156 } 157 158 public ExchangePattern getPattern() { 159 return pattern; 160 } 161 162 /** 163 * Sets the optional {@link ExchangePattern} used to invoke this endpoint 164 */ 165 public void setPattern(ExchangePattern pattern) { 166 this.pattern = pattern; 167 } 168 169 public String getConfigurationRef() { 170 return configurationRef; 171 } 172 173 /** 174 * Refers to a ServiceCall configuration to use 175 */ 176 public void setConfigurationRef(String configurationRef) { 177 this.configurationRef = configurationRef; 178 } 179 180 public String getUri() { 181 return uri; 182 } 183 184 /** 185 * The uri of the endpoint to send to. 186 * The uri can be dynamic computed using the {@link org.apache.camel.language.simple.SimpleLanguage} expression. 187 */ 188 public void setUri(String uri) { 189 this.uri = uri; 190 } 191 192 public String getComponent() { 193 return component; 194 } 195 196 /** 197 * The component to use. 198 */ 199 public void setComponent(String component) { 200 this.component = component; 201 } 202 203 public String getServiceDiscoveryRef() { 204 return serviceDiscoveryRef; 205 } 206 207 /** 208 * Sets a reference to a custom {@link ServiceDiscovery} to use. 209 */ 210 public void setServiceDiscoveryRef(String serviceDiscoveryRef) { 211 this.serviceDiscoveryRef = serviceDiscoveryRef; 212 } 213 214 public ServiceDiscovery getServiceDiscovery() { 215 return serviceDiscovery; 216 } 217 218 /** 219 * Sets a custom {@link ServiceDiscovery} to use. 220 */ 221 public void setServiceDiscovery(ServiceDiscovery serviceDiscovery) { 222 this.serviceDiscovery = serviceDiscovery; 223 } 224 225 public String getServiceFilterRef() { 226 return serviceFilterRef; 227 } 228 229 /** 230 * Sets a reference to a custom {@link ServiceFilter} to use. 231 */ 232 public void setServiceFilterRef(String serviceFilterRef) { 233 this.serviceFilterRef = serviceFilterRef; 234 } 235 236 public ServiceFilter getServiceFilter() { 237 return serviceFilter; 238 } 239 240 /** 241 * Sets a custom {@link ServiceFilter} to use. 242 */ 243 public void setServiceFilter(ServiceFilter serviceFilter) { 244 this.serviceFilter = serviceFilter; 245 } 246 247 public String getServiceChooserRef() { 248 return serviceChooserRef; 249 } 250 251 /** 252 * Sets a reference to a custom {@link ServiceChooser} to use. 253 */ 254 public void setServiceChooserRef(String serviceChooserRef) { 255 this.serviceChooserRef = serviceChooserRef; 256 } 257 258 public ServiceChooser getServiceChooser() { 259 return serviceChooser; 260 } 261 262 /** 263 * Sets a custom {@link ServiceChooser} to use. 264 */ 265 public void setServiceChooser(ServiceChooser serviceChooser) { 266 this.serviceChooser = serviceChooser; 267 } 268 269 public String getLoadBalancerRef() { 270 return loadBalancerRef; 271 } 272 273 /** 274 * Sets a reference to a custom {@link ServiceLoadBalancer} to use. 275 */ 276 public void setLoadBalancerRef(String loadBalancerRef) { 277 this.loadBalancerRef = loadBalancerRef; 278 } 279 280 public ServiceLoadBalancer getLoadBalancer() { 281 return loadBalancer; 282 } 283 284 /** 285 * Sets a custom {@link ServiceLoadBalancer} to use. 286 */ 287 public void setLoadBalancer(ServiceLoadBalancer loadBalancer) { 288 this.loadBalancer = loadBalancer; 289 } 290 291 public String getExpressionRef() { 292 return expressionRef; 293 } 294 295 /** 296 * Set a reference to a custom {@link Expression} to use. 297 */ 298 public void setExpressionRef(String expressionRef) { 299 this.expressionRef = expressionRef; 300 } 301 302 public Expression getExpression() { 303 return expression; 304 } 305 306 /** 307 * Set a custom {@link Expression} to use. 308 */ 309 public void setExpression(Expression expression) { 310 this.expression = expression; 311 } 312 313 public ServiceCallServiceDiscoveryConfiguration getServiceDiscoveryConfiguration() { 314 return serviceDiscoveryConfiguration; 315 } 316 317 /** 318 * Configures the ServiceDiscovery using the given configuration. 319 */ 320 public void setServiceDiscoveryConfiguration(ServiceCallServiceDiscoveryConfiguration serviceDiscoveryConfiguration) { 321 this.serviceDiscoveryConfiguration = serviceDiscoveryConfiguration; 322 } 323 324 public ServiceCallServiceFilterConfiguration getServiceFilterConfiguration() { 325 return serviceFilterConfiguration; 326 } 327 328 /** 329 * Configures the ServiceFilter using the given configuration. 330 */ 331 public void setServiceFilterConfiguration(ServiceCallServiceFilterConfiguration serviceFilterConfiguration) { 332 this.serviceFilterConfiguration = serviceFilterConfiguration; 333 } 334 335 public ServiceCallServiceLoadBalancerConfiguration getLoadBalancerConfiguration() { 336 return loadBalancerConfiguration; 337 } 338 339 /** 340 * Configures the LoadBalancer using the given configuration. 341 */ 342 public void setLoadBalancerConfiguration(ServiceCallServiceLoadBalancerConfiguration loadBalancerConfiguration) { 343 this.loadBalancerConfiguration = loadBalancerConfiguration; 344 } 345 346 public ServiceCallExpressionConfiguration getExpressionConfiguration() { 347 return expressionConfiguration; 348 } 349 350 /** 351 * Configures the Expression using the given configuration. 352 */ 353 public void setExpressionConfiguration(ServiceCallExpressionConfiguration expressionConfiguration) { 354 this.expressionConfiguration = expressionConfiguration; 355 } 356 357 // ***************************** 358 // Fluent API 359 // ***************************** 360 361 /** 362 * Sets the optional {@link ExchangePattern} used to invoke this endpoint 363 */ 364 public ServiceCallDefinition pattern(ExchangePattern pattern) { 365 setPattern(pattern); 366 return this; 367 } 368 369 /** 370 * Sets the name of the service to use 371 */ 372 public ServiceCallDefinition name(String name) { 373 setName(name); 374 return this; 375 } 376 377 /** 378 * Sets the uri of the service to use 379 */ 380 public ServiceCallDefinition uri(String uri) { 381 setUri(uri); 382 return this; 383 } 384 385 /** 386 * Sets the component to use 387 */ 388 public ServiceCallDefinition component(String component) { 389 setComponent(component); 390 return this; 391 } 392 393 /** 394 * Refers to a ServiceCall configuration to use 395 */ 396 public ServiceCallDefinition serviceCallConfiguration(String ref) { 397 configurationRef = ref; 398 return this; 399 } 400 401 /** 402 * Sets a reference to a custom {@link ServiceDiscovery} to use. 403 */ 404 public ServiceCallDefinition serviceDiscovery(String serviceDiscoveryRef) { 405 setServiceDiscoveryRef(serviceDiscoveryRef); 406 return this; 407 } 408 409 /** 410 * Sets a custom {@link ServiceDiscovery} to use. 411 */ 412 public ServiceCallDefinition serviceDiscovery(ServiceDiscovery serviceDiscovery) { 413 setServiceDiscovery(serviceDiscovery); 414 return this; 415 } 416 417 /** 418 * Sets a reference to a custom {@link ServiceFilter} to use. 419 */ 420 public ServiceCallDefinition serviceFilter(String serviceFilterRef) { 421 setServiceDiscoveryRef(serviceDiscoveryRef); 422 return this; 423 } 424 425 /** 426 * Sets a custom {@link ServiceFilter} to use. 427 */ 428 public ServiceCallDefinition serviceFilter(ServiceFilter serviceFilter) { 429 setServiceFilter(serviceFilter); 430 return this; 431 } 432 433 /** 434 * Sets a reference to a custom {@link ServiceChooser} to use. 435 */ 436 public ServiceCallDefinition serviceChooser(String serviceChooserRef) { 437 setServiceChooserRef(serviceChooserRef); 438 return this; 439 } 440 441 /** 442 * Sets a custom {@link ServiceChooser} to use. 443 */ 444 public ServiceCallDefinition serviceChooser(ServiceChooser serviceChooser) { 445 setServiceChooser(serviceChooser); 446 return this; 447 } 448 449 /** 450 * Sets a reference to a custom {@link ServiceLoadBalancer} to use. 451 */ 452 public ServiceCallDefinition loadBalancer(String loadBalancerRef) { 453 setLoadBalancerRef(loadBalancerRef); 454 return this; 455 } 456 457 /** 458 * Sets a custom {@link ServiceLoadBalancer} to use. 459 */ 460 public ServiceCallDefinition loadBalancer(ServiceLoadBalancer loadBalancer) { 461 setLoadBalancer(loadBalancer); 462 return this; 463 } 464 465 /** 466 * Sets a reference to a custom {@link Expression} to use. 467 */ 468 public ServiceCallDefinition expression(String expressionRef) { 469 setExpressionRef(loadBalancerRef); 470 return this; 471 } 472 473 /** 474 * Sets a custom {@link Expression} to use. 475 */ 476 public ServiceCallDefinition expression(Expression expression) { 477 setExpression(expression); 478 return this; 479 } 480 481 /** 482 * Sets a custom {@link Expression} to use through an expression builder clause. 483 * 484 * @return a expression builder clause to set the body 485 */ 486 public ExpressionClause<ServiceCallDefinition> expression() { 487 ExpressionClause<ServiceCallDefinition> clause = new ExpressionClause<>(this); 488 setExpression(clause); 489 490 return clause; 491 } 492 493 /** 494 * Configures the ServiceDiscovery using the given configuration. 495 */ 496 public ServiceCallDefinition serviceDiscoveryConfiguration(ServiceCallServiceDiscoveryConfiguration serviceDiscoveryConfiguration) { 497 setServiceDiscoveryConfiguration(serviceDiscoveryConfiguration); 498 return this; 499 } 500 501 /** 502 * Configures the ServiceFilter using the given configuration. 503 */ 504 public ServiceCallDefinition serviceFilterConfiguration(ServiceCallServiceFilterConfiguration serviceFilterConfiguration) { 505 setServiceFilterConfiguration(serviceFilterConfiguration); 506 return this; 507 } 508 509 /** 510 * Configures the LoadBalancer using the given configuration. 511 */ 512 public ServiceCallDefinition loadBalancerConfiguration(ServiceCallServiceLoadBalancerConfiguration loadBalancerConfiguration) { 513 setLoadBalancerConfiguration(loadBalancerConfiguration); 514 return this; 515 } 516 517 /** 518 * Configures the Expression using the given configuration. 519 */ 520 public ServiceCallDefinition expressionConfiguration(ServiceCallExpressionConfiguration expressionConfiguration) { 521 setExpressionConfiguration(expressionConfiguration); 522 return this; 523 } 524 525 // ***************************** 526 // Shortcuts - ServiceDiscovery 527 // ***************************** 528 529 public CachingServiceCallServiceDiscoveryConfiguration cachingServiceDiscovery() { 530 CachingServiceCallServiceDiscoveryConfiguration conf = new CachingServiceCallServiceDiscoveryConfiguration(this); 531 setServiceDiscoveryConfiguration(conf); 532 533 return conf; 534 } 535 536 public ConsulServiceCallServiceDiscoveryConfiguration consulServiceDiscovery() { 537 ConsulServiceCallServiceDiscoveryConfiguration conf = new ConsulServiceCallServiceDiscoveryConfiguration(this); 538 setServiceDiscoveryConfiguration(conf); 539 540 return conf; 541 } 542 543 public ServiceCallDefinition consulServiceDiscovery(String url) { 544 ConsulServiceCallServiceDiscoveryConfiguration conf = new ConsulServiceCallServiceDiscoveryConfiguration(this); 545 conf.setUrl(url); 546 547 setServiceDiscoveryConfiguration(conf); 548 549 return this; 550 } 551 552 public DnsServiceCallServiceDiscoveryConfiguration dnsServiceDiscovery() { 553 DnsServiceCallServiceDiscoveryConfiguration conf = new DnsServiceCallServiceDiscoveryConfiguration(this); 554 setServiceDiscoveryConfiguration(conf); 555 556 return conf; 557 } 558 559 public ServiceCallDefinition dnsServiceDiscovery(String domain) { 560 DnsServiceCallServiceDiscoveryConfiguration conf = new DnsServiceCallServiceDiscoveryConfiguration(this); 561 conf.setDomain(domain); 562 563 setServiceDiscoveryConfiguration(conf); 564 565 return this; 566 } 567 568 public ServiceCallDefinition dnsServiceDiscovery(String domain, String protocol) { 569 DnsServiceCallServiceDiscoveryConfiguration conf = new DnsServiceCallServiceDiscoveryConfiguration(this); 570 conf.setDomain(domain); 571 conf.setProto(protocol); 572 573 setServiceDiscoveryConfiguration(conf); 574 575 return this; 576 } 577 578 public EtcdServiceCallServiceDiscoveryConfiguration etcdServiceDiscovery() { 579 EtcdServiceCallServiceDiscoveryConfiguration conf = new EtcdServiceCallServiceDiscoveryConfiguration(this); 580 setServiceDiscoveryConfiguration(conf); 581 582 return conf; 583 } 584 585 public ServiceCallDefinition etcdServiceDiscovery(String uris) { 586 EtcdServiceCallServiceDiscoveryConfiguration conf = new EtcdServiceCallServiceDiscoveryConfiguration(this); 587 conf.setUris(uris); 588 589 setServiceDiscoveryConfiguration(conf); 590 591 return this; 592 } 593 594 public ServiceCallDefinition etcdServiceDiscovery(String uris, String servicePath) { 595 EtcdServiceCallServiceDiscoveryConfiguration conf = new EtcdServiceCallServiceDiscoveryConfiguration(this); 596 conf.setUris(uris); 597 conf.setServicePath(servicePath); 598 599 setServiceDiscoveryConfiguration(conf); 600 601 return this; 602 } 603 604 public KubernetesServiceCallServiceDiscoveryConfiguration kubernetesServiceDiscovery() { 605 KubernetesServiceCallServiceDiscoveryConfiguration conf = new KubernetesServiceCallServiceDiscoveryConfiguration(this); 606 setServiceDiscoveryConfiguration(conf); 607 608 return conf; 609 } 610 611 public KubernetesServiceCallServiceDiscoveryConfiguration kubernetesClientServiceDiscovery() { 612 KubernetesServiceCallServiceDiscoveryConfiguration conf = new KubernetesServiceCallServiceDiscoveryConfiguration(this); 613 conf.setLookup("client"); 614 615 setServiceDiscoveryConfiguration(conf); 616 617 return conf; 618 } 619 620 public ServiceCallDefinition kubernetesEnvServiceDiscovery() { 621 KubernetesServiceCallServiceDiscoveryConfiguration conf = new KubernetesServiceCallServiceDiscoveryConfiguration(this); 622 conf.setLookup("environment"); 623 624 setServiceDiscoveryConfiguration(conf); 625 626 return this; 627 } 628 629 public ServiceCallDefinition kubernetesDnsServiceDiscovery(String namespace, String domain) { 630 KubernetesServiceCallServiceDiscoveryConfiguration conf = new KubernetesServiceCallServiceDiscoveryConfiguration(this); 631 conf.setLookup("dns"); 632 conf.setNamespace(namespace); 633 conf.setDnsDomain(domain); 634 635 setServiceDiscoveryConfiguration(conf); 636 637 return this; 638 } 639 640 public AggregatingServiceCallServiceDiscoveryConfiguration multiServiceDiscovery() { 641 AggregatingServiceCallServiceDiscoveryConfiguration conf = new AggregatingServiceCallServiceDiscoveryConfiguration(this); 642 setServiceDiscoveryConfiguration(conf); 643 644 return conf; 645 } 646 647 public StaticServiceCallServiceDiscoveryConfiguration staticServiceDiscovery() { 648 StaticServiceCallServiceDiscoveryConfiguration conf = new StaticServiceCallServiceDiscoveryConfiguration(this); 649 setServiceDiscoveryConfiguration(conf); 650 651 return conf; 652 } 653 654 // ***************************** 655 // Shortcuts - ServiceFilter 656 // ***************************** 657 658 public ServiceCallDefinition healthyFilter() { 659 HealthyServiceCallServiceFilterConfiguration conf = new HealthyServiceCallServiceFilterConfiguration(this); 660 setServiceFilterConfiguration(conf); 661 662 return this; 663 } 664 665 public ServiceCallDefinition passThroughFilter() { 666 PassThroughServiceCallServiceFilterConfiguration conf = new PassThroughServiceCallServiceFilterConfiguration(this); 667 setServiceFilterConfiguration(conf); 668 669 return this; 670 } 671 672 public ChainedServiceCallServiceFilterConfiguration multiFilter() { 673 ChainedServiceCallServiceFilterConfiguration conf = new ChainedServiceCallServiceFilterConfiguration(this); 674 setServiceFilterConfiguration(conf); 675 676 return conf; 677 } 678 679 public BlacklistServiceCallServiceFilterConfiguration blacklistFilter() { 680 BlacklistServiceCallServiceFilterConfiguration conf = new BlacklistServiceCallServiceFilterConfiguration(); 681 setServiceFilterConfiguration(conf); 682 683 return conf; 684 } 685 686 public ServiceCallDefinition customFilter(String serviceFilter) { 687 CustomServiceCallServiceFilterConfiguration conf = new CustomServiceCallServiceFilterConfiguration(); 688 conf.setServiceFilterRef(serviceFilter); 689 690 setServiceFilterConfiguration(conf); 691 692 return this; 693 } 694 695 public ServiceCallDefinition customFilter(ServiceFilter serviceFilter) { 696 CustomServiceCallServiceFilterConfiguration conf = new CustomServiceCallServiceFilterConfiguration(); 697 conf.setServiceFilter(serviceFilter); 698 699 setServiceFilterConfiguration(conf); 700 701 return this; 702 } 703 704 // ***************************** 705 // Shortcuts - LoadBalancer 706 // ***************************** 707 708 public ServiceCallDefinition defaultLoadBalancer() { 709 DefaultServiceCallServiceLoadBalancerConfiguration conf = new DefaultServiceCallServiceLoadBalancerConfiguration(); 710 setLoadBalancerConfiguration(conf); 711 712 return this; 713 } 714 715 public ServiceCallDefinition ribbonLoadBalancer() { 716 RibbonServiceCallServiceLoadBalancerConfiguration conf = new RibbonServiceCallServiceLoadBalancerConfiguration(this); 717 setLoadBalancerConfiguration(conf); 718 719 return this; 720 } 721 722 public ServiceCallDefinition ribbonLoadBalancer(String clientName) { 723 RibbonServiceCallServiceLoadBalancerConfiguration conf = new RibbonServiceCallServiceLoadBalancerConfiguration(this); 724 conf.setClientName(clientName); 725 726 setLoadBalancerConfiguration(conf); 727 728 return this; 729 } 730 731 // ***************************** 732 // Processor Factory 733 // ***************************** 734 735 @Override 736 public Processor createProcessor(RouteContext routeContext) throws Exception { 737 final CamelContext camelContext = routeContext.getCamelContext(); 738 final ServiceDiscovery serviceDiscovery = retrieveServiceDiscovery(camelContext); 739 final ServiceFilter serviceFilter = retrieveServiceFilter(camelContext); 740 final ServiceChooser serviceChooser = retrieveServiceChooser(camelContext); 741 final ServiceLoadBalancer loadBalancer = retrieveLoadBalancer(camelContext); 742 743 if (loadBalancer instanceof CamelContextAware) { 744 ((CamelContextAware) loadBalancer).setCamelContext(camelContext); 745 } 746 if (loadBalancer instanceof ServiceDiscoveryAware) { 747 ((ServiceDiscoveryAware) loadBalancer).setServiceDiscovery(serviceDiscovery); 748 } 749 if (loadBalancer instanceof ServiceFilterAware) { 750 ((ServiceFilterAware) loadBalancer).setServiceFilter(serviceFilter); 751 } 752 if (loadBalancer instanceof ServiceChooserAware) { 753 ((ServiceChooserAware) loadBalancer).setServiceChooser(serviceChooser); 754 } 755 756 // The component is used to configure the default scheme to use (eg camel component name). 757 // The component configured on EIP takes precedence vs configured on configuration. 758 String endpointScheme = this.component; 759 if (endpointScheme == null) { 760 ServiceCallConfigurationDefinition conf = retrieveConfig(camelContext); 761 if (conf != null) { 762 endpointScheme = conf.getComponent(); 763 } 764 } 765 if (endpointScheme == null) { 766 ServiceCallConfigurationDefinition conf = retrieveDefaultConfig(camelContext); 767 if (conf != null) { 768 endpointScheme = conf.getComponent(); 769 } 770 } 771 772 // The uri is used to tweak the uri. 773 // The uri configured on EIP takes precedence vs configured on configuration. 774 String endpointUri = this.uri; 775 if (endpointUri == null) { 776 ServiceCallConfigurationDefinition conf = retrieveConfig(camelContext); 777 if (conf != null) { 778 endpointUri = conf.getUri(); 779 } 780 } 781 if (endpointUri == null) { 782 ServiceCallConfigurationDefinition conf = retrieveDefaultConfig(camelContext); 783 if (conf != null) { 784 endpointUri = conf.getUri(); 785 } 786 } 787 788 // Service name is mandatory 789 ObjectHelper.notNull(name, "Service name"); 790 791 endpointScheme = ObjectHelper.applyIfNotEmpty(endpointScheme, camelContext::resolvePropertyPlaceholders, () -> ServiceCallDefinitionConstants.DEFAULT_COMPONENT); 792 endpointUri = ObjectHelper.applyIfNotEmpty(endpointUri, camelContext::resolvePropertyPlaceholders, () -> null); 793 794 return new DefaultServiceCallProcessor( 795 camelContext, 796 camelContext.resolvePropertyPlaceholders(name), 797 endpointScheme, 798 endpointUri, 799 pattern, 800 loadBalancer, 801 retrieveExpression(camelContext, endpointScheme)); 802 } 803 804 // ***************************** 805 // Helpers 806 // ***************************** 807 808 private ServiceCallConfigurationDefinition retrieveDefaultConfig(CamelContext camelContext) { 809 // check if a default configuration is bound to the registry 810 ServiceCallConfigurationDefinition config = camelContext.getServiceCallConfiguration(null); 811 812 if (config == null) { 813 // Or if it is in the registry 814 config = lookup( 815 camelContext, 816 ServiceCallDefinitionConstants.DEFAULT_SERVICE_CALL_CONFIG_ID, 817 ServiceCallConfigurationDefinition.class); 818 } 819 820 if (config == null) { 821 // If no default is set either by searching by name or bound to the 822 // camel context, assume that if there is a single instance in the 823 // registry, that is the default one 824 config = findByType(camelContext, ServiceCallConfigurationDefinition.class); 825 } 826 827 return config; 828 } 829 830 private ServiceCallConfigurationDefinition retrieveConfig(CamelContext camelContext) { 831 ServiceCallConfigurationDefinition config = null; 832 if (configurationRef != null) { 833 // lookup in registry firstNotNull 834 config = lookup(camelContext, configurationRef, ServiceCallConfigurationDefinition.class); 835 if (config == null) { 836 // and fallback as service configuration 837 config = camelContext.getServiceCallConfiguration(configurationRef); 838 } 839 } 840 841 return config; 842 } 843 844 // ****************************************** 845 // ServiceDiscovery 846 // ****************************************** 847 848 private ServiceDiscovery retrieveServiceDiscovery(CamelContext camelContext, Function<CamelContext, ServiceCallConfigurationDefinition> function) throws Exception { 849 ServiceDiscovery answer = null; 850 851 ServiceCallConfigurationDefinition config = function.apply(camelContext); 852 if (config != null) { 853 if (config.getServiceDiscoveryConfiguration() != null) { 854 answer = config.getServiceDiscoveryConfiguration().newInstance(camelContext); 855 } else { 856 answer = retrieve( 857 ServiceDiscovery.class, 858 camelContext, 859 config::getServiceDiscovery, 860 config::getServiceDiscoveryRef 861 ); 862 } 863 } 864 865 return answer; 866 } 867 868 private ServiceDiscovery retrieveServiceDiscovery(CamelContext camelContext) throws Exception { 869 return Suppliers.firstNotNull( 870 () -> (serviceDiscoveryConfiguration != null) ? serviceDiscoveryConfiguration.newInstance(camelContext) : null, 871 // Local configuration 872 () -> retrieve(ServiceDiscovery.class, camelContext, this::getServiceDiscovery, this::getServiceDiscoveryRef), 873 // Linked configuration 874 () -> retrieveServiceDiscovery(camelContext, this::retrieveConfig), 875 // Default configuration 876 () -> retrieveServiceDiscovery(camelContext, this::retrieveDefaultConfig), 877 // Check if there is a single instance in the registry 878 () -> findByType(camelContext, ServiceDiscovery.class), 879 // From registry 880 () -> lookup(camelContext, ServiceCallDefinitionConstants.DEFAULT_SERVICE_DISCOVERY_ID, ServiceDiscovery.class) 881 ).orElseGet( 882 // Default, that's s little ugly but a load balancer may live without 883 // (i.e. the Ribbon one) so let's delegate the null check to the actual 884 // impl. 885 () -> null 886 ); 887 } 888 889 // ****************************************** 890 // ServiceFilter 891 // ****************************************** 892 893 private ServiceFilter retrieveServiceFilter(CamelContext camelContext, Function<CamelContext, ServiceCallConfigurationDefinition> function) throws Exception { 894 ServiceFilter answer = null; 895 896 ServiceCallConfigurationDefinition config = function.apply(camelContext); 897 if (config != null) { 898 if (config.getServiceFilterConfiguration() != null) { 899 answer = config.getServiceFilterConfiguration().newInstance(camelContext); 900 } else { 901 answer = retrieve( 902 ServiceFilter.class, 903 camelContext, 904 config::getServiceFilter, 905 config::getServiceFilterRef 906 ); 907 } 908 909 if (answer == null) { 910 String ref = config.getServiceFilterRef(); 911 if (ObjectHelper.equal("healthy", ref, true)) { 912 answer = new HealthyServiceFilter(); 913 } else if (ObjectHelper.equal("pass-through", ref, true)) { 914 answer = new PassThroughServiceFilter(); 915 } else if (ObjectHelper.equal("passthrough", ref, true)) { 916 answer = new PassThroughServiceFilter(); 917 } 918 } 919 } 920 921 return answer; 922 } 923 924 private ServiceFilter retrieveServiceFilter(CamelContext camelContext) throws Exception { 925 return Suppliers.firstNotNull( 926 () -> (serviceFilterConfiguration != null) ? serviceFilterConfiguration.newInstance(camelContext) : null, 927 // Local configuration 928 () -> retrieve(ServiceFilter.class, camelContext, this::getServiceFilter, this::getServiceFilterRef), 929 // Linked configuration 930 () -> retrieveServiceFilter(camelContext, this::retrieveConfig), 931 // Default configuration 932 () -> retrieveServiceFilter(camelContext, this::retrieveDefaultConfig), 933 // Check if there is a single instance in the registry 934 () -> findByType(camelContext, ServiceFilter.class), 935 // From registry 936 () -> lookup(camelContext, ServiceCallDefinitionConstants.DEFAULT_SERVICE_FILTER_ID, ServiceFilter.class) 937 ).orElseGet( 938 // Default 939 () -> new HealthyServiceFilter() 940 ); 941 } 942 943 // ****************************************** 944 // ServiceChooser 945 // ****************************************** 946 947 private ServiceChooser retrieveServiceChooser(CamelContext camelContext, Function<CamelContext, ServiceCallConfigurationDefinition> function) throws Exception { 948 ServiceChooser answer = null; 949 950 ServiceCallConfigurationDefinition config = function.apply(camelContext); 951 if (config != null) { 952 answer = retrieve( 953 ServiceChooser.class, 954 camelContext, 955 config::getServiceChooser, 956 config::getServiceChooserRef 957 ); 958 959 if (answer == null) { 960 String ref = config.getServiceChooserRef(); 961 if (ObjectHelper.equal("roundrobin", ref, true)) { 962 answer = new RoundRobinServiceChooser(); 963 } else if (ObjectHelper.equal("round-robin", ref, true)) { 964 answer = new RoundRobinServiceChooser(); 965 } else if (ObjectHelper.equal("random", ref, true)) { 966 answer = new RandomServiceChooser(); 967 } 968 } 969 } 970 971 return answer; 972 } 973 974 private ServiceChooser retrieveServiceChooser(CamelContext camelContext) throws Exception { 975 return Suppliers.firstNotNull( 976 // Local configuration 977 () -> retrieve(ServiceChooser.class, camelContext, this::getServiceChooser, this::getServiceChooserRef), 978 // Linked configuration 979 () -> retrieveServiceChooser(camelContext, this::retrieveConfig), 980 // Default configuration 981 () -> retrieveServiceChooser(camelContext, this::retrieveDefaultConfig), 982 // Check if there is a single instance in the registry 983 () -> findByType(camelContext, ServiceChooser.class), 984 // From registry 985 () -> lookup(camelContext, ServiceCallDefinitionConstants.DEFAULT_SERVICE_CHOOSER_ID, ServiceChooser.class) 986 ).orElseGet( 987 // Default 988 () -> new RoundRobinServiceChooser() 989 ); 990 } 991 992 // ****************************************** 993 // LoadBalancer 994 // ****************************************** 995 996 private ServiceLoadBalancer retrieveLoadBalancer(CamelContext camelContext, Function<CamelContext, ServiceCallConfigurationDefinition> function) throws Exception { 997 ServiceLoadBalancer answer = null; 998 999 ServiceCallConfigurationDefinition config = function.apply(camelContext); 1000 if (config != null) { 1001 if (config.getLoadBalancerConfiguration() != null) { 1002 answer = config.getLoadBalancerConfiguration().newInstance(camelContext); 1003 } else { 1004 answer = retrieve( 1005 ServiceLoadBalancer.class, 1006 camelContext, 1007 config::getLoadBalancer, 1008 config::getLoadBalancerRef 1009 ); 1010 } 1011 } 1012 1013 return answer; 1014 } 1015 1016 private ServiceLoadBalancer retrieveLoadBalancer(CamelContext camelContext) throws Exception { 1017 return Suppliers.firstNotNull( 1018 () -> (loadBalancerConfiguration != null) ? loadBalancerConfiguration.newInstance(camelContext) : null, 1019 // Local configuration 1020 () -> retrieve(ServiceLoadBalancer.class, camelContext, this::getLoadBalancer, this::getLoadBalancerRef), 1021 // Linked configuration 1022 () -> retrieveLoadBalancer(camelContext, this::retrieveConfig), 1023 // Default configuration 1024 () -> retrieveLoadBalancer(camelContext, this::retrieveDefaultConfig), 1025 // Check if there is a single instance in the registry 1026 () -> findByType(camelContext, ServiceLoadBalancer.class), 1027 // From registry 1028 () -> lookup(camelContext, ServiceCallDefinitionConstants.DEFAULT_LOAD_BALANCER_ID, ServiceLoadBalancer.class) 1029 ).orElseGet( 1030 // Default 1031 () -> new DefaultServiceLoadBalancer() 1032 ); 1033 } 1034 1035 // ****************************************** 1036 // Expression 1037 // ****************************************** 1038 1039 private Expression retrieveExpression(CamelContext camelContext, Function<CamelContext, ServiceCallConfigurationDefinition> function) throws Exception { 1040 Expression answer = null; 1041 1042 ServiceCallConfigurationDefinition config = function.apply(camelContext); 1043 if (config != null) { 1044 if (config.getExpressionConfiguration() != null) { 1045 answer = config.getExpressionConfiguration().newInstance(camelContext); 1046 } else { 1047 answer = retrieve( 1048 Expression.class, 1049 camelContext, 1050 config::getExpression, 1051 config::getExpressionRef 1052 ); 1053 } 1054 } 1055 1056 return answer; 1057 } 1058 1059 private Expression retrieveExpression(CamelContext camelContext, String component) throws Exception { 1060 Optional<Expression> expression = Suppliers.firstNotNull( 1061 () -> (expressionConfiguration != null) ? expressionConfiguration.newInstance(camelContext) : null, 1062 // Local configuration 1063 () -> retrieve(Expression.class, camelContext, this::getExpression, this::getExpressionRef), 1064 // Linked configuration 1065 () -> retrieveExpression(camelContext, this::retrieveConfig), 1066 // Default configuration 1067 () -> retrieveExpression(camelContext, this::retrieveDefaultConfig), 1068 // From registry 1069 () -> lookup(camelContext, ServiceCallDefinitionConstants.DEFAULT_SERVICE_CALL_EXPRESSION_ID, Expression.class) 1070 ); 1071 1072 if (expression.isPresent()) { 1073 return expression.get(); 1074 } else { 1075 String lookupName = component + "-service-expression"; 1076 // First try to find the factory from the registry. 1077 ServiceExpressionFactory factory = CamelContextHelper.lookup(camelContext, lookupName, ServiceExpressionFactory.class); 1078 if (factory != null) { 1079 // If a factory is found in the registry do not re-configure it as 1080 // it should be pre-configured. 1081 return factory.newInstance(camelContext); 1082 } else { 1083 1084 Class<?> type = null; 1085 1086 try { 1087 // Then use Service factory. 1088 type = camelContext.getFactoryFinder(ServiceCallDefinitionConstants.RESOURCE_PATH).findClass(lookupName); 1089 } catch (Exception e) { 1090 } 1091 1092 if (ObjectHelper.isNotEmpty(type)) { 1093 if (ServiceExpressionFactory.class.isAssignableFrom(type)) { 1094 factory = (ServiceExpressionFactory) camelContext.getInjector().newInstance(type); 1095 } else { 1096 throw new IllegalArgumentException( 1097 "Resolving Expression: " + lookupName + " detected type conflict: Not a ServiceExpressionFactory implementation. Found: " + type.getName()); 1098 } 1099 } else { 1100 // If no factory is found, returns the default 1101 factory = context -> new DefaultServiceCallExpression(); 1102 } 1103 1104 return factory.newInstance(camelContext); 1105 } 1106 } 1107 } 1108 1109 // ************************************ 1110 // Helpers 1111 // ************************************ 1112 1113 private <T> T retrieve(Class<T> type, CamelContext camelContext, Supplier<T> instanceSupplier, Supplier<String> refSupplier) { 1114 T answer = null; 1115 if (instanceSupplier != null) { 1116 answer = instanceSupplier.get(); 1117 } 1118 1119 if (answer == null && refSupplier != null) { 1120 String ref = refSupplier.get(); 1121 if (ref != null) { 1122 answer = lookup(camelContext, ref, type); 1123 } 1124 } 1125 1126 return answer; 1127 } 1128}