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.ExchangePattern; 032import org.apache.camel.Expression; 033import org.apache.camel.Processor; 034import org.apache.camel.builder.ExpressionClause; 035import org.apache.camel.cloud.ServiceChooser; 036import org.apache.camel.cloud.ServiceChooserAware; 037import org.apache.camel.cloud.ServiceDiscovery; 038import org.apache.camel.cloud.ServiceDiscoveryAware; 039import org.apache.camel.cloud.ServiceExpressionFactory; 040import org.apache.camel.cloud.ServiceFilter; 041import org.apache.camel.cloud.ServiceFilterAware; 042import org.apache.camel.cloud.ServiceLoadBalancer; 043import org.apache.camel.impl.cloud.DefaultServiceCallExpression; 044import org.apache.camel.impl.cloud.DefaultServiceCallProcessor; 045import org.apache.camel.impl.cloud.DefaultServiceLoadBalancer; 046import org.apache.camel.impl.cloud.HealthyServiceFilter; 047import org.apache.camel.impl.cloud.PassThroughServiceFilter; 048import org.apache.camel.impl.cloud.RandomServiceChooser; 049import org.apache.camel.impl.cloud.RoundRobinServiceChooser; 050import org.apache.camel.model.NoOutputDefinition; 051import org.apache.camel.spi.Metadata; 052import org.apache.camel.spi.RouteContext; 053import org.apache.camel.util.CamelContextHelper; 054import org.apache.camel.util.ObjectHelper; 055import org.apache.camel.util.function.Suppliers; 056 057import static org.apache.camel.util.CamelContextHelper.findByType; 058import static org.apache.camel.util.CamelContextHelper.lookup; 059 060/** 061 * To call remote services 062 */ 063@Metadata(label = "eip,routing") 064@XmlRootElement(name = "serviceCall") 065@XmlAccessorType(XmlAccessType.FIELD) 066public class ServiceCallDefinition extends NoOutputDefinition<ServiceCallDefinition> { 067 @XmlAttribute @Metadata(required = "true") 068 private String name; 069 @XmlAttribute 070 private String uri; 071 @XmlAttribute @Metadata(defaultValue = ServiceCallDefinitionConstants.DEFAULT_COMPONENT) 072 private String component; 073 @XmlAttribute 074 private ExchangePattern pattern; 075 @XmlAttribute 076 private String configurationRef; 077 @XmlAttribute 078 private String serviceDiscoveryRef; 079 @XmlTransient 080 private ServiceDiscovery serviceDiscovery; 081 @XmlAttribute 082 private String serviceFilterRef; 083 @XmlTransient 084 private ServiceFilter serviceFilter; 085 @XmlAttribute 086 private String serviceChooserRef; 087 @XmlTransient 088 private ServiceChooser serviceChooser; 089 @XmlAttribute 090 private String loadBalancerRef; 091 @XmlTransient 092 private ServiceLoadBalancer loadBalancer; 093 @XmlAttribute 094 private String expressionRef; 095 @XmlTransient 096 private Expression expression; 097 098 @XmlElements({ 099 @XmlElement(name = "cachingServiceDiscovery", type = CachingServiceCallServiceDiscoveryConfiguration.class), 100 @XmlElement(name = "aggregatingServiceDiscovery", type = AggregatingServiceCallServiceDiscoveryConfiguration.class), 101 @XmlElement(name = "consulServiceDiscovery", type = ConsulServiceCallServiceDiscoveryConfiguration.class), 102 @XmlElement(name = "dnsServiceDiscovery", type = DnsServiceCallServiceDiscoveryConfiguration.class), 103 @XmlElement(name = "etcdServiceDiscovery", type = EtcdServiceCallServiceDiscoveryConfiguration.class), 104 @XmlElement(name = "kubernetesServiceDiscovery", type = KubernetesServiceCallServiceDiscoveryConfiguration.class), 105 @XmlElement(name = "staticServiceDiscovery", type = StaticServiceCallServiceDiscoveryConfiguration.class), 106 @XmlElement(name = "zookeeperServiceDiscovery", type = ZooKeeperServiceCallServiceDiscoveryConfiguration.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 public ZooKeeperServiceCallServiceDiscoveryConfiguration zookeeperServiceDiscovery() { 655 ZooKeeperServiceCallServiceDiscoveryConfiguration conf = new ZooKeeperServiceCallServiceDiscoveryConfiguration(this); 656 setServiceDiscoveryConfiguration(conf); 657 658 return conf; 659 } 660 661 public ServiceCallDefinition zookeeperServiceDiscovery(String nodes, String basePath) { 662 ZooKeeperServiceCallServiceDiscoveryConfiguration conf = new ZooKeeperServiceCallServiceDiscoveryConfiguration(this); 663 conf.setNodes(nodes); 664 conf.setBasePath(basePath); 665 666 setServiceDiscoveryConfiguration(conf); 667 668 return this; 669 } 670 671 // ***************************** 672 // Shortcuts - ServiceFilter 673 // ***************************** 674 675 public ServiceCallDefinition healthyFilter() { 676 HealthyServiceCallServiceFilterConfiguration conf = new HealthyServiceCallServiceFilterConfiguration(this); 677 setServiceFilterConfiguration(conf); 678 679 return this; 680 } 681 682 public ServiceCallDefinition passThroughFilter() { 683 PassThroughServiceCallServiceFilterConfiguration conf = new PassThroughServiceCallServiceFilterConfiguration(this); 684 setServiceFilterConfiguration(conf); 685 686 return this; 687 } 688 689 public ChainedServiceCallServiceFilterConfiguration multiFilter() { 690 ChainedServiceCallServiceFilterConfiguration conf = new ChainedServiceCallServiceFilterConfiguration(this); 691 setServiceFilterConfiguration(conf); 692 693 return conf; 694 } 695 696 public BlacklistServiceCallServiceFilterConfiguration blacklistFilter() { 697 BlacklistServiceCallServiceFilterConfiguration conf = new BlacklistServiceCallServiceFilterConfiguration(); 698 setServiceFilterConfiguration(conf); 699 700 return conf; 701 } 702 703 public ServiceCallDefinition customFilter(String serviceFilter) { 704 CustomServiceCallServiceFilterConfiguration conf = new CustomServiceCallServiceFilterConfiguration(); 705 conf.setServiceFilterRef(serviceFilter); 706 707 setServiceFilterConfiguration(conf); 708 709 return this; 710 } 711 712 public ServiceCallDefinition customFilter(ServiceFilter serviceFilter) { 713 CustomServiceCallServiceFilterConfiguration conf = new CustomServiceCallServiceFilterConfiguration(); 714 conf.setServiceFilter(serviceFilter); 715 716 setServiceFilterConfiguration(conf); 717 718 return this; 719 } 720 721 // ***************************** 722 // Shortcuts - LoadBalancer 723 // ***************************** 724 725 public ServiceCallDefinition defaultLoadBalancer() { 726 DefaultServiceCallServiceLoadBalancerConfiguration conf = new DefaultServiceCallServiceLoadBalancerConfiguration(); 727 setLoadBalancerConfiguration(conf); 728 729 return this; 730 } 731 732 public ServiceCallDefinition ribbonLoadBalancer() { 733 RibbonServiceCallServiceLoadBalancerConfiguration conf = new RibbonServiceCallServiceLoadBalancerConfiguration(this); 734 setLoadBalancerConfiguration(conf); 735 736 return this; 737 } 738 739 public ServiceCallDefinition ribbonLoadBalancer(String clientName) { 740 RibbonServiceCallServiceLoadBalancerConfiguration conf = new RibbonServiceCallServiceLoadBalancerConfiguration(this); 741 conf.setClientName(clientName); 742 743 setLoadBalancerConfiguration(conf); 744 745 return this; 746 } 747 748 // ***************************** 749 // Processor Factory 750 // ***************************** 751 752 @Override 753 public Processor createProcessor(RouteContext routeContext) throws Exception { 754 final CamelContext camelContext = routeContext.getCamelContext(); 755 final ServiceDiscovery serviceDiscovery = retrieveServiceDiscovery(camelContext); 756 final ServiceFilter serviceFilter = retrieveServiceFilter(camelContext); 757 final ServiceChooser serviceChooser = retrieveServiceChooser(camelContext); 758 final ServiceLoadBalancer loadBalancer = retrieveLoadBalancer(camelContext); 759 760 ObjectHelper.trySetCamelContext(serviceDiscovery, camelContext); 761 ObjectHelper.trySetCamelContext(serviceFilter, camelContext); 762 ObjectHelper.trySetCamelContext(serviceChooser, camelContext); 763 ObjectHelper.trySetCamelContext(loadBalancer, camelContext); 764 765 if (loadBalancer instanceof ServiceDiscoveryAware) { 766 ((ServiceDiscoveryAware) loadBalancer).setServiceDiscovery(serviceDiscovery); 767 } 768 if (loadBalancer instanceof ServiceFilterAware) { 769 ((ServiceFilterAware) loadBalancer).setServiceFilter(serviceFilter); 770 } 771 if (loadBalancer instanceof ServiceChooserAware) { 772 ((ServiceChooserAware) loadBalancer).setServiceChooser(serviceChooser); 773 } 774 775 // The component is used to configure the default scheme to use (eg camel component name). 776 // The component configured on EIP takes precedence vs configured on configuration. 777 String endpointScheme = this.component; 778 if (endpointScheme == null) { 779 ServiceCallConfigurationDefinition conf = retrieveConfig(camelContext); 780 if (conf != null) { 781 endpointScheme = conf.getComponent(); 782 } 783 } 784 if (endpointScheme == null) { 785 ServiceCallConfigurationDefinition conf = retrieveDefaultConfig(camelContext); 786 if (conf != null) { 787 endpointScheme = conf.getComponent(); 788 } 789 } 790 791 // The uri is used to tweak the uri. 792 // The uri configured on EIP takes precedence vs configured on configuration. 793 String endpointUri = this.uri; 794 if (endpointUri == null) { 795 ServiceCallConfigurationDefinition conf = retrieveConfig(camelContext); 796 if (conf != null) { 797 endpointUri = conf.getUri(); 798 } 799 } 800 if (endpointUri == null) { 801 ServiceCallConfigurationDefinition conf = retrieveDefaultConfig(camelContext); 802 if (conf != null) { 803 endpointUri = conf.getUri(); 804 } 805 } 806 807 // Service name is mandatory 808 ObjectHelper.notNull(name, "Service name"); 809 810 endpointScheme = ObjectHelper.applyIfNotEmpty(endpointScheme, camelContext::resolvePropertyPlaceholders, () -> ServiceCallDefinitionConstants.DEFAULT_COMPONENT); 811 endpointUri = ObjectHelper.applyIfNotEmpty(endpointUri, camelContext::resolvePropertyPlaceholders, () -> null); 812 813 return new DefaultServiceCallProcessor( 814 camelContext, 815 camelContext.resolvePropertyPlaceholders(name), 816 endpointScheme, 817 endpointUri, 818 pattern, 819 loadBalancer, 820 retrieveExpression(camelContext, endpointScheme)); 821 } 822 823 // ***************************** 824 // Helpers 825 // ***************************** 826 827 private ServiceCallConfigurationDefinition retrieveDefaultConfig(CamelContext camelContext) { 828 // check if a default configuration is bound to the registry 829 ServiceCallConfigurationDefinition config = camelContext.getServiceCallConfiguration(null); 830 831 if (config == null) { 832 // Or if it is in the registry 833 config = lookup( 834 camelContext, 835 ServiceCallDefinitionConstants.DEFAULT_SERVICE_CALL_CONFIG_ID, 836 ServiceCallConfigurationDefinition.class); 837 } 838 839 if (config == null) { 840 // If no default is set either by searching by name or bound to the 841 // camel context, assume that if there is a single instance in the 842 // registry, that is the default one 843 config = findByType(camelContext, ServiceCallConfigurationDefinition.class); 844 } 845 846 return config; 847 } 848 849 private ServiceCallConfigurationDefinition retrieveConfig(CamelContext camelContext) { 850 ServiceCallConfigurationDefinition config = null; 851 if (configurationRef != null) { 852 // lookup in registry firstNotNull 853 config = lookup(camelContext, configurationRef, ServiceCallConfigurationDefinition.class); 854 if (config == null) { 855 // and fallback as service configuration 856 config = camelContext.getServiceCallConfiguration(configurationRef); 857 } 858 } 859 860 return config; 861 } 862 863 // ****************************************** 864 // ServiceDiscovery 865 // ****************************************** 866 867 private ServiceDiscovery retrieveServiceDiscovery(CamelContext camelContext, Function<CamelContext, ServiceCallConfigurationDefinition> function) throws Exception { 868 ServiceDiscovery answer = null; 869 870 ServiceCallConfigurationDefinition config = function.apply(camelContext); 871 if (config != null) { 872 if (config.getServiceDiscoveryConfiguration() != null) { 873 answer = config.getServiceDiscoveryConfiguration().newInstance(camelContext); 874 } else { 875 answer = retrieve( 876 ServiceDiscovery.class, 877 camelContext, 878 config::getServiceDiscovery, 879 config::getServiceDiscoveryRef 880 ); 881 } 882 } 883 884 return answer; 885 } 886 887 private ServiceDiscovery retrieveServiceDiscovery(CamelContext camelContext) throws Exception { 888 return Suppliers.firstNotNull( 889 () -> (serviceDiscoveryConfiguration != null) ? serviceDiscoveryConfiguration.newInstance(camelContext) : null, 890 // Local configuration 891 () -> retrieve(ServiceDiscovery.class, camelContext, this::getServiceDiscovery, this::getServiceDiscoveryRef), 892 // Linked configuration 893 () -> retrieveServiceDiscovery(camelContext, this::retrieveConfig), 894 // Default configuration 895 () -> retrieveServiceDiscovery(camelContext, this::retrieveDefaultConfig), 896 // Check if there is a single instance in the registry 897 () -> findByType(camelContext, ServiceDiscovery.class), 898 // From registry 899 () -> lookup(camelContext, ServiceCallDefinitionConstants.DEFAULT_SERVICE_DISCOVERY_ID, ServiceDiscovery.class) 900 ).orElseGet( 901 // Default, that's s little ugly but a load balancer may live without 902 // (i.e. the Ribbon one) so let's delegate the null check to the actual 903 // impl. 904 () -> null 905 ); 906 } 907 908 // ****************************************** 909 // ServiceFilter 910 // ****************************************** 911 912 private ServiceFilter retrieveServiceFilter(CamelContext camelContext, Function<CamelContext, ServiceCallConfigurationDefinition> function) throws Exception { 913 ServiceFilter answer = null; 914 915 ServiceCallConfigurationDefinition config = function.apply(camelContext); 916 if (config != null) { 917 if (config.getServiceFilterConfiguration() != null) { 918 answer = config.getServiceFilterConfiguration().newInstance(camelContext); 919 } else { 920 answer = retrieve( 921 ServiceFilter.class, 922 camelContext, 923 config::getServiceFilter, 924 config::getServiceFilterRef 925 ); 926 } 927 928 if (answer == null) { 929 String ref = config.getServiceFilterRef(); 930 if (ObjectHelper.equal("healthy", ref, true)) { 931 answer = new HealthyServiceFilter(); 932 } else if (ObjectHelper.equal("pass-through", ref, true)) { 933 answer = new PassThroughServiceFilter(); 934 } else if (ObjectHelper.equal("passthrough", ref, true)) { 935 answer = new PassThroughServiceFilter(); 936 } 937 } 938 } 939 940 return answer; 941 } 942 943 private ServiceFilter retrieveServiceFilter(CamelContext camelContext) throws Exception { 944 return Suppliers.firstNotNull( 945 () -> (serviceFilterConfiguration != null) ? serviceFilterConfiguration.newInstance(camelContext) : null, 946 // Local configuration 947 () -> retrieve(ServiceFilter.class, camelContext, this::getServiceFilter, this::getServiceFilterRef), 948 // Linked configuration 949 () -> retrieveServiceFilter(camelContext, this::retrieveConfig), 950 // Default configuration 951 () -> retrieveServiceFilter(camelContext, this::retrieveDefaultConfig), 952 // Check if there is a single instance in the registry 953 () -> findByType(camelContext, ServiceFilter.class), 954 // From registry 955 () -> lookup(camelContext, ServiceCallDefinitionConstants.DEFAULT_SERVICE_FILTER_ID, ServiceFilter.class) 956 ).orElseGet( 957 // Default 958 () -> new HealthyServiceFilter() 959 ); 960 } 961 962 // ****************************************** 963 // ServiceChooser 964 // ****************************************** 965 966 private ServiceChooser retrieveServiceChooser(CamelContext camelContext, Function<CamelContext, ServiceCallConfigurationDefinition> function) throws Exception { 967 ServiceChooser answer = null; 968 969 ServiceCallConfigurationDefinition config = function.apply(camelContext); 970 if (config != null) { 971 answer = retrieve( 972 ServiceChooser.class, 973 camelContext, 974 config::getServiceChooser, 975 config::getServiceChooserRef 976 ); 977 978 if (answer == null) { 979 String ref = config.getServiceChooserRef(); 980 if (ObjectHelper.equal("roundrobin", ref, true)) { 981 answer = new RoundRobinServiceChooser(); 982 } else if (ObjectHelper.equal("round-robin", ref, true)) { 983 answer = new RoundRobinServiceChooser(); 984 } else if (ObjectHelper.equal("random", ref, true)) { 985 answer = new RandomServiceChooser(); 986 } 987 } 988 } 989 990 return answer; 991 } 992 993 private ServiceChooser retrieveServiceChooser(CamelContext camelContext) throws Exception { 994 return Suppliers.firstNotNull( 995 // Local configuration 996 () -> retrieve(ServiceChooser.class, camelContext, this::getServiceChooser, this::getServiceChooserRef), 997 // Linked configuration 998 () -> retrieveServiceChooser(camelContext, this::retrieveConfig), 999 // Default configuration 1000 () -> retrieveServiceChooser(camelContext, this::retrieveDefaultConfig), 1001 // Check if there is a single instance in the registry 1002 () -> findByType(camelContext, ServiceChooser.class), 1003 // From registry 1004 () -> lookup(camelContext, ServiceCallDefinitionConstants.DEFAULT_SERVICE_CHOOSER_ID, ServiceChooser.class) 1005 ).orElseGet( 1006 // Default 1007 () -> new RoundRobinServiceChooser() 1008 ); 1009 } 1010 1011 // ****************************************** 1012 // LoadBalancer 1013 // ****************************************** 1014 1015 private ServiceLoadBalancer retrieveLoadBalancer(CamelContext camelContext, Function<CamelContext, ServiceCallConfigurationDefinition> function) throws Exception { 1016 ServiceLoadBalancer answer = null; 1017 1018 ServiceCallConfigurationDefinition config = function.apply(camelContext); 1019 if (config != null) { 1020 if (config.getLoadBalancerConfiguration() != null) { 1021 answer = config.getLoadBalancerConfiguration().newInstance(camelContext); 1022 } else { 1023 answer = retrieve( 1024 ServiceLoadBalancer.class, 1025 camelContext, 1026 config::getLoadBalancer, 1027 config::getLoadBalancerRef 1028 ); 1029 } 1030 } 1031 1032 return answer; 1033 } 1034 1035 private ServiceLoadBalancer retrieveLoadBalancer(CamelContext camelContext) throws Exception { 1036 return Suppliers.firstNotNull( 1037 () -> (loadBalancerConfiguration != null) ? loadBalancerConfiguration.newInstance(camelContext) : null, 1038 // Local configuration 1039 () -> retrieve(ServiceLoadBalancer.class, camelContext, this::getLoadBalancer, this::getLoadBalancerRef), 1040 // Linked configuration 1041 () -> retrieveLoadBalancer(camelContext, this::retrieveConfig), 1042 // Default configuration 1043 () -> retrieveLoadBalancer(camelContext, this::retrieveDefaultConfig), 1044 // Check if there is a single instance in the registry 1045 () -> findByType(camelContext, ServiceLoadBalancer.class), 1046 // From registry 1047 () -> lookup(camelContext, ServiceCallDefinitionConstants.DEFAULT_LOAD_BALANCER_ID, ServiceLoadBalancer.class) 1048 ).orElseGet( 1049 // Default 1050 () -> new DefaultServiceLoadBalancer() 1051 ); 1052 } 1053 1054 // ****************************************** 1055 // Expression 1056 // ****************************************** 1057 1058 private Expression retrieveExpression(CamelContext camelContext, Function<CamelContext, ServiceCallConfigurationDefinition> function) throws Exception { 1059 Expression answer = null; 1060 1061 ServiceCallConfigurationDefinition config = function.apply(camelContext); 1062 if (config != null) { 1063 if (config.getExpressionConfiguration() != null) { 1064 answer = config.getExpressionConfiguration().newInstance(camelContext); 1065 } else { 1066 answer = retrieve( 1067 Expression.class, 1068 camelContext, 1069 config::getExpression, 1070 config::getExpressionRef 1071 ); 1072 } 1073 } 1074 1075 return answer; 1076 } 1077 1078 private Expression retrieveExpression(CamelContext camelContext, String component) throws Exception { 1079 Optional<Expression> expression = Suppliers.firstNotNull( 1080 () -> (expressionConfiguration != null) ? expressionConfiguration.newInstance(camelContext) : null, 1081 // Local configuration 1082 () -> retrieve(Expression.class, camelContext, this::getExpression, this::getExpressionRef), 1083 // Linked configuration 1084 () -> retrieveExpression(camelContext, this::retrieveConfig), 1085 // Default configuration 1086 () -> retrieveExpression(camelContext, this::retrieveDefaultConfig), 1087 // From registry 1088 () -> lookup(camelContext, ServiceCallDefinitionConstants.DEFAULT_SERVICE_CALL_EXPRESSION_ID, Expression.class) 1089 ); 1090 1091 if (expression.isPresent()) { 1092 return expression.get(); 1093 } else { 1094 String lookupName = component + "-service-expression"; 1095 // First try to find the factory from the registry. 1096 ServiceExpressionFactory factory = CamelContextHelper.lookup(camelContext, lookupName, ServiceExpressionFactory.class); 1097 if (factory != null) { 1098 // If a factory is found in the registry do not re-configure it as 1099 // it should be pre-configured. 1100 return factory.newInstance(camelContext); 1101 } else { 1102 1103 Class<?> type = null; 1104 1105 try { 1106 // Then use Service factory. 1107 type = camelContext.getFactoryFinder(ServiceCallDefinitionConstants.RESOURCE_PATH).findClass(lookupName); 1108 } catch (Exception e) { 1109 } 1110 1111 if (ObjectHelper.isNotEmpty(type)) { 1112 if (ServiceExpressionFactory.class.isAssignableFrom(type)) { 1113 factory = (ServiceExpressionFactory) camelContext.getInjector().newInstance(type); 1114 } else { 1115 throw new IllegalArgumentException( 1116 "Resolving Expression: " + lookupName + " detected type conflict: Not a ServiceExpressionFactory implementation. Found: " + type.getName()); 1117 } 1118 } else { 1119 // If no factory is found, returns the default 1120 factory = context -> new DefaultServiceCallExpression(); 1121 } 1122 1123 return factory.newInstance(camelContext); 1124 } 1125 } 1126 } 1127 1128 // ************************************ 1129 // Helpers 1130 // ************************************ 1131 1132 private <T> T retrieve(Class<T> type, CamelContext camelContext, Supplier<T> instanceSupplier, Supplier<String> refSupplier) { 1133 T answer = null; 1134 if (instanceSupplier != null) { 1135 answer = instanceSupplier.get(); 1136 } 1137 1138 if (answer == null && refSupplier != null) { 1139 String ref = refSupplier.get(); 1140 if (ref != null) { 1141 answer = lookup(camelContext, ref, type); 1142 } 1143 } 1144 1145 return answer; 1146 } 1147}