/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.model.cloud;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElements;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import org.apache.camel.CamelContext;
import org.apache.camel.CamelContextAware;
import org.apache.camel.ExchangePattern;
import org.apache.camel.Expression;
import org.apache.camel.Processor;
import org.apache.camel.builder.ExpressionClause;
import org.apache.camel.cloud.ServiceChooser;
import org.apache.camel.cloud.ServiceChooserAware;
import org.apache.camel.cloud.ServiceDiscovery;
import org.apache.camel.cloud.ServiceDiscoveryAware;
import org.apache.camel.cloud.ServiceExpressionFactory;
import org.apache.camel.cloud.ServiceFilter;
import org.apache.camel.cloud.ServiceFilterAware;
import org.apache.camel.cloud.ServiceLoadBalancer;
import org.apache.camel.impl.cloud.DefaultServiceCallExpression;
import org.apache.camel.impl.cloud.DefaultServiceCallProcessor;
import org.apache.camel.impl.cloud.DefaultServiceLoadBalancer;
import org.apache.camel.impl.cloud.HealthyServiceFilter;
import org.apache.camel.impl.cloud.PassThroughServiceFilter;
import org.apache.camel.impl.cloud.RandomServiceChooser;
import org.apache.camel.impl.cloud.RoundRobinServiceChooser;
import org.apache.camel.model.NoOutputDefinition;
import org.apache.camel.spi.Metadata;
import org.apache.camel.spi.RouteContext;
import org.apache.camel.util.CamelContextHelper;
import org.apache.camel.util.ObjectHelper;
import org.apache.camel.util.function.Suppliers;
import static org.apache.camel.util.CamelContextHelper.findByType;
import static org.apache.camel.util.CamelContextHelper.lookup;
/**
* To call remote services
*/
@Metadata(label = "eip,routing")
@XmlRootElement(name = "serviceCall")
@XmlAccessorType(XmlAccessType.FIELD)
public class ServiceCallDefinition extends NoOutputDefinition<ServiceCallDefinition> {
@XmlAttribute @Metadata(required = "true")
private String name;
@XmlAttribute
private String uri;
@XmlAttribute @Metadata(defaultValue = ServiceCallDefinitionConstants.DEFAULT_COMPONENT)
private String component;
@XmlAttribute
private ExchangePattern pattern;
@XmlAttribute
private String configurationRef;
@XmlAttribute
private String serviceDiscoveryRef;
@XmlTransient
private ServiceDiscovery serviceDiscovery;
@XmlAttribute
private String serviceFilterRef;
@XmlTransient
private ServiceFilter serviceFilter;
@XmlAttribute
private String serviceChooserRef;
@XmlTransient
private ServiceChooser serviceChooser;
@XmlAttribute
private String loadBalancerRef;
@XmlTransient
private ServiceLoadBalancer loadBalancer;
@XmlAttribute
private String expressionRef;
@XmlTransient
private Expression expression;
@XmlElements({
@XmlElement(name = "cachingServiceDiscovery", type = CachingServiceCallServiceDiscoveryConfiguration.class),
@XmlElement(name = "aggregatingServiceDiscovery", type = AggregatingServiceCallServiceDiscoveryConfiguration.class),
@XmlElement(name = "consulServiceDiscovery", type = ConsulServiceCallServiceDiscoveryConfiguration.class),
@XmlElement(name = "dnsServiceDiscovery", type = DnsServiceCallServiceDiscoveryConfiguration.class),
@XmlElement(name = "etcdServiceDiscovery", type = EtcdServiceCallServiceDiscoveryConfiguration.class),
@XmlElement(name = "kubernetesServiceDiscovery", type = KubernetesServiceCallServiceDiscoveryConfiguration.class),
@XmlElement(name = "staticServiceDiscovery", type = StaticServiceCallServiceDiscoveryConfiguration.class)}
)
private ServiceCallServiceDiscoveryConfiguration serviceDiscoveryConfiguration;
@XmlElements({
@XmlElement(name = "blacklistServiceFilter", type = BlacklistServiceCallServiceFilterConfiguration.class),
@XmlElement(name = "chainedServiceFilter", type = ChainedServiceCallServiceFilterConfiguration.class),
@XmlElement(name = "customServiceFilter", type = CustomServiceCallServiceFilterConfiguration.class),
@XmlElement(name = "healthyServiceFilter", type = HealthyServiceCallServiceFilterConfiguration.class),
@XmlElement(name = "passThroughServiceFilter", type = PassThroughServiceCallServiceFilterConfiguration.class)}
)
private ServiceCallServiceFilterConfiguration serviceFilterConfiguration;
@XmlElements({
@XmlElement(name = "ribbonLoadBalancer", type = RibbonServiceCallServiceLoadBalancerConfiguration.class),
@XmlElement(name = "defaultLoadBalancer", type = DefaultServiceCallServiceLoadBalancerConfiguration.class) }
)
private ServiceCallServiceLoadBalancerConfiguration loadBalancerConfiguration;
@XmlElements({
@XmlElement(name = "expressionConfiguration", type = ServiceCallExpressionConfiguration.class)}
)
private ServiceCallExpressionConfiguration expressionConfiguration;
public ServiceCallDefinition() {
}
@Override
public String toString() {
return "ServiceCall[" + name + "]";
}
@Override
public String getLabel() {
return "serviceCall";
}
// *****************************
// Properties
// *****************************
public String getName() {
return name;
}
/**
* Sets the name of the service to use
*/
public void setName(String name) {
this.name = name;
}
public ExchangePattern getPattern() {
return pattern;
}
/**
* Sets the optional {@link ExchangePattern} used to invoke this endpoint
*/
public void setPattern(ExchangePattern pattern) {
this.pattern = pattern;
}
public String getConfigurationRef() {
return configurationRef;
}
/**
* Refers to a ServiceCall configuration to use
*/
public void setConfigurationRef(String configurationRef) {
this.configurationRef = configurationRef;
}
public String getUri() {
return uri;
}
/**
* The uri of the endpoint to send to.
* The uri can be dynamic computed using the {@link org.apache.camel.language.simple.SimpleLanguage} expression.
*/
public void setUri(String uri) {
this.uri = uri;
}
public String getComponent() {
return component;
}
/**
* The component to use.
*/
public void setComponent(String component) {
this.component = component;
}
public String getServiceDiscoveryRef() {
return serviceDiscoveryRef;
}
/**
* Sets a reference to a custom {@link ServiceDiscovery} to use.
*/
public void setServiceDiscoveryRef(String serviceDiscoveryRef) {
this.serviceDiscoveryRef = serviceDiscoveryRef;
}
public ServiceDiscovery getServiceDiscovery() {
return serviceDiscovery;
}
/**
* Sets a custom {@link ServiceDiscovery} to use.
*/
public void setServiceDiscovery(ServiceDiscovery serviceDiscovery) {
this.serviceDiscovery = serviceDiscovery;
}
public String getServiceFilterRef() {
return serviceFilterRef;
}
/**
* Sets a reference to a custom {@link ServiceFilter} to use.
*/
public void setServiceFilterRef(String serviceFilterRef) {
this.serviceFilterRef = serviceFilterRef;
}
public ServiceFilter getServiceFilter() {
return serviceFilter;
}
/**
* Sets a custom {@link ServiceFilter} to use.
*/
public void setServiceFilter(ServiceFilter serviceFilter) {
this.serviceFilter = serviceFilter;
}
public String getServiceChooserRef() {
return serviceChooserRef;
}
/**
* Sets a reference to a custom {@link ServiceChooser} to use.
*/
public void setServiceChooserRef(String serviceChooserRef) {
this.serviceChooserRef = serviceChooserRef;
}
public ServiceChooser getServiceChooser() {
return serviceChooser;
}
/**
* Sets a custom {@link ServiceChooser} to use.
*/
public void setServiceChooser(ServiceChooser serviceChooser) {
this.serviceChooser = serviceChooser;
}
public String getLoadBalancerRef() {
return loadBalancerRef;
}
/**
* Sets a reference to a custom {@link ServiceLoadBalancer} to use.
*/
public void setLoadBalancerRef(String loadBalancerRef) {
this.loadBalancerRef = loadBalancerRef;
}
public ServiceLoadBalancer getLoadBalancer() {
return loadBalancer;
}
/**
* Sets a custom {@link ServiceLoadBalancer} to use.
*/
public void setLoadBalancer(ServiceLoadBalancer loadBalancer) {
this.loadBalancer = loadBalancer;
}
public String getExpressionRef() {
return expressionRef;
}
/**
* Set a reference to a custom {@link Expression} to use.
*/
public void setExpressionRef(String expressionRef) {
this.expressionRef = expressionRef;
}
public Expression getExpression() {
return expression;
}
/**
* Set a custom {@link Expression} to use.
*/
public void setExpression(Expression expression) {
this.expression = expression;
}
public ServiceCallServiceDiscoveryConfiguration getServiceDiscoveryConfiguration() {
return serviceDiscoveryConfiguration;
}
/**
* Configures the ServiceDiscovery using the given configuration.
*/
public void setServiceDiscoveryConfiguration(ServiceCallServiceDiscoveryConfiguration serviceDiscoveryConfiguration) {
this.serviceDiscoveryConfiguration = serviceDiscoveryConfiguration;
}
public ServiceCallServiceFilterConfiguration getServiceFilterConfiguration() {
return serviceFilterConfiguration;
}
/**
* Configures the ServiceFilter using the given configuration.
*/
public void setServiceFilterConfiguration(ServiceCallServiceFilterConfiguration serviceFilterConfiguration) {
this.serviceFilterConfiguration = serviceFilterConfiguration;
}
public ServiceCallServiceLoadBalancerConfiguration getLoadBalancerConfiguration() {
return loadBalancerConfiguration;
}
/**
* Configures the LoadBalancer using the given configuration.
*/
public void setLoadBalancerConfiguration(ServiceCallServiceLoadBalancerConfiguration loadBalancerConfiguration) {
this.loadBalancerConfiguration = loadBalancerConfiguration;
}
public ServiceCallExpressionConfiguration getExpressionConfiguration() {
return expressionConfiguration;
}
/**
* Configures the Expression using the given configuration.
*/
public void setExpressionConfiguration(ServiceCallExpressionConfiguration expressionConfiguration) {
this.expressionConfiguration = expressionConfiguration;
}
// *****************************
// Fluent API
// *****************************
/**
* Sets the optional {@link ExchangePattern} used to invoke this endpoint
*/
public ServiceCallDefinition pattern(ExchangePattern pattern) {
setPattern(pattern);
return this;
}
/**
* Sets the name of the service to use
*/
public ServiceCallDefinition name(String name) {
setName(name);
return this;
}
/**
* Sets the uri of the service to use
*/
public ServiceCallDefinition uri(String uri) {
setUri(uri);
return this;
}
/**
* Sets the component to use
*/
public ServiceCallDefinition component(String component) {
setComponent(component);
return this;
}
/**
* Refers to a ServiceCall configuration to use
*/
public ServiceCallDefinition serviceCallConfiguration(String ref) {
configurationRef = ref;
return this;
}
/**
* Sets a reference to a custom {@link ServiceDiscovery} to use.
*/
public ServiceCallDefinition serviceDiscovery(String serviceDiscoveryRef) {
setServiceDiscoveryRef(serviceDiscoveryRef);
return this;
}
/**
* Sets a custom {@link ServiceDiscovery} to use.
*/
public ServiceCallDefinition serviceDiscovery(ServiceDiscovery serviceDiscovery) {
setServiceDiscovery(serviceDiscovery);
return this;
}
/**
* Sets a reference to a custom {@link ServiceFilter} to use.
*/
public ServiceCallDefinition serviceFilter(String serviceFilterRef) {
setServiceDiscoveryRef(serviceDiscoveryRef);
return this;
}
/**
* Sets a custom {@link ServiceFilter} to use.
*/
public ServiceCallDefinition serviceFilter(ServiceFilter serviceFilter) {
setServiceFilter(serviceFilter);
return this;
}
/**
* Sets a reference to a custom {@link ServiceChooser} to use.
*/
public ServiceCallDefinition serviceChooser(String serviceChooserRef) {
setServiceChooserRef(serviceChooserRef);
return this;
}
/**
* Sets a custom {@link ServiceChooser} to use.
*/
public ServiceCallDefinition serviceChooser(ServiceChooser serviceChooser) {
setServiceChooser(serviceChooser);
return this;
}
/**
* Sets a reference to a custom {@link ServiceLoadBalancer} to use.
*/
public ServiceCallDefinition loadBalancer(String loadBalancerRef) {
setLoadBalancerRef(loadBalancerRef);
return this;
}
/**
* Sets a custom {@link ServiceLoadBalancer} to use.
*/
public ServiceCallDefinition loadBalancer(ServiceLoadBalancer loadBalancer) {
setLoadBalancer(loadBalancer);
return this;
}
/**
* Sets a reference to a custom {@link Expression} to use.
*/
public ServiceCallDefinition expression(String expressionRef) {
setExpressionRef(loadBalancerRef);
return this;
}
/**
* Sets a custom {@link Expression} to use.
*/
public ServiceCallDefinition expression(Expression expression) {
setExpression(expression);
return this;
}
/**
* Sets a custom {@link Expression} to use through an expression builder clause.
*
* @return a expression builder clause to set the body
*/
public ExpressionClause<ServiceCallDefinition> expression() {
ExpressionClause<ServiceCallDefinition> clause = new ExpressionClause<>(this);
setExpression(clause);
return clause;
}
/**
* Configures the ServiceDiscovery using the given configuration.
*/
public ServiceCallDefinition serviceDiscoveryConfiguration(ServiceCallServiceDiscoveryConfiguration serviceDiscoveryConfiguration) {
setServiceDiscoveryConfiguration(serviceDiscoveryConfiguration);
return this;
}
/**
* Configures the ServiceFilter using the given configuration.
*/
public ServiceCallDefinition serviceFilterConfiguration(ServiceCallServiceFilterConfiguration serviceFilterConfiguration) {
setServiceFilterConfiguration(serviceFilterConfiguration);
return this;
}
/**
* Configures the LoadBalancer using the given configuration.
*/
public ServiceCallDefinition loadBalancerConfiguration(ServiceCallServiceLoadBalancerConfiguration loadBalancerConfiguration) {
setLoadBalancerConfiguration(loadBalancerConfiguration);
return this;
}
/**
* Configures the Expression using the given configuration.
*/
public ServiceCallDefinition expressionConfiguration(ServiceCallExpressionConfiguration expressionConfiguration) {
setExpressionConfiguration(expressionConfiguration);
return this;
}
// *****************************
// Shortcuts - ServiceDiscovery
// *****************************
public CachingServiceCallServiceDiscoveryConfiguration cachingServiceDiscovery() {
CachingServiceCallServiceDiscoveryConfiguration conf = new CachingServiceCallServiceDiscoveryConfiguration(this);
setServiceDiscoveryConfiguration(conf);
return conf;
}
public ConsulServiceCallServiceDiscoveryConfiguration consulServiceDiscovery() {
ConsulServiceCallServiceDiscoveryConfiguration conf = new ConsulServiceCallServiceDiscoveryConfiguration(this);
setServiceDiscoveryConfiguration(conf);
return conf;
}
public ServiceCallDefinition consulServiceDiscovery(String url) {
ConsulServiceCallServiceDiscoveryConfiguration conf = new ConsulServiceCallServiceDiscoveryConfiguration(this);
conf.setUrl(url);
setServiceDiscoveryConfiguration(conf);
return this;
}
public DnsServiceCallServiceDiscoveryConfiguration dnsServiceDiscovery() {
DnsServiceCallServiceDiscoveryConfiguration conf = new DnsServiceCallServiceDiscoveryConfiguration(this);
setServiceDiscoveryConfiguration(conf);
return conf;
}
public ServiceCallDefinition dnsServiceDiscovery(String domain) {
DnsServiceCallServiceDiscoveryConfiguration conf = new DnsServiceCallServiceDiscoveryConfiguration(this);
conf.setDomain(domain);
setServiceDiscoveryConfiguration(conf);
return this;
}
public ServiceCallDefinition dnsServiceDiscovery(String domain, String protocol) {
DnsServiceCallServiceDiscoveryConfiguration conf = new DnsServiceCallServiceDiscoveryConfiguration(this);
conf.setDomain(domain);
conf.setProto(protocol);
setServiceDiscoveryConfiguration(conf);
return this;
}
public EtcdServiceCallServiceDiscoveryConfiguration etcdServiceDiscovery() {
EtcdServiceCallServiceDiscoveryConfiguration conf = new EtcdServiceCallServiceDiscoveryConfiguration(this);
setServiceDiscoveryConfiguration(conf);
return conf;
}
public ServiceCallDefinition etcdServiceDiscovery(String uris) {
EtcdServiceCallServiceDiscoveryConfiguration conf = new EtcdServiceCallServiceDiscoveryConfiguration(this);
conf.setUris(uris);
setServiceDiscoveryConfiguration(conf);
return this;
}
public ServiceCallDefinition etcdServiceDiscovery(String uris, String servicePath) {
EtcdServiceCallServiceDiscoveryConfiguration conf = new EtcdServiceCallServiceDiscoveryConfiguration(this);
conf.setUris(uris);
conf.setServicePath(servicePath);
setServiceDiscoveryConfiguration(conf);
return this;
}
public KubernetesServiceCallServiceDiscoveryConfiguration kubernetesServiceDiscovery() {
KubernetesServiceCallServiceDiscoveryConfiguration conf = new KubernetesServiceCallServiceDiscoveryConfiguration(this);
setServiceDiscoveryConfiguration(conf);
return conf;
}
public KubernetesServiceCallServiceDiscoveryConfiguration kubernetesClientServiceDiscovery() {
KubernetesServiceCallServiceDiscoveryConfiguration conf = new KubernetesServiceCallServiceDiscoveryConfiguration(this);
conf.setLookup("client");
setServiceDiscoveryConfiguration(conf);
return conf;
}
public ServiceCallDefinition kubernetesEnvServiceDiscovery() {
KubernetesServiceCallServiceDiscoveryConfiguration conf = new KubernetesServiceCallServiceDiscoveryConfiguration(this);
conf.setLookup("environment");
setServiceDiscoveryConfiguration(conf);
return this;
}
public ServiceCallDefinition kubernetesDnsServiceDiscovery(String namespace, String domain) {
KubernetesServiceCallServiceDiscoveryConfiguration conf = new KubernetesServiceCallServiceDiscoveryConfiguration(this);
conf.setLookup("dns");
conf.setNamespace(namespace);
conf.setDnsDomain(domain);
setServiceDiscoveryConfiguration(conf);
return this;
}
public AggregatingServiceCallServiceDiscoveryConfiguration multiServiceDiscovery() {
AggregatingServiceCallServiceDiscoveryConfiguration conf = new AggregatingServiceCallServiceDiscoveryConfiguration(this);
setServiceDiscoveryConfiguration(conf);
return conf;
}
public StaticServiceCallServiceDiscoveryConfiguration staticServiceDiscovery() {
StaticServiceCallServiceDiscoveryConfiguration conf = new StaticServiceCallServiceDiscoveryConfiguration(this);
setServiceDiscoveryConfiguration(conf);
return conf;
}
// *****************************
// Shortcuts - ServiceFilter
// *****************************
public ServiceCallDefinition healthyFilter() {
HealthyServiceCallServiceFilterConfiguration conf = new HealthyServiceCallServiceFilterConfiguration(this);
setServiceFilterConfiguration(conf);
return this;
}
public ServiceCallDefinition passThroughFilter() {
PassThroughServiceCallServiceFilterConfiguration conf = new PassThroughServiceCallServiceFilterConfiguration(this);
setServiceFilterConfiguration(conf);
return this;
}
public ChainedServiceCallServiceFilterConfiguration multiFilter() {
ChainedServiceCallServiceFilterConfiguration conf = new ChainedServiceCallServiceFilterConfiguration(this);
setServiceFilterConfiguration(conf);
return conf;
}
public BlacklistServiceCallServiceFilterConfiguration blacklistFilter() {
BlacklistServiceCallServiceFilterConfiguration conf = new BlacklistServiceCallServiceFilterConfiguration();
setServiceFilterConfiguration(conf);
return conf;
}
public ServiceCallDefinition customFilter(String serviceFilter) {
CustomServiceCallServiceFilterConfiguration conf = new CustomServiceCallServiceFilterConfiguration();
conf.setServiceFilterRef(serviceFilter);
setServiceFilterConfiguration(conf);
return this;
}
public ServiceCallDefinition customFilter(ServiceFilter serviceFilter) {
CustomServiceCallServiceFilterConfiguration conf = new CustomServiceCallServiceFilterConfiguration();
conf.setServiceFilter(serviceFilter);
setServiceFilterConfiguration(conf);
return this;
}
// *****************************
// Shortcuts - LoadBalancer
// *****************************
public ServiceCallDefinition defaultLoadBalancer() {
DefaultServiceCallServiceLoadBalancerConfiguration conf = new DefaultServiceCallServiceLoadBalancerConfiguration();
setLoadBalancerConfiguration(conf);
return this;
}
public ServiceCallDefinition ribbonLoadBalancer() {
RibbonServiceCallServiceLoadBalancerConfiguration conf = new RibbonServiceCallServiceLoadBalancerConfiguration(this);
setLoadBalancerConfiguration(conf);
return this;
}
public ServiceCallDefinition ribbonLoadBalancer(String clientName) {
RibbonServiceCallServiceLoadBalancerConfiguration conf = new RibbonServiceCallServiceLoadBalancerConfiguration(this);
conf.setClientName(clientName);
setLoadBalancerConfiguration(conf);
return this;
}
// *****************************
// Processor Factory
// *****************************
@Override
public Processor createProcessor(RouteContext routeContext) throws Exception {
final CamelContext camelContext = routeContext.getCamelContext();
final ServiceDiscovery serviceDiscovery = retrieveServiceDiscovery(camelContext);
final ServiceFilter serviceFilter = retrieveServiceFilter(camelContext);
final ServiceChooser serviceChooser = retrieveServiceChooser(camelContext);
final ServiceLoadBalancer loadBalancer = retrieveLoadBalancer(camelContext);
if (loadBalancer instanceof CamelContextAware) {
((CamelContextAware) loadBalancer).setCamelContext(camelContext);
}
if (loadBalancer instanceof ServiceDiscoveryAware) {
((ServiceDiscoveryAware) loadBalancer).setServiceDiscovery(serviceDiscovery);
}
if (loadBalancer instanceof ServiceFilterAware) {
((ServiceFilterAware) loadBalancer).setServiceFilter(serviceFilter);
}
if (loadBalancer instanceof ServiceChooserAware) {
((ServiceChooserAware) loadBalancer).setServiceChooser(serviceChooser);
}
// The component is used to configure the default scheme to use (eg camel component name).
// The component configured on EIP takes precedence vs configured on configuration.
String endpointScheme = this.component;
if (endpointScheme == null) {
ServiceCallConfigurationDefinition conf = retrieveConfig(camelContext);
if (conf != null) {
endpointScheme = conf.getComponent();
}
}
if (endpointScheme == null) {
ServiceCallConfigurationDefinition conf = retrieveDefaultConfig(camelContext);
if (conf != null) {
endpointScheme = conf.getComponent();
}
}
// The uri is used to tweak the uri.
// The uri configured on EIP takes precedence vs configured on configuration.
String endpointUri = this.uri;
if (endpointUri == null) {
ServiceCallConfigurationDefinition conf = retrieveConfig(camelContext);
if (conf != null) {
endpointUri = conf.getUri();
}
}
if (endpointUri == null) {
ServiceCallConfigurationDefinition conf = retrieveDefaultConfig(camelContext);
if (conf != null) {
endpointUri = conf.getUri();
}
}
// Service name is mandatory
ObjectHelper.notNull(name, "Service name");
endpointScheme = ObjectHelper.applyIfNotEmpty(endpointScheme, camelContext::resolvePropertyPlaceholders, () -> ServiceCallDefinitionConstants.DEFAULT_COMPONENT);
endpointUri = ObjectHelper.applyIfNotEmpty(endpointUri, camelContext::resolvePropertyPlaceholders, () -> null);
return new DefaultServiceCallProcessor(
camelContext,
camelContext.resolvePropertyPlaceholders(name),
endpointScheme,
endpointUri,
pattern,
loadBalancer,
retrieveExpression(camelContext, endpointScheme));
}
// *****************************
// Helpers
// *****************************
private ServiceCallConfigurationDefinition retrieveDefaultConfig(CamelContext camelContext) {
// check if a default configuration is bound to the registry
ServiceCallConfigurationDefinition config = camelContext.getServiceCallConfiguration(null);
if (config == null) {
// Or if it is in the registry
config = lookup(
camelContext,
ServiceCallDefinitionConstants.DEFAULT_SERVICE_CALL_CONFIG_ID,
ServiceCallConfigurationDefinition.class);
}
if (config == null) {
// If no default is set either by searching by name or bound to the
// camel context, assume that if there is a single instance in the
// registry, that is the default one
config = findByType(camelContext, ServiceCallConfigurationDefinition.class);
}
return config;
}
private ServiceCallConfigurationDefinition retrieveConfig(CamelContext camelContext) {
ServiceCallConfigurationDefinition config = null;
if (configurationRef != null) {
// lookup in registry firstNotNull
config = lookup(camelContext, configurationRef, ServiceCallConfigurationDefinition.class);
if (config == null) {
// and fallback as service configuration
config = camelContext.getServiceCallConfiguration(configurationRef);
}
}
return config;
}
// ******************************************
// ServiceDiscovery
// ******************************************
private ServiceDiscovery retrieveServiceDiscovery(CamelContext camelContext, Function<CamelContext, ServiceCallConfigurationDefinition> function) throws Exception {
ServiceDiscovery answer = null;
ServiceCallConfigurationDefinition config = function.apply(camelContext);
if (config != null) {
if (config.getServiceDiscoveryConfiguration() != null) {
answer = config.getServiceDiscoveryConfiguration().newInstance(camelContext);
} else {
answer = retrieve(
ServiceDiscovery.class,
camelContext,
config::getServiceDiscovery,
config::getServiceDiscoveryRef
);
}
}
return answer;
}
private ServiceDiscovery retrieveServiceDiscovery(CamelContext camelContext) throws Exception {
return Suppliers.firstNotNull(
() -> (serviceDiscoveryConfiguration != null) ? serviceDiscoveryConfiguration.newInstance(camelContext) : null,
// Local configuration
() -> retrieve(ServiceDiscovery.class, camelContext, this::getServiceDiscovery, this::getServiceDiscoveryRef),
// Linked configuration
() -> retrieveServiceDiscovery(camelContext, this::retrieveConfig),
// Default configuration
() -> retrieveServiceDiscovery(camelContext, this::retrieveDefaultConfig),
// Check if there is a single instance in the registry
() -> findByType(camelContext, ServiceDiscovery.class),
// From registry
() -> lookup(camelContext, ServiceCallDefinitionConstants.DEFAULT_SERVICE_DISCOVERY_ID, ServiceDiscovery.class)
).orElseGet(
// Default, that's s little ugly but a load balancer may live without
// (i.e. the Ribbon one) so let's delegate the null check to the actual
// impl.
() -> null
);
}
// ******************************************
// ServiceFilter
// ******************************************
private ServiceFilter retrieveServiceFilter(CamelContext camelContext, Function<CamelContext, ServiceCallConfigurationDefinition> function) throws Exception {
ServiceFilter answer = null;
ServiceCallConfigurationDefinition config = function.apply(camelContext);
if (config != null) {
if (config.getServiceFilterConfiguration() != null) {
answer = config.getServiceFilterConfiguration().newInstance(camelContext);
} else {
answer = retrieve(
ServiceFilter.class,
camelContext,
config::getServiceFilter,
config::getServiceFilterRef
);
}
if (answer == null) {
String ref = config.getServiceFilterRef();
if (ObjectHelper.equal("healthy", ref, true)) {
answer = new HealthyServiceFilter();
} else if (ObjectHelper.equal("pass-through", ref, true)) {
answer = new PassThroughServiceFilter();
} else if (ObjectHelper.equal("passthrough", ref, true)) {
answer = new PassThroughServiceFilter();
}
}
}
return answer;
}
private ServiceFilter retrieveServiceFilter(CamelContext camelContext) throws Exception {
return Suppliers.firstNotNull(
() -> (serviceFilterConfiguration != null) ? serviceFilterConfiguration.newInstance(camelContext) : null,
// Local configuration
() -> retrieve(ServiceFilter.class, camelContext, this::getServiceFilter, this::getServiceFilterRef),
// Linked configuration
() -> retrieveServiceFilter(camelContext, this::retrieveConfig),
// Default configuration
() -> retrieveServiceFilter(camelContext, this::retrieveDefaultConfig),
// Check if there is a single instance in the registry
() -> findByType(camelContext, ServiceFilter.class),
// From registry
() -> lookup(camelContext, ServiceCallDefinitionConstants.DEFAULT_SERVICE_FILTER_ID, ServiceFilter.class)
).orElseGet(
// Default
() -> new HealthyServiceFilter()
);
}
// ******************************************
// ServiceChooser
// ******************************************
private ServiceChooser retrieveServiceChooser(CamelContext camelContext, Function<CamelContext, ServiceCallConfigurationDefinition> function) throws Exception {
ServiceChooser answer = null;
ServiceCallConfigurationDefinition config = function.apply(camelContext);
if (config != null) {
answer = retrieve(
ServiceChooser.class,
camelContext,
config::getServiceChooser,
config::getServiceChooserRef
);
if (answer == null) {
String ref = config.getServiceChooserRef();
if (ObjectHelper.equal("roundrobin", ref, true)) {
answer = new RoundRobinServiceChooser();
} else if (ObjectHelper.equal("round-robin", ref, true)) {
answer = new RoundRobinServiceChooser();
} else if (ObjectHelper.equal("random", ref, true)) {
answer = new RandomServiceChooser();
}
}
}
return answer;
}
private ServiceChooser retrieveServiceChooser(CamelContext camelContext) throws Exception {
return Suppliers.firstNotNull(
// Local configuration
() -> retrieve(ServiceChooser.class, camelContext, this::getServiceChooser, this::getServiceChooserRef),
// Linked configuration
() -> retrieveServiceChooser(camelContext, this::retrieveConfig),
// Default configuration
() -> retrieveServiceChooser(camelContext, this::retrieveDefaultConfig),
// Check if there is a single instance in the registry
() -> findByType(camelContext, ServiceChooser.class),
// From registry
() -> lookup(camelContext, ServiceCallDefinitionConstants.DEFAULT_SERVICE_CHOOSER_ID, ServiceChooser.class)
).orElseGet(
// Default
() -> new RoundRobinServiceChooser()
);
}
// ******************************************
// LoadBalancer
// ******************************************
private ServiceLoadBalancer retrieveLoadBalancer(CamelContext camelContext, Function<CamelContext, ServiceCallConfigurationDefinition> function) throws Exception {
ServiceLoadBalancer answer = null;
ServiceCallConfigurationDefinition config = function.apply(camelContext);
if (config != null) {
if (config.getLoadBalancerConfiguration() != null) {
answer = config.getLoadBalancerConfiguration().newInstance(camelContext);
} else {
answer = retrieve(
ServiceLoadBalancer.class,
camelContext,
config::getLoadBalancer,
config::getLoadBalancerRef
);
}
}
return answer;
}
private ServiceLoadBalancer retrieveLoadBalancer(CamelContext camelContext) throws Exception {
return Suppliers.firstNotNull(
() -> (loadBalancerConfiguration != null) ? loadBalancerConfiguration.newInstance(camelContext) : null,
// Local configuration
() -> retrieve(ServiceLoadBalancer.class, camelContext, this::getLoadBalancer, this::getLoadBalancerRef),
// Linked configuration
() -> retrieveLoadBalancer(camelContext, this::retrieveConfig),
// Default configuration
() -> retrieveLoadBalancer(camelContext, this::retrieveDefaultConfig),
// Check if there is a single instance in the registry
() -> findByType(camelContext, ServiceLoadBalancer.class),
// From registry
() -> lookup(camelContext, ServiceCallDefinitionConstants.DEFAULT_LOAD_BALANCER_ID, ServiceLoadBalancer.class)
).orElseGet(
// Default
() -> new DefaultServiceLoadBalancer()
);
}
// ******************************************
// Expression
// ******************************************
private Expression retrieveExpression(CamelContext camelContext, Function<CamelContext, ServiceCallConfigurationDefinition> function) throws Exception {
Expression answer = null;
ServiceCallConfigurationDefinition config = function.apply(camelContext);
if (config != null) {
if (config.getExpressionConfiguration() != null) {
answer = config.getExpressionConfiguration().newInstance(camelContext);
} else {
answer = retrieve(
Expression.class,
camelContext,
config::getExpression,
config::getExpressionRef
);
}
}
return answer;
}
private Expression retrieveExpression(CamelContext camelContext, String component) throws Exception {
Optional<Expression> expression = Suppliers.firstNotNull(
() -> (expressionConfiguration != null) ? expressionConfiguration.newInstance(camelContext) : null,
// Local configuration
() -> retrieve(Expression.class, camelContext, this::getExpression, this::getExpressionRef),
// Linked configuration
() -> retrieveExpression(camelContext, this::retrieveConfig),
// Default configuration
() -> retrieveExpression(camelContext, this::retrieveDefaultConfig),
// From registry
() -> lookup(camelContext, ServiceCallDefinitionConstants.DEFAULT_SERVICE_CALL_EXPRESSION_ID, Expression.class)
);
if (expression.isPresent()) {
return expression.get();
} else {
String lookupName = component + "-service-expression";
// First try to find the factory from the registry.
ServiceExpressionFactory factory = CamelContextHelper.lookup(camelContext, lookupName, ServiceExpressionFactory.class);
if (factory != null) {
// If a factory is found in the registry do not re-configure it as
// it should be pre-configured.
return factory.newInstance(camelContext);
} else {
Class<?> type = null;
try {
// Then use Service factory.
type = camelContext.getFactoryFinder(ServiceCallDefinitionConstants.RESOURCE_PATH).findClass(lookupName);
} catch (Exception e) {
}
if (ObjectHelper.isNotEmpty(type)) {
if (ServiceExpressionFactory.class.isAssignableFrom(type)) {
factory = (ServiceExpressionFactory) camelContext.getInjector().newInstance(type);
} else {
throw new IllegalArgumentException(
"Resolving Expression: " + lookupName + " detected type conflict: Not a ServiceExpressionFactory implementation. Found: " + type.getName());
}
} else {
// If no factory is found, returns the default
factory = context -> new DefaultServiceCallExpression();
}
return factory.newInstance(camelContext);
}
}
}
// ************************************
// Helpers
// ************************************
private <T> T retrieve(Class<T> type, CamelContext camelContext, Supplier<T> instanceSupplier, Supplier<String> refSupplier) {
T answer = null;
if (instanceSupplier != null) {
answer = instanceSupplier.get();
}
if (answer == null && refSupplier != null) {
String ref = refSupplier.get();
if (ref != null) {
answer = lookup(camelContext, ref, type);
}
}
return answer;
}
}