This is an automated email from the ASF dual-hosted git repository. lburgazzoli pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/camel.git
commit 4512c44b37332871c65ba156e4be6b5be2939e0d Author: lburgazzoli <lburgazz...@gmail.com> AuthorDate: Thu May 24 15:16:08 2018 +0200 CAMEL-12518: camel cloud : leverage spring-cloud ServiceRegistry to register routes --- camel-core/pom.xml | 6 + .../apache/camel/cloud/DiscoverableService.java | 2 +- .../camel/impl/cloud/DefaultServiceDefinition.java | 44 ++----- .../impl/cloud/ServiceRegistrationRoutePolicy.java | 60 ++++----- .../camel/impl/cloud/ServiceRegistryTest.java | 134 +++++++++++++++++++++ .../camel/http/common/HttpCommonEndpoint.java | 4 +- .../camel/component/service/ServiceComponent.java | 24 ++-- .../camel/component/service/ServiceEndpoint.java | 6 +- .../boot/util/CompositeConversionService.java | 83 +++++++++++++ .../consul/ConsulServerToServiceDefinition.java | 23 ++-- ...erverToServiceDefinitionAutoConfiguration.java} | 34 +++--- ...tionToConsulRegistrationAutoConfiguration.java} | 4 +- .../src/main/resources/META-INF/spring.factories | 3 +- .../CamelCloudConsulAutoConfigurationTest.java | 27 +++++ .../CamelCloudConsulServiceRegistryTest.java | 3 +- components/camel-spring-cloud-netflix/pom.xml | 4 + ...CamelCloudNetflixRibbonClientConfiguration.java | 47 -------- .../CamelCloudNetflixServiceLoadBalancer.java | 88 ++++++++++++++ ...tflixServiceLoadBalancerAutoConfiguration.java} | 35 +++--- .../src/main/resources/META-INF/spring.factories | 4 +- .../netflix/CamelCloudNetflixServiceCallTest.java | 93 -------------- ...ixServiceLoadBalancerAutoConfigurationTest.java | 78 ++++++++++++ .../src/test/resources/logback.xml | 1 + ...nToZookeeperRegistrationAutoConfiguration.java} | 6 +- .../ZookeeperServerToServiceDefinition.java | 23 ++-- ...eeperToServiceDefinitionAutoConfiguration.java} | 20 ++- .../src/main/resources/META-INF/spring.factories | 3 +- .../CamelCloudZookeeperAutoConfigurationTest.java | 35 ++++++ .../CamelCloudZookeeperServiceRegistryTest.java | 3 +- .../cloud/CamelSpringCloudServiceLoadBalancer.java | 23 ++-- ...gCloudServiceLoadBalancerAutoConfiguration.java | 9 +- .../cloud/CamelSpringCloudServiceRegistry.java | 37 +++--- .../cloud/DefaultLoadBalancerClientAdapter.java | 15 +-- .../spring/cloud/DefaultServiceLoadBalancer.java | 50 ++++++++ .../camel/component/undertow/UndertowEndpoint.java | 4 +- .../consumer/pom.xml | 4 + .../src/main/resources/application.properties | 9 -- 37 files changed, 711 insertions(+), 337 deletions(-) diff --git a/camel-core/pom.xml b/camel-core/pom.xml index 22aa696..0166d5c 100644 --- a/camel-core/pom.xml +++ b/camel-core/pom.xml @@ -174,6 +174,12 @@ <artifactId>awaitility</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.assertj</groupId> + <artifactId>assertj-core</artifactId> + <version>${assertj-version}</version> + <scope>test</scope> + </dependency> <!-- logging --> <dependency> diff --git a/camel-core/src/main/java/org/apache/camel/cloud/DiscoverableService.java b/camel-core/src/main/java/org/apache/camel/cloud/DiscoverableService.java index 6d1946c..d8cc9e3 100644 --- a/camel-core/src/main/java/org/apache/camel/cloud/DiscoverableService.java +++ b/camel-core/src/main/java/org/apache/camel/cloud/DiscoverableService.java @@ -22,5 +22,5 @@ public interface DiscoverableService { /** * Get the service properties. */ - Map<String, Object> getServiceProperties(); + Map<String, String> getServiceProperties(); } diff --git a/camel-core/src/main/java/org/apache/camel/impl/cloud/DefaultServiceDefinition.java b/camel-core/src/main/java/org/apache/camel/impl/cloud/DefaultServiceDefinition.java index 8deace6..cfc1bc1 100644 --- a/camel-core/src/main/java/org/apache/camel/impl/cloud/DefaultServiceDefinition.java +++ b/camel-core/src/main/java/org/apache/camel/impl/cloud/DefaultServiceDefinition.java @@ -169,7 +169,7 @@ public class DefaultServiceDefinition implements ServiceDefinition { } /** - * Fluent builder to contruct ServiceDefinition. + * Fluent builder to construct ServiceDefinition. */ public static class Builder { private String id; @@ -190,46 +190,18 @@ public class DefaultServiceDefinition implements ServiceDefinition { return this; } - public Builder from(Map<String, Object> properties) { - Map<String, Object> options = new HashMap<>(properties); - Object val = null; + public Builder from(Map<String, String> properties) { + ObjectHelper.ifNotEmpty(properties.get(ServiceDefinition.SERVICE_META_ID), this::withId); + ObjectHelper.ifNotEmpty(properties.get(ServiceDefinition.SERVICE_META_NAME), this::withName); + ObjectHelper.ifNotEmpty(properties.get(ServiceDefinition.SERVICE_META_HOST), this::withHost); + ObjectHelper.ifNotEmpty(properties.get(ServiceDefinition.SERVICE_META_PORT), this::withPort); - val = options.remove(ServiceDefinition.SERVICE_META_ID); - if (val != null && val instanceof String) { - withId((String)val); - } - - val = options.remove(ServiceDefinition.SERVICE_META_NAME); - if (val != null && val instanceof String) { - withName((String)val); - } - - val = options.remove(ServiceDefinition.SERVICE_META_HOST); - if (val != null && val instanceof String) { - withHost((String)val); - } - - val = options.remove(ServiceDefinition.SERVICE_META_PORT); - if (val != null && val instanceof String) { - withPort((String)val); - } - if (val != null && val instanceof Integer) { - withPort((Integer)val); - } - - val = options.remove(ServiceDefinition.SERVICE_META_HOST); - if (val != null && val instanceof String) { - withHost((String)val); - } - - for (Map.Entry<String, Object> entry : options.entrySet()) { + for (Map.Entry<String, String> entry : properties.entrySet()) { if (!entry.getKey().startsWith(ServiceDefinition.SERVICE_META_PREFIX)) { continue; } - if (entry.getValue() instanceof String) { - addMeta(entry.getKey(), (String)entry.getValue()); - } + addMeta(entry.getKey(), entry.getValue()); } return this; diff --git a/camel-core/src/main/java/org/apache/camel/impl/cloud/ServiceRegistrationRoutePolicy.java b/camel-core/src/main/java/org/apache/camel/impl/cloud/ServiceRegistrationRoutePolicy.java index f506a04..130b513 100644 --- a/camel-core/src/main/java/org/apache/camel/impl/cloud/ServiceRegistrationRoutePolicy.java +++ b/camel-core/src/main/java/org/apache/camel/impl/cloud/ServiceRegistrationRoutePolicy.java @@ -123,7 +123,7 @@ public class ServiceRegistrationRoutePolicy extends RoutePolicySupport implement private Optional<ServiceDefinition> computeServiceDefinition(Route route) { final Endpoint endpoint = route.getConsumer().getEndpoint(); - final Map<String, Object> properties = new HashMap<>(); + final Map<String, String> properties = new HashMap<>(); if (endpoint instanceof DiscoverableService) { final DiscoverableService service = (DiscoverableService) endpoint; @@ -132,8 +132,22 @@ public class ServiceRegistrationRoutePolicy extends RoutePolicySupport implement properties.putAll(service.getServiceProperties()); } + // then add additional properties from route with ServiceDefinition.SERVICE_META_PREFIX, + // note that route defined properties may override DiscoverableService + // provided ones + for (Map.Entry<String, Object> entry: route.getProperties().entrySet()) { + if (!entry.getKey().startsWith(ServiceDefinition.SERVICE_META_PREFIX)) { + continue; + } + + final String key = entry.getKey(); + final String val = camelContext.getTypeConverter().convertTo(String.class, entry.getValue()); + + properties.put(key, val); + } + // try to get the service id from route properties - String serviceId = (String)route.getProperties().get(ServiceDefinition.SERVICE_META_ID); + String serviceId = properties.get(ServiceDefinition.SERVICE_META_ID); if (serviceId == null) { // if not check if the route id is custom and use it if (route.getRouteContext().getRoute().hasCustomIdAssigned()) { @@ -142,18 +156,18 @@ public class ServiceRegistrationRoutePolicy extends RoutePolicySupport implement } if (serviceId == null) { // finally get the id from the DiscoverableService - serviceId = (String)properties.get(ServiceDefinition.SERVICE_META_ID); + serviceId = properties.get(ServiceDefinition.SERVICE_META_ID); } // try to get the service name from route properties - String serviceName = (String)route.getProperties().get(ServiceDefinition.SERVICE_META_NAME); + String serviceName = properties.get(ServiceDefinition.SERVICE_META_NAME); if (serviceName == null) { // if not check if the route group is defined use the route group serviceName = route.getGroup(); } if (serviceName == null) { // finally get the name from the DiscoverableService - serviceName = (String)properties.get(ServiceDefinition.SERVICE_META_NAME); + serviceName = properties.get(ServiceDefinition.SERVICE_META_NAME); } if (ObjectHelper.isEmpty(serviceId) || ObjectHelper.isEmpty(serviceName)) { @@ -161,32 +175,20 @@ public class ServiceRegistrationRoutePolicy extends RoutePolicySupport implement return Optional.empty(); } + String serviceHost = properties.get(ServiceDefinition.SERVICE_META_HOST); + String servicePort = properties.getOrDefault(ServiceDefinition.SERVICE_META_PORT, "-1"); + // Build the final resource definition from bits collected from the // endpoint and the route. - DefaultServiceDefinition.Builder builder = DefaultServiceDefinition.builder() - .from(properties) - .withId(serviceId) - .withName(serviceName) - .addMeta(ServiceDefinition.SERVICE_META_NAME, serviceName) - .addMeta(ServiceDefinition.SERVICE_META_ID, serviceId); - - // Add additional metadata from route properties whose name starts - // with ServiceDefinition.SERVICE_META_PREFIX. - // - // NOTE: At the moment it is not possible to add properties to a route - // with fluent DSL - for (Map.Entry<String, Object> entry: route.getProperties().entrySet()) { - if (!entry.getKey().startsWith(ServiceDefinition.SERVICE_META_PREFIX)) { - continue; - } - - final String key = entry.getKey().substring(ServiceDefinition.SERVICE_META_PREFIX.length()); - final String val = camelContext.getTypeConverter().convertTo(String.class, entry.getValue()); - - builder.addMeta(key, val); - } - - return Optional.of(builder.build()); + return Optional.of( + new DefaultServiceDefinition( + serviceId, + serviceName, + serviceHost, + Integer.parseInt(servicePort), + properties + ) + ); } } diff --git a/camel-core/src/test/java/org/apache/camel/impl/cloud/ServiceRegistryTest.java b/camel-core/src/test/java/org/apache/camel/impl/cloud/ServiceRegistryTest.java new file mode 100644 index 0000000..6c3cdaa --- /dev/null +++ b/camel-core/src/test/java/org/apache/camel/impl/cloud/ServiceRegistryTest.java @@ -0,0 +1,134 @@ +/** + * 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.impl.cloud; + +import java.util.Collections; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.apache.camel.ContextTestSupport; +import org.apache.camel.cloud.ServiceDefinition; +import org.apache.camel.model.RouteDefinition; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ServiceRegistryTest extends ContextTestSupport { + + // ********************* + // Set up + // ********************* + + @Override + public boolean isUseRouteBuilder() { + return false; + } + + // ********************* + // Tests + // ********************* + + @Test + public void testServiceRegistrationWithRouteproperties() throws Exception { + final String serviceName = UUID.randomUUID().toString(); + final String serviceId = UUID.randomUUID().toString(); + final int port = 9090; + + context.addRouteDefinition( + new RouteDefinition() + .from("direct:start") + .routeProperty(ServiceDefinition.SERVICE_META_NAME, serviceName) + .routeProperty(ServiceDefinition.SERVICE_META_ID, serviceId) + .routeProperty(ServiceDefinition.SERVICE_META_HOST, "localhost") + .routeProperty(ServiceDefinition.SERVICE_META_PORT, "" + port) + .routeProperty("service.meta1", "meta1") + .routeProperty("meta2", "meta2") + .routePolicy(new ServiceRegistrationRoutePolicy()) + .to("mock:end") + ); + + InMemoryServiceRegistry sr = new InMemoryServiceRegistry(); + + context.addService(sr); + context.start(); + + final Map<String, ServiceDefinition> defs = sr.getDefinitions(); + + assertThat(defs).hasSize(1); + + // basic properties + assertThat(defs.values()).first().hasFieldOrPropertyWithValue("name", serviceName); + assertThat(defs.values()).first().hasFieldOrPropertyWithValue("id", serviceId); + assertThat(defs.values()).first().hasFieldOrPropertyWithValue("host", "localhost"); + assertThat(defs.values()).first().hasFieldOrPropertyWithValue("port", port); + + // metadata + assertThat(defs.get(serviceId).getMetadata()).containsEntry(ServiceDefinition.SERVICE_META_NAME, serviceName); + assertThat(defs.get(serviceId).getMetadata()).containsEntry(ServiceDefinition.SERVICE_META_ID, serviceId); + assertThat(defs.get(serviceId).getMetadata()).containsEntry(ServiceDefinition.SERVICE_META_HOST, "localhost"); + assertThat(defs.get(serviceId).getMetadata()).containsEntry(ServiceDefinition.SERVICE_META_PORT, "" + port); + assertThat(defs.get(serviceId).getMetadata()).containsEntry("service.meta1", "meta1"); + assertThat(defs.get(serviceId).getMetadata()).doesNotContainKeys("meta2"); + + } + + // ********************* + // Helpers + // ********************* + + private static class InMemoryServiceRegistry extends AbstractServiceRegistry { + private final ConcurrentMap<String, ServiceDefinition> definitions; + + public InMemoryServiceRegistry() { + super(UUID.randomUUID().toString()); + + this.definitions = new ConcurrentHashMap<>(); + } + + @Override + public void register(ServiceDefinition definition) { + Objects.requireNonNull(definition.getId(), "ServiceDefinition ID"); + Objects.requireNonNull(definition.getName(), "ServiceDefinition Name"); + + definitions.put(definition.getId(), definition); + } + + @Override + public void deregister(ServiceDefinition definition) { + Objects.requireNonNull(definition.getId(), "ServiceDefinition ID"); + Objects.requireNonNull(definition.getName(), "ServiceDefinition Name"); + + definitions.remove(definition.getId()); + } + + @Override + protected void doStart() throws Exception { + } + + @Override + protected void doStop() throws Exception { + definitions.clear(); + } + + Map<String, ServiceDefinition> getDefinitions() { + return Collections.unmodifiableMap(definitions); + } + } +} diff --git a/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpCommonEndpoint.java b/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpCommonEndpoint.java index e7d465e..834cb63 100644 --- a/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpCommonEndpoint.java +++ b/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpCommonEndpoint.java @@ -201,9 +201,9 @@ public abstract class HttpCommonEndpoint extends DefaultEndpoint implements Head //------------------------------------------------------------------------- @Override - public Map<String, Object> getServiceProperties() { + public Map<String, String> getServiceProperties() { return CollectionHelper.immutableMapOf( - ServiceDefinition.SERVICE_META_PORT, getPort(), + ServiceDefinition.SERVICE_META_PORT, Integer.toString(getPort()), ServiceDefinition.SERVICE_META_PATH, getPath(), ServiceDefinition.SERVICE_META_PROTOCOL, getProtocol() ); diff --git a/components/camel-service/src/main/java/org/apache/camel/component/service/ServiceComponent.java b/components/camel-service/src/main/java/org/apache/camel/component/service/ServiceComponent.java index b7e249b..26c3cb7 100644 --- a/components/camel-service/src/main/java/org/apache/camel/component/service/ServiceComponent.java +++ b/components/camel-service/src/main/java/org/apache/camel/component/service/ServiceComponent.java @@ -56,23 +56,27 @@ public class ServiceComponent extends DefaultComponent { ObjectHelper.notNull(serviceName, "Service Name"); ObjectHelper.notNull(delegateUri, "Delegate URI"); - // add service name to the parameters - parameters.put(ServiceDefinition.SERVICE_META_NAME, serviceName); - // Lookup the service registry, this may be a static selected service // or dynamically selected one through a ServiceRegistry.Selector final ServiceRegistry service = getServiceRegistry(); // Compute service definition from parameters, this is used as default // definition - final Map<String, Object> params = new HashMap<>(); - parameters.forEach( - (k, v) -> { - if (k.startsWith(ServiceDefinition.SERVICE_META_PREFIX)) { - params.put(k, v); - } + final Map<String, String> params = new HashMap<>(); + + for (Map.Entry<String, Object> entry: parameters.entrySet()) { + if (!entry.getKey().startsWith(ServiceDefinition.SERVICE_META_PREFIX)) { + continue; } - ); + + final String key = entry.getKey(); + final String val = getCamelContext().getTypeConverter().convertTo(String.class, entry.getValue()); + + params.put(key, val); + } + + // add service name, this is always set from an uri path param + params.put(ServiceDefinition.SERVICE_META_NAME, serviceName); // remove all the service related options so the underlying component // does not fail because of unknown parameters diff --git a/components/camel-service/src/main/java/org/apache/camel/component/service/ServiceEndpoint.java b/components/camel-service/src/main/java/org/apache/camel/component/service/ServiceEndpoint.java index f4bcd55..d16f448 100644 --- a/components/camel-service/src/main/java/org/apache/camel/component/service/ServiceEndpoint.java +++ b/components/camel-service/src/main/java/org/apache/camel/component/service/ServiceEndpoint.java @@ -54,14 +54,14 @@ import org.apache.camel.spi.UriPath; public class ServiceEndpoint extends DefaultEndpoint implements DelegateEndpoint { private final Endpoint delegateEndpoint; private final ServiceRegistry serviceRegistry; - private final Map<String, Object> serviceParameters; + private final Map<String, String> serviceParameters; private final ServiceDefinition serviceDefinition; @UriPath(description = "The endpoint uri to expose as service") @Metadata(required = "true") private final String delegateUri; - public ServiceEndpoint(String uri, ServiceComponent component, ServiceRegistry serviceRegistry, Map<String, Object> serviceParameters, String delegateUri) { + public ServiceEndpoint(String uri, ServiceComponent component, ServiceRegistry serviceRegistry, Map<String, String> serviceParameters, String delegateUri) { super(uri, component); this.serviceRegistry = serviceRegistry; @@ -101,7 +101,7 @@ public class ServiceEndpoint extends DefaultEndpoint implements DelegateEndpoint } private ServiceDefinition computeServiceDefinition(CamelContext context, Endpoint delegateEndpoint) { - Map<String, Object> parameters = new HashMap<>(); + Map<String, String> parameters = new HashMap<>(); if (delegateEndpoint instanceof DiscoverableService) { parameters.putAll(((DiscoverableService)delegateEndpoint).getServiceProperties()); diff --git a/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/util/CompositeConversionService.java b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/util/CompositeConversionService.java new file mode 100644 index 0000000..e397653 --- /dev/null +++ b/components/camel-spring-boot/src/main/java/org/apache/camel/spring/boot/util/CompositeConversionService.java @@ -0,0 +1,83 @@ +/** + * 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.spring.boot.util; + +import java.util.List; + +import org.springframework.core.convert.ConversionException; +import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.TypeDescriptor; + +public class CompositeConversionService implements ConversionService { + private final List<ConversionService> delegates; + + public CompositeConversionService(List<ConversionService> delegates) { + this.delegates = delegates; + } + + @Override + public boolean canConvert(Class<?> sourceType, Class<?> targetType) { + for (ConversionService service : this.delegates) { + if (service.canConvert(sourceType, targetType)) { + return true; + } + } + return false; + } + + @Override + public boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType) { + for (ConversionService service : this.delegates) { + if (service.canConvert(sourceType, targetType)) { + return true; + } + } + return false; + } + + @Override + public <T> T convert(Object source, Class<T> targetType) { + for (int i = 0; i < this.delegates.size() - 1; i++) { + try { + ConversionService delegate = this.delegates.get(i); + if (delegate.canConvert(source.getClass(), targetType)) { + return delegate.convert(source, targetType); + } + } catch (ConversionException e) { + // ignored + } + } + + return this.delegates.get(this.delegates.size() - 1).convert(source, targetType); + } + + @Override + public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { + for (int i = 0; i < this.delegates.size() - 1; i++) { + try { + ConversionService delegate = this.delegates.get(i); + if (delegate.canConvert(sourceType, targetType)) { + return delegate.convert(source, sourceType, targetType); + } + } catch (ConversionException e) { + // ignored + } + } + + return this.delegates.get(this.delegates.size() - 1).convert(source, sourceType, targetType); + } +} diff --git a/camel-core/src/main/java/org/apache/camel/cloud/DiscoverableService.java b/components/camel-spring-cloud-consul/src/main/java/org/apache/camel/spring/cloud/consul/ConsulServerToServiceDefinition.java similarity index 55% copy from camel-core/src/main/java/org/apache/camel/cloud/DiscoverableService.java copy to components/camel-spring-cloud-consul/src/main/java/org/apache/camel/spring/cloud/consul/ConsulServerToServiceDefinition.java index 6d1946c..cf50710 100644 --- a/camel-core/src/main/java/org/apache/camel/cloud/DiscoverableService.java +++ b/components/camel-spring-cloud-consul/src/main/java/org/apache/camel/spring/cloud/consul/ConsulServerToServiceDefinition.java @@ -14,13 +14,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.cloud; +package org.apache.camel.spring.cloud.consul; -import java.util.Map; +import org.apache.camel.cloud.ServiceDefinition; +import org.apache.camel.impl.cloud.DefaultServiceDefinition; +import org.springframework.cloud.consul.discovery.ConsulServer; +import org.springframework.core.convert.converter.Converter; -public interface DiscoverableService { - /** - * Get the service properties. - */ - Map<String, Object> getServiceProperties(); +public final class ConsulServerToServiceDefinition implements Converter<ConsulServer, ServiceDefinition> { + + @Override + public ServiceDefinition convert(ConsulServer source) { + return new DefaultServiceDefinition( + source.getId(), + source.getHost(), + source.getPort(), + source.getMetadata() + ); + } } diff --git a/components/camel-spring-cloud-netflix/src/main/java/org/apache/camel/spring/cloud/netflix/CamelCloudNetflixRibbonAutoConfiguration.java b/components/camel-spring-cloud-consul/src/main/java/org/apache/camel/spring/cloud/consul/ConsulServerToServiceDefinitionAutoConfiguration.java similarity index 54% rename from components/camel-spring-cloud-netflix/src/main/java/org/apache/camel/spring/cloud/netflix/CamelCloudNetflixRibbonAutoConfiguration.java rename to components/camel-spring-cloud-consul/src/main/java/org/apache/camel/spring/cloud/consul/ConsulServerToServiceDefinitionAutoConfiguration.java index 5631507..ff94103 100644 --- a/components/camel-spring-cloud-netflix/src/main/java/org/apache/camel/spring/cloud/netflix/CamelCloudNetflixRibbonAutoConfiguration.java +++ b/components/camel-spring-cloud-consul/src/main/java/org/apache/camel/spring/cloud/consul/ConsulServerToServiceDefinitionAutoConfiguration.java @@ -14,25 +14,29 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.spring.cloud.netflix; +package org.apache.camel.spring.cloud.consul; +import org.apache.camel.cloud.ServiceDefinition; import org.apache.camel.spring.boot.util.GroupCondition; -import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration; -import org.springframework.cloud.netflix.ribbon.RibbonClients; -import org.springframework.cloud.netflix.ribbon.SpringClientFactory; +import org.apache.camel.spring.cloud.CamelSpringCloudServiceLoadBalancerAutoConfiguration; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.cloud.consul.ConditionalOnConsulEnabled; +import org.springframework.cloud.consul.discovery.ConsulServer; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; +import org.springframework.core.convert.converter.Converter; @Configuration -@EnableConfigurationProperties -@ConditionalOnBean(SpringClientFactory.class) -@Conditional(CamelCloudNetflixRibbonAutoConfiguration.Condition.class) -@AutoConfigureAfter({ CamelCloudNetflixAutoConfiguration.class, RibbonAutoConfiguration.class }) -@RibbonClients(defaultConfiguration = CamelCloudNetflixRibbonClientConfiguration.class) -public class CamelCloudNetflixRibbonAutoConfiguration { +@AutoConfigureBefore(CamelSpringCloudServiceLoadBalancerAutoConfiguration.class) +@ConditionalOnConsulEnabled +@Conditional(ConsulServerToServiceDefinitionAutoConfiguration.Condition.class) +public class ConsulServerToServiceDefinitionAutoConfiguration { + + @Bean(name = "consul-server-to-service-definition") + public Converter<ConsulServer, ServiceDefinition> consulServerToServiceDefinition() { + return new ConsulServerToServiceDefinition(); + } // ******************************* // Condition @@ -41,8 +45,8 @@ public class CamelCloudNetflixRibbonAutoConfiguration { public static class Condition extends GroupCondition { public Condition() { super( - "camel.cloud.netflix", - "camel.cloud.netflix.ribbon" + "camel.cloud", + "camel.cloud.consul" ); } } diff --git a/components/camel-spring-cloud-consul/src/main/java/org/apache/camel/spring/cloud/consul/CamelCloudConsulAutoConfiguration.java b/components/camel-spring-cloud-consul/src/main/java/org/apache/camel/spring/cloud/consul/ServiceDefinitionToConsulRegistrationAutoConfiguration.java similarity index 94% rename from components/camel-spring-cloud-consul/src/main/java/org/apache/camel/spring/cloud/consul/CamelCloudConsulAutoConfiguration.java rename to components/camel-spring-cloud-consul/src/main/java/org/apache/camel/spring/cloud/consul/ServiceDefinitionToConsulRegistrationAutoConfiguration.java index a1ba31f..1f42dcf 100644 --- a/components/camel-spring-cloud-consul/src/main/java/org/apache/camel/spring/cloud/consul/CamelCloudConsulAutoConfiguration.java +++ b/components/camel-spring-cloud-consul/src/main/java/org/apache/camel/spring/cloud/consul/ServiceDefinitionToConsulRegistrationAutoConfiguration.java @@ -32,9 +32,9 @@ import org.springframework.core.convert.converter.Converter; @Configuration @AutoConfigureBefore(CamelSpringCloudServiceRegistryAutoConfiguration.class) @ConditionalOnConsulEnabled -@Conditional(CamelCloudConsulAutoConfiguration.Condition.class) +@Conditional(ServiceDefinitionToConsulRegistrationAutoConfiguration.Condition.class) @EnableConfigurationProperties(CamelCloudConfigurationProperties.class) -public class CamelCloudConsulAutoConfiguration { +public class ServiceDefinitionToConsulRegistrationAutoConfiguration { @Bean(name = "service-definition-to-consul-registration") public Converter<ServiceDefinition, ConsulRegistration> serviceDefinitionToConsulRegistration( diff --git a/components/camel-spring-cloud-consul/src/main/resources/META-INF/spring.factories b/components/camel-spring-cloud-consul/src/main/resources/META-INF/spring.factories index 56dd79f..43705ca 100644 --- a/components/camel-spring-cloud-consul/src/main/resources/META-INF/spring.factories +++ b/components/camel-spring-cloud-consul/src/main/resources/META-INF/spring.factories @@ -16,4 +16,5 @@ # org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ - org.apache.camel.spring.cloud.consul.CamelCloudConsulAutoConfiguration \ No newline at end of file + org.apache.camel.spring.cloud.consul.ServiceDefinitionToConsulRegistrationAutoConfiguration,\ + org.apache.camel.spring.cloud.consul.ConsulServerToServiceDefinitionAutoConfiguration \ No newline at end of file diff --git a/components/camel-spring-cloud-consul/src/test/java/org/apache/camel/spring/cloud/consul/CamelCloudConsulAutoConfigurationTest.java b/components/camel-spring-cloud-consul/src/test/java/org/apache/camel/spring/cloud/consul/CamelCloudConsulAutoConfigurationTest.java index 83e50df..a291515 100644 --- a/components/camel-spring-cloud-consul/src/test/java/org/apache/camel/spring/cloud/consul/CamelCloudConsulAutoConfigurationTest.java +++ b/components/camel-spring-cloud-consul/src/test/java/org/apache/camel/spring/cloud/consul/CamelCloudConsulAutoConfigurationTest.java @@ -57,6 +57,33 @@ public class CamelCloudConsulAutoConfigurationTest { } } + @Test + public void testConsulServerToServiceDefinition() throws Exception { + ConfigurableApplicationContext context = new SpringApplicationBuilder(TestConfiguration.class) + .web(WebApplicationType.NONE) + .run( + "--debug=false", + "--spring.main.banner-mode=OFF", + "--spring.application.name=" + UUID.randomUUID().toString(), + "--ribbon.enabled=false", + "--ribbon.eureka.enabled=false", + "--management.endpoint.enabled=false", + "--spring.cloud.consul.enabled=true", + "--spring.cloud.consul.config.enabled=false", + "--spring.cloud.consul.discovery.enabled=true", + "--spring.cloud.service-registry.auto-registration.enabled=false" + ); + + try { + Map<String, Converter> converters = context.getBeansOfType(Converter.class); + + assertThat(converters).isNotNull(); + assertThat(converters.values().stream().anyMatch(ConsulServerToServiceDefinition.class::isInstance)).isTrue(); + } finally { + context.close(); + } + } + // ************************************* // Config // ************************************* diff --git a/components/camel-spring-cloud-consul/src/test/java/org/apache/camel/spring/cloud/consul/CamelCloudConsulServiceRegistryTest.java b/components/camel-spring-cloud-consul/src/test/java/org/apache/camel/spring/cloud/consul/CamelCloudConsulServiceRegistryTest.java index b576351..e1a9e95 100644 --- a/components/camel-spring-cloud-consul/src/test/java/org/apache/camel/spring/cloud/consul/CamelCloudConsulServiceRegistryTest.java +++ b/components/camel-spring-cloud-consul/src/test/java/org/apache/camel/spring/cloud/consul/CamelCloudConsulServiceRegistryTest.java @@ -62,7 +62,8 @@ public class CamelCloudConsulServiceRegistryTest { "--spring.cloud.consul.port=" + container.getMappedPort(8500), "--spring.cloud.consul.config.enabled=false", "--spring.cloud.consul.discovery.enabled=true", - "--spring.cloud.service-registry.auto-registration.enabled=false" + "--spring.cloud.service-registry.auto-registration.enabled=false", + "--camel.cloud.service-registry.service-host=localhost" ); try { diff --git a/components/camel-spring-cloud-netflix/pom.xml b/components/camel-spring-cloud-netflix/pom.xml index b412e93..c5111e7 100644 --- a/components/camel-spring-cloud-netflix/pom.xml +++ b/components/camel-spring-cloud-netflix/pom.xml @@ -91,6 +91,10 @@ <artifactId>camel-spring-boot</artifactId> </dependency> <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-spring-cloud</artifactId> + </dependency> + <dependency> <groupId>io.reactivex</groupId> <artifactId>rxjava</artifactId> <version>${rxjava-version}</version> diff --git a/components/camel-spring-cloud-netflix/src/main/java/org/apache/camel/spring/cloud/netflix/CamelCloudNetflixRibbonClientConfiguration.java b/components/camel-spring-cloud-netflix/src/main/java/org/apache/camel/spring/cloud/netflix/CamelCloudNetflixRibbonClientConfiguration.java deleted file mode 100644 index 1b492a8..0000000 --- a/components/camel-spring-cloud-netflix/src/main/java/org/apache/camel/spring/cloud/netflix/CamelCloudNetflixRibbonClientConfiguration.java +++ /dev/null @@ -1,47 +0,0 @@ -/** - * 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.spring.cloud.netflix; - -import com.netflix.client.config.IClientConfig; -import com.netflix.loadbalancer.ServerList; -import org.apache.camel.spring.boot.cloud.CamelCloudServiceDiscovery; -import org.apache.camel.spring.boot.cloud.CamelCloudServiceFilter; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class CamelCloudNetflixRibbonClientConfiguration { - @Autowired - private IClientConfig clientConfig; - @Autowired - private CamelCloudServiceDiscovery serviceDiscovery; - @Autowired - private CamelCloudServiceFilter serviceFilter; - - @Bean - @ConditionalOnMissingBean - public ServerList<?> ribbonServerList() { - CamelCloudNetflixServerList serverList = new CamelCloudNetflixServerList(); - serverList.setServiceDiscovery(serviceDiscovery); - serverList.setServiceFilter(serviceFilter); - serverList.initWithNiwsConfig(clientConfig); - - return serverList; - } -} diff --git a/components/camel-spring-cloud-netflix/src/main/java/org/apache/camel/spring/cloud/netflix/CamelCloudNetflixServiceLoadBalancer.java b/components/camel-spring-cloud-netflix/src/main/java/org/apache/camel/spring/cloud/netflix/CamelCloudNetflixServiceLoadBalancer.java new file mode 100644 index 0000000..a13211d --- /dev/null +++ b/components/camel-spring-cloud-netflix/src/main/java/org/apache/camel/spring/cloud/netflix/CamelCloudNetflixServiceLoadBalancer.java @@ -0,0 +1,88 @@ +/** + * 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.spring.cloud.netflix; + +import java.util.List; + +import com.netflix.loadbalancer.Server; +import org.apache.camel.cloud.ServiceDefinition; +import org.apache.camel.cloud.ServiceLoadBalancer; +import org.apache.camel.cloud.ServiceLoadBalancerFunction; +import org.apache.camel.impl.cloud.DefaultServiceDefinition; +import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; +import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient; +import org.springframework.core.convert.ConversionService; + +public class CamelCloudNetflixServiceLoadBalancer implements ServiceLoadBalancer { + private final LoadBalancerClient client; + private final List<ConversionService> conversionServices; + + public CamelCloudNetflixServiceLoadBalancer(LoadBalancerClient client, List<ConversionService> conversionServices) { + this.client = client; + this.conversionServices = conversionServices; + } + + @Override + public <T> T process(String serviceName, ServiceLoadBalancerFunction<T> function) throws Exception { + return client.execute(serviceName, instance -> { + ServiceDefinition definition = null; + + // + // this should not be needed but there is a bug or misbehavior on + // spring cloud netflix side (2.x) that prevent ribbon load balancer + // to propagate metadata from i.e. consul, see: + // + // https://github.com/spring-cloud/spring-cloud-consul/issues/424 + // + // so here we do try to find a converter that is able to use the + // underlying server implementation to extract meta-data and any + // other thing needed by Camel. + // + + if (instance instanceof RibbonLoadBalancerClient.RibbonServer) { + Server server = RibbonLoadBalancerClient.RibbonServer.class.cast(instance).getServer(); + + for (int i = 0; i < conversionServices.size(); i++) { + ConversionService cs = conversionServices.get(i); + + if (cs.canConvert(server.getClass(), ServiceDefinition.class)) { + definition = cs.convert(server, ServiceDefinition.class); + + if (definition != null) { + break; + } + } + } + } + + // If no conversion is possible we use the info found on service + // instance given by the load balancer as it is so the result may + // be incomplete + + if (definition == null) { + definition = new DefaultServiceDefinition( + instance.getServiceId(), + instance.getHost(), + instance.getPort(), + instance.getMetadata() + ); + } + + return function.apply(definition); + }); + } +} diff --git a/components/camel-spring-cloud-zookeeper/src/main/java/org/apache/camel/spring/cloud/zookeeper/CamelCloudZookeeperAutoConfiguration.java b/components/camel-spring-cloud-netflix/src/main/java/org/apache/camel/spring/cloud/netflix/CamelCloudNetflixServiceLoadBalancerAutoConfiguration.java similarity index 56% copy from components/camel-spring-cloud-zookeeper/src/main/java/org/apache/camel/spring/cloud/zookeeper/CamelCloudZookeeperAutoConfiguration.java copy to components/camel-spring-cloud-netflix/src/main/java/org/apache/camel/spring/cloud/netflix/CamelCloudNetflixServiceLoadBalancerAutoConfiguration.java index b223e02..9f01558 100644 --- a/components/camel-spring-cloud-zookeeper/src/main/java/org/apache/camel/spring/cloud/zookeeper/CamelCloudZookeeperAutoConfiguration.java +++ b/components/camel-spring-cloud-netflix/src/main/java/org/apache/camel/spring/cloud/netflix/CamelCloudNetflixServiceLoadBalancerAutoConfiguration.java @@ -14,32 +14,35 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.spring.cloud.zookeeper; +package org.apache.camel.spring.cloud.netflix; + +import java.util.List; -import org.apache.camel.cloud.ServiceDefinition; -import org.apache.camel.spring.boot.cloud.CamelCloudConfigurationProperties; import org.apache.camel.spring.boot.util.GroupCondition; +import org.apache.camel.spring.cloud.CamelSpringCloudServiceLoadBalancer; import org.apache.camel.spring.cloud.CamelSpringCloudServiceRegistryAutoConfiguration; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureBefore; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cloud.zookeeper.ConditionalOnZookeeperEnabled; -import org.springframework.cloud.zookeeper.serviceregistry.ZookeeperRegistration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; +import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; -import org.springframework.core.convert.converter.Converter; +import org.springframework.core.convert.ConversionService; @Configuration +@AutoConfigureAfter(RibbonAutoConfiguration.class) @AutoConfigureBefore(CamelSpringCloudServiceRegistryAutoConfiguration.class) -@ConditionalOnZookeeperEnabled -@Conditional(CamelCloudZookeeperAutoConfiguration.Condition.class) -@EnableConfigurationProperties(CamelCloudConfigurationProperties.class) -public class CamelCloudZookeeperAutoConfiguration { +@Conditional(CamelCloudNetflixServiceLoadBalancerAutoConfiguration.Condition.class) +public class CamelCloudNetflixServiceLoadBalancerAutoConfiguration { - @Bean(name = "service-definition-to-zookeeper-registration") - public Converter<ServiceDefinition, ZookeeperRegistration> serviceDefinitionToConsulRegistration( - CamelCloudConfigurationProperties properties) { - return new ServiceDefinitionToZookeeperRegistration(properties); + @ConditionalOnBean(LoadBalancerClient.class) + @ConditionalOnMissingBean + @Bean("netflix-client-load-balancer-adapter") + public CamelSpringCloudServiceLoadBalancer.LoadBalancerClientAdapter netflixClientLoadBalancerAdapter(List<ConversionService> conversionServices) { + return client -> new CamelCloudNetflixServiceLoadBalancer(client, conversionServices); } // ******************************* @@ -50,7 +53,7 @@ public class CamelCloudZookeeperAutoConfiguration { public Condition() { super( "camel.cloud", - "camel.cloud.zookeeper" + "camel.cloud.netflix" ); } } diff --git a/components/camel-spring-cloud-netflix/src/main/resources/META-INF/spring.factories b/components/camel-spring-cloud-netflix/src/main/resources/META-INF/spring.factories index 1926ceb..4d93027 100644 --- a/components/camel-spring-cloud-netflix/src/main/resources/META-INF/spring.factories +++ b/components/camel-spring-cloud-netflix/src/main/resources/META-INF/spring.factories @@ -16,5 +16,5 @@ # org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ -org.apache.camel.spring.cloud.netflix.CamelCloudNetflixAutoConfiguration,\ -org.apache.camel.spring.cloud.netflix.CamelCloudNetflixRibbonAutoConfiguration \ No newline at end of file + org.apache.camel.spring.cloud.netflix.CamelCloudNetflixAutoConfiguration,\ + org.apache.camel.spring.cloud.netflix.CamelCloudNetflixServiceLoadBalancerAutoConfiguration \ No newline at end of file diff --git a/components/camel-spring-cloud-netflix/src/test/java/org/apache/camel/spring/cloud/netflix/CamelCloudNetflixServiceCallTest.java b/components/camel-spring-cloud-netflix/src/test/java/org/apache/camel/spring/cloud/netflix/CamelCloudNetflixServiceCallTest.java deleted file mode 100644 index 0cd76bb..0000000 --- a/components/camel-spring-cloud-netflix/src/test/java/org/apache/camel/spring/cloud/netflix/CamelCloudNetflixServiceCallTest.java +++ /dev/null @@ -1,93 +0,0 @@ -/** - * 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.spring.cloud.netflix; - -import org.apache.camel.ProducerTemplate; -import org.apache.camel.builder.RouteBuilder; -import org.apache.camel.spring.boot.CamelAutoConfiguration; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.junit4.SpringRunner; - -@DirtiesContext -@RunWith(SpringRunner.class) -@SpringBootApplication -@SpringBootTest( - classes = { - CamelAutoConfiguration.class, - CamelCloudNetflixAutoConfiguration.class, - CamelCloudNetflixServiceCallTest.TestConfiguration.class, - RibbonClientConfiguration.class, - }, - properties = { - "camel.cloud.load-balancer.enabled=true", - "camel.cloud.service-discovery.services[custom-svc-list]=localhost:9090,localhost:9091,localhost:9092", - "camel.cloud.service-filter.blacklist[custom-svc-list]=localhost:9091", - "ribbon.enabled=true", - "ribbon.client.name=custom-svc-list", - "ribbon.eureka.enabled=false", - "debug=false" - } -) -public class CamelCloudNetflixServiceCallTest { - @Autowired - private ProducerTemplate template; - - @Test - public void testServiceCall() throws Exception { - Assert.assertEquals("9090", template.requestBody("direct:start", null, String.class)); - Assert.assertEquals("9092", template.requestBody("direct:start", null, String.class)); - } - - // *********************************************** - // Configuration - // *********************************************** - - @Configuration - public static class TestConfiguration { - @Bean - public RouteBuilder myRouteBuilder() { - return new RouteBuilder() { - @Override - public void configure() throws Exception { - from("direct:start") - .serviceCall() - .name("custom-svc-list/hello"); - - from("jetty:http://localhost:9090/hello") - .transform() - .constant("9090"); - from("jetty:http://localhost:9091/hello") - .transform() - .constant("9091"); - from("jetty:http://localhost:9092/hello") - .transform() - .constant("9092"); - } - }; - } - } -} - diff --git a/components/camel-spring-cloud-netflix/src/test/java/org/apache/camel/spring/cloud/netflix/CamelCloudNetflixServiceLoadBalancerAutoConfigurationTest.java b/components/camel-spring-cloud-netflix/src/test/java/org/apache/camel/spring/cloud/netflix/CamelCloudNetflixServiceLoadBalancerAutoConfigurationTest.java new file mode 100644 index 0000000..297638a --- /dev/null +++ b/components/camel-spring-cloud-netflix/src/test/java/org/apache/camel/spring/cloud/netflix/CamelCloudNetflixServiceLoadBalancerAutoConfigurationTest.java @@ -0,0 +1,78 @@ +/** + * 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.spring.cloud.netflix; + +import org.apache.camel.cloud.ServiceLoadBalancer; +import org.apache.camel.spring.boot.CamelAutoConfiguration; +import org.apache.camel.spring.boot.cloud.CamelCloudAutoConfiguration; +import org.apache.camel.spring.cloud.CamelSpringCloudServiceLoadBalancer; +import org.apache.camel.spring.cloud.CamelSpringCloudServiceRegistryAutoConfiguration; +import org.junit.Test; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; +import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration; +import org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration; +import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.Assertions.assertThat; + +public class CamelCloudNetflixServiceLoadBalancerAutoConfigurationTest { + + @Test + public void testAutoConfiguration() { + new ApplicationContextRunner() + .withConfiguration( + AutoConfigurations.of( + CamelAutoConfiguration.class, + CamelCloudAutoConfiguration.class, + CamelSpringCloudServiceRegistryAutoConfiguration.class, + CamelCloudNetflixServiceLoadBalancerAutoConfiguration.class, + RibbonAutoConfiguration.class, + RibbonClientConfiguration.class + )) + .withUserConfiguration( + TestConfiguration.class) + .withPropertyValues( + "debug=true", + "spring.main.banner-mode=off", + "ribbon.client.name=test") + .run( + context -> { + assertThat(context).hasSingleBean(LoadBalancerClient.class); + assertThat(context).getBean(LoadBalancerClient.class).isInstanceOf(RibbonLoadBalancerClient.class); + + assertThat(context).hasSingleBean(CamelSpringCloudServiceLoadBalancer.LoadBalancerClientAdapter.class); + + LoadBalancerClient client = context.getBean(LoadBalancerClient.class); + ServiceLoadBalancer balancer = context.getBean(CamelSpringCloudServiceLoadBalancer.LoadBalancerClientAdapter.class).adapt(client); + + assertThat(balancer).isInstanceOf(CamelCloudNetflixServiceLoadBalancer.class); + } + ); + } + + + @EnableAutoConfiguration + @Configuration + public static class TestConfiguration { + + } +} + diff --git a/components/camel-spring-cloud-netflix/src/test/resources/logback.xml b/components/camel-spring-cloud-netflix/src/test/resources/logback.xml index 75c70d1..848cd0f 100644 --- a/components/camel-spring-cloud-netflix/src/test/resources/logback.xml +++ b/components/camel-spring-cloud-netflix/src/test/resources/logback.xml @@ -35,6 +35,7 @@ </appender> <root level="INFO"> + <!--<appender-ref ref="STDOUT"/>--> <appender-ref ref="FILE"/> </root> diff --git a/components/camel-spring-cloud-zookeeper/src/main/java/org/apache/camel/spring/cloud/zookeeper/CamelCloudZookeeperAutoConfiguration.java b/components/camel-spring-cloud-zookeeper/src/main/java/org/apache/camel/spring/cloud/zookeeper/ServiceDefinitionToZookeeperRegistrationAutoConfiguration.java similarity index 92% copy from components/camel-spring-cloud-zookeeper/src/main/java/org/apache/camel/spring/cloud/zookeeper/CamelCloudZookeeperAutoConfiguration.java copy to components/camel-spring-cloud-zookeeper/src/main/java/org/apache/camel/spring/cloud/zookeeper/ServiceDefinitionToZookeeperRegistrationAutoConfiguration.java index b223e02..38435af 100644 --- a/components/camel-spring-cloud-zookeeper/src/main/java/org/apache/camel/spring/cloud/zookeeper/CamelCloudZookeeperAutoConfiguration.java +++ b/components/camel-spring-cloud-zookeeper/src/main/java/org/apache/camel/spring/cloud/zookeeper/ServiceDefinitionToZookeeperRegistrationAutoConfiguration.java @@ -32,12 +32,12 @@ import org.springframework.core.convert.converter.Converter; @Configuration @AutoConfigureBefore(CamelSpringCloudServiceRegistryAutoConfiguration.class) @ConditionalOnZookeeperEnabled -@Conditional(CamelCloudZookeeperAutoConfiguration.Condition.class) +@Conditional(ServiceDefinitionToZookeeperRegistrationAutoConfiguration.Condition.class) @EnableConfigurationProperties(CamelCloudConfigurationProperties.class) -public class CamelCloudZookeeperAutoConfiguration { +public class ServiceDefinitionToZookeeperRegistrationAutoConfiguration { @Bean(name = "service-definition-to-zookeeper-registration") - public Converter<ServiceDefinition, ZookeeperRegistration> serviceDefinitionToConsulRegistration( + public Converter<ServiceDefinition, ZookeeperRegistration> serviceDefinitionToZookeeperRegistration( CamelCloudConfigurationProperties properties) { return new ServiceDefinitionToZookeeperRegistration(properties); } diff --git a/camel-core/src/main/java/org/apache/camel/cloud/DiscoverableService.java b/components/camel-spring-cloud-zookeeper/src/main/java/org/apache/camel/spring/cloud/zookeeper/ZookeeperServerToServiceDefinition.java similarity index 53% copy from camel-core/src/main/java/org/apache/camel/cloud/DiscoverableService.java copy to components/camel-spring-cloud-zookeeper/src/main/java/org/apache/camel/spring/cloud/zookeeper/ZookeeperServerToServiceDefinition.java index 6d1946c..463146a 100644 --- a/camel-core/src/main/java/org/apache/camel/cloud/DiscoverableService.java +++ b/components/camel-spring-cloud-zookeeper/src/main/java/org/apache/camel/spring/cloud/zookeeper/ZookeeperServerToServiceDefinition.java @@ -14,13 +14,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.cloud; +package org.apache.camel.spring.cloud.zookeeper; -import java.util.Map; +import org.apache.camel.cloud.ServiceDefinition; +import org.apache.camel.impl.cloud.DefaultServiceDefinition; +import org.springframework.cloud.zookeeper.discovery.ZookeeperServer; +import org.springframework.core.convert.converter.Converter; -public interface DiscoverableService { - /** - * Get the service properties. - */ - Map<String, Object> getServiceProperties(); +public final class ZookeeperServerToServiceDefinition implements Converter<ZookeeperServer, ServiceDefinition> { + + @Override + public ServiceDefinition convert(ZookeeperServer source) { + return new DefaultServiceDefinition( + source.getId(), + source.getHost(), + source.getPort(), + source.getInstance().getPayload().getMetadata() + ); + } } diff --git a/components/camel-spring-cloud-zookeeper/src/main/java/org/apache/camel/spring/cloud/zookeeper/CamelCloudZookeeperAutoConfiguration.java b/components/camel-spring-cloud-zookeeper/src/main/java/org/apache/camel/spring/cloud/zookeeper/ZookeeperToServiceDefinitionAutoConfiguration.java similarity index 65% rename from components/camel-spring-cloud-zookeeper/src/main/java/org/apache/camel/spring/cloud/zookeeper/CamelCloudZookeeperAutoConfiguration.java rename to components/camel-spring-cloud-zookeeper/src/main/java/org/apache/camel/spring/cloud/zookeeper/ZookeeperToServiceDefinitionAutoConfiguration.java index b223e02..535c9e5 100644 --- a/components/camel-spring-cloud-zookeeper/src/main/java/org/apache/camel/spring/cloud/zookeeper/CamelCloudZookeeperAutoConfiguration.java +++ b/components/camel-spring-cloud-zookeeper/src/main/java/org/apache/camel/spring/cloud/zookeeper/ZookeeperToServiceDefinitionAutoConfiguration.java @@ -17,29 +17,25 @@ package org.apache.camel.spring.cloud.zookeeper; import org.apache.camel.cloud.ServiceDefinition; -import org.apache.camel.spring.boot.cloud.CamelCloudConfigurationProperties; import org.apache.camel.spring.boot.util.GroupCondition; -import org.apache.camel.spring.cloud.CamelSpringCloudServiceRegistryAutoConfiguration; +import org.apache.camel.spring.cloud.CamelSpringCloudServiceLoadBalancerAutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigureBefore; -import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.zookeeper.ConditionalOnZookeeperEnabled; -import org.springframework.cloud.zookeeper.serviceregistry.ZookeeperRegistration; +import org.springframework.cloud.zookeeper.discovery.ZookeeperServer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.core.convert.converter.Converter; @Configuration -@AutoConfigureBefore(CamelSpringCloudServiceRegistryAutoConfiguration.class) +@AutoConfigureBefore(CamelSpringCloudServiceLoadBalancerAutoConfiguration.class) @ConditionalOnZookeeperEnabled -@Conditional(CamelCloudZookeeperAutoConfiguration.Condition.class) -@EnableConfigurationProperties(CamelCloudConfigurationProperties.class) -public class CamelCloudZookeeperAutoConfiguration { +@Conditional(ZookeeperToServiceDefinitionAutoConfiguration.Condition.class) +public class ZookeeperToServiceDefinitionAutoConfiguration { - @Bean(name = "service-definition-to-zookeeper-registration") - public Converter<ServiceDefinition, ZookeeperRegistration> serviceDefinitionToConsulRegistration( - CamelCloudConfigurationProperties properties) { - return new ServiceDefinitionToZookeeperRegistration(properties); + @Bean(name = "zookeeper-server-to-service-definition") + public Converter<ZookeeperServer, ServiceDefinition> zookeeperServerToServiceDefinition() { + return new ZookeeperServerToServiceDefinition(); } // ******************************* diff --git a/components/camel-spring-cloud-zookeeper/src/main/resources/META-INF/spring.factories b/components/camel-spring-cloud-zookeeper/src/main/resources/META-INF/spring.factories index 04d8a13..f6b9530 100644 --- a/components/camel-spring-cloud-zookeeper/src/main/resources/META-INF/spring.factories +++ b/components/camel-spring-cloud-zookeeper/src/main/resources/META-INF/spring.factories @@ -16,4 +16,5 @@ # org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ - org.apache.camel.spring.cloud.zookeeper.CamelCloudZookeeperAutoConfiguration \ No newline at end of file + org.apache.camel.spring.cloud.zookeeper.ServiceDefinitionToZookeeperRegistrationAutoConfiguration,\ + org.apache.camel.spring.cloud.zookeeper.ZookeeperToServiceDefinitionAutoConfiguration \ No newline at end of file diff --git a/components/camel-spring-cloud-zookeeper/src/test/java/org/apache/camel/spring/cloud/zookeeper/CamelCloudZookeeperAutoConfigurationTest.java b/components/camel-spring-cloud-zookeeper/src/test/java/org/apache/camel/spring/cloud/zookeeper/CamelCloudZookeeperAutoConfigurationTest.java index 205b5a9..9d28b93 100644 --- a/components/camel-spring-cloud-zookeeper/src/test/java/org/apache/camel/spring/cloud/zookeeper/CamelCloudZookeeperAutoConfigurationTest.java +++ b/components/camel-spring-cloud-zookeeper/src/test/java/org/apache/camel/spring/cloud/zookeeper/CamelCloudZookeeperAutoConfigurationTest.java @@ -73,6 +73,41 @@ public class CamelCloudZookeeperAutoConfigurationTest { } } + @Test + public void testZookeeperServerToServiceDefinition() throws Exception { + final ZookeeperServer server = new ZookeeperServer(temporaryFolder.newFolder(testName.getMethodName())); + + ConfigurableApplicationContext context = new SpringApplicationBuilder(TestConfiguration.class) + .web(WebApplicationType.NONE) + .run( + "--debug=false", + "--spring.main.banner-mode=OFF", + "--spring.application.name=" + UUID.randomUUID().toString(), + "--ribbon.enabled=false", + "--ribbon.eureka.enabled=false", + "--management.endpoint.enabled=false", + "--spring.cloud.zookeeper.enabled=true", + "--spring.cloud.zookeeper.connect-string=" + server.connectString(), + "--spring.cloud.zookeeper.config.enabled=false", + "--spring.cloud.zookeeper.discovery.enabled=true", + "--spring.cloud.service-registry.auto-registration.enabled=false" + ); + + try { + Map<String, Converter> converters = context.getBeansOfType(Converter.class); + + assertThat(converters).isNotNull(); + assertThat(converters.values().stream().anyMatch(ZookeeperServerToServiceDefinition.class::isInstance)).isTrue(); + } finally { + + // shutdown spring context + context.close(); + + // shutdown zookeeper + server.shutdown(); + } + } + // ************************************* // Config // ************************************* diff --git a/components/camel-spring-cloud-zookeeper/src/test/java/org/apache/camel/spring/cloud/zookeeper/CamelCloudZookeeperServiceRegistryTest.java b/components/camel-spring-cloud-zookeeper/src/test/java/org/apache/camel/spring/cloud/zookeeper/CamelCloudZookeeperServiceRegistryTest.java index 465dcd6..4c62084 100644 --- a/components/camel-spring-cloud-zookeeper/src/test/java/org/apache/camel/spring/cloud/zookeeper/CamelCloudZookeeperServiceRegistryTest.java +++ b/components/camel-spring-cloud-zookeeper/src/test/java/org/apache/camel/spring/cloud/zookeeper/CamelCloudZookeeperServiceRegistryTest.java @@ -69,7 +69,8 @@ public class CamelCloudZookeeperServiceRegistryTest { "--spring.cloud.zookeeper.connect-string=" + server.connectString(), "--spring.cloud.zookeeper.config.enabled=false", "--spring.cloud.zookeeper.discovery.enabled=true", - "--spring.cloud.service-registry.auto-registration.enabled=false" + "--spring.cloud.service-registry.auto-registration.enabled=false", + "--camel.cloud.service-registry.service-host=" + SERVICE_HOST ); try { diff --git a/components/camel-spring-cloud/src/main/java/org/apache/camel/spring/cloud/CamelSpringCloudServiceLoadBalancer.java b/components/camel-spring-cloud/src/main/java/org/apache/camel/spring/cloud/CamelSpringCloudServiceLoadBalancer.java index 50447f7..d1b6dd6 100644 --- a/components/camel-spring-cloud/src/main/java/org/apache/camel/spring/cloud/CamelSpringCloudServiceLoadBalancer.java +++ b/components/camel-spring-cloud/src/main/java/org/apache/camel/spring/cloud/CamelSpringCloudServiceLoadBalancer.java @@ -16,27 +16,28 @@ */ package org.apache.camel.spring.cloud; +import java.util.Optional; + import org.apache.camel.CamelContext; import org.apache.camel.CamelContextAware; -import org.apache.camel.cloud.ServiceDefinition; import org.apache.camel.cloud.ServiceLoadBalancer; import org.apache.camel.cloud.ServiceLoadBalancerFunction; -import org.apache.camel.impl.cloud.DefaultServiceDefinition; import org.apache.camel.support.ServiceSupport; import org.apache.camel.util.ObjectHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; public class CamelSpringCloudServiceLoadBalancer extends ServiceSupport implements CamelContextAware, ServiceLoadBalancer { private static final Logger LOGGER = LoggerFactory.getLogger(CamelSpringCloudServiceLoadBalancer.class); private final LoadBalancerClient loadBalancerClient; + private final ServiceLoadBalancer loadBalancer; private CamelContext camelContext; - public CamelSpringCloudServiceLoadBalancer(LoadBalancerClient loadBalancerClient) { + public CamelSpringCloudServiceLoadBalancer(LoadBalancerClient loadBalancerClient, Optional<LoadBalancerClientAdapter> clientAdapter) { this.loadBalancerClient = loadBalancerClient; + this.loadBalancer = clientAdapter.orElseGet(DefaultLoadBalancerClientAdapter::new).adapt(loadBalancerClient); } @Override @@ -63,19 +64,15 @@ public class CamelSpringCloudServiceLoadBalancer extends ServiceSupport implemen @Override public <T> T process(String serviceName, ServiceLoadBalancerFunction<T> function) throws Exception { - return loadBalancerClient.execute(serviceName, i -> function.apply(instanceToDefinition(i))); + return loadBalancer.process(serviceName, function); } // ******************************* - // Helpers + // // ******************************* - private ServiceDefinition instanceToDefinition(ServiceInstance instance) { - return new DefaultServiceDefinition( - instance.getServiceId(), - instance.getHost(), - instance.getPort(), - instance.getMetadata() - ); + @FunctionalInterface + public interface LoadBalancerClientAdapter { + ServiceLoadBalancer adapt(LoadBalancerClient client); } } \ No newline at end of file diff --git a/components/camel-spring-cloud/src/main/java/org/apache/camel/spring/cloud/CamelSpringCloudServiceLoadBalancerAutoConfiguration.java b/components/camel-spring-cloud/src/main/java/org/apache/camel/spring/cloud/CamelSpringCloudServiceLoadBalancerAutoConfiguration.java index eab3441..1406724 100644 --- a/components/camel-spring-cloud/src/main/java/org/apache/camel/spring/cloud/CamelSpringCloudServiceLoadBalancerAutoConfiguration.java +++ b/components/camel-spring-cloud/src/main/java/org/apache/camel/spring/cloud/CamelSpringCloudServiceLoadBalancerAutoConfiguration.java @@ -16,6 +16,8 @@ */ package org.apache.camel.spring.cloud; +import java.util.Optional; + import org.apache.camel.cloud.ServiceLoadBalancer; import org.apache.camel.spring.boot.cloud.CamelCloudAutoConfiguration; import org.apache.camel.spring.boot.cloud.CamelCloudConfigurationProperties; @@ -40,8 +42,11 @@ public class CamelSpringCloudServiceLoadBalancerAutoConfiguration { @Bean(name = "load-balancer") @ConditionalOnMissingBean - public ServiceLoadBalancer cloudLoadBalancer(LoadBalancerClient loadBalancerClient) { - return new CamelSpringCloudServiceLoadBalancer(loadBalancerClient); + public ServiceLoadBalancer cloudLoadBalancer( + LoadBalancerClient loadBalancerClient, + Optional<CamelSpringCloudServiceLoadBalancer.LoadBalancerClientAdapter> clientAdapter) { + + return new CamelSpringCloudServiceLoadBalancer(loadBalancerClient, clientAdapter); } // ******************************* diff --git a/components/camel-spring-cloud/src/main/java/org/apache/camel/spring/cloud/CamelSpringCloudServiceRegistry.java b/components/camel-spring-cloud/src/main/java/org/apache/camel/spring/cloud/CamelSpringCloudServiceRegistry.java index e376e08..f7674ac 100644 --- a/components/camel-spring-cloud/src/main/java/org/apache/camel/spring/cloud/CamelSpringCloudServiceRegistry.java +++ b/components/camel-spring-cloud/src/main/java/org/apache/camel/spring/cloud/CamelSpringCloudServiceRegistry.java @@ -47,16 +47,17 @@ public class CamelSpringCloudServiceRegistry extends AbstractServiceRegistry { @Override public void register(ServiceDefinition definition) { - Registration result = convertServiceDefinition(definition); - synchronized (this) { - LOGGER.debug("Register service with definition: {} with registrations: {}", definition, registrationType); - - serviceRegistry.register(result); - // keep track of registered definition to remove them upon registry // shutdown if (definitions.stream().noneMatch(d -> matchById(d, definition))) { + LOGGER.debug("Register service with definition: {} with registrations: {}", definition, registrationType); + + // compute registration from definition + Registration result = convertServiceDefinition(definition); + + serviceRegistry.register(result); + definitions.add(definition); } } @@ -64,12 +65,15 @@ public class CamelSpringCloudServiceRegistry extends AbstractServiceRegistry { @Override public void deregister(ServiceDefinition definition) { - Registration result = convertServiceDefinition(definition); - synchronized (this) { - LOGGER.debug("Deregister service with definition: {} with registrations: {}", definition, registrationType); + if (definitions.stream().noneMatch(d -> matchById(d, definition))) { + LOGGER.debug("Deregister service with definition: {} with registrations: {}", definition, registrationType); + + // compute registration from definition + Registration result = convertServiceDefinition(definition); - serviceRegistry.deregister(result); + serviceRegistry.deregister(result); + } // remove any instance with the same id definitions.removeIf(d -> matchById(d, definition)); @@ -82,8 +86,9 @@ public class CamelSpringCloudServiceRegistry extends AbstractServiceRegistry { @Override protected void doStop() throws Exception { - // TODO: need to be improved - new ArrayList<>(definitions).forEach(this::deregister); + synchronized (this) { + new ArrayList<>(definitions).forEach(this::deregister); + } } public ServiceRegistry getNativeServiceRegistry() { @@ -139,9 +144,11 @@ public class CamelSpringCloudServiceRegistry extends AbstractServiceRegistry { } private Registration convertServiceDefinition(ServiceDefinition definition) { - for (ConversionService conversionService: conversionServices) { - if (conversionService.canConvert(ServiceDefinition.class, registrationType)) { - return conversionService.convert(definition, registrationType); + for (int i = 0; i < conversionServices.size(); i++) { + ConversionService cs = conversionServices.get(i); + + if (cs.canConvert(ServiceDefinition.class, registrationType)) { + return cs.convert(definition, registrationType); } } diff --git a/camel-core/src/main/java/org/apache/camel/cloud/DiscoverableService.java b/components/camel-spring-cloud/src/main/java/org/apache/camel/spring/cloud/DefaultLoadBalancerClientAdapter.java similarity index 65% copy from camel-core/src/main/java/org/apache/camel/cloud/DiscoverableService.java copy to components/camel-spring-cloud/src/main/java/org/apache/camel/spring/cloud/DefaultLoadBalancerClientAdapter.java index 6d1946c..3ecb6d2 100644 --- a/camel-core/src/main/java/org/apache/camel/cloud/DiscoverableService.java +++ b/components/camel-spring-cloud/src/main/java/org/apache/camel/spring/cloud/DefaultLoadBalancerClientAdapter.java @@ -14,13 +14,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.cloud; +package org.apache.camel.spring.cloud; -import java.util.Map; +import org.apache.camel.cloud.ServiceLoadBalancer; +import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; -public interface DiscoverableService { - /** - * Get the service properties. - */ - Map<String, Object> getServiceProperties(); +public class DefaultLoadBalancerClientAdapter implements CamelSpringCloudServiceLoadBalancer.LoadBalancerClientAdapter { + @Override + public ServiceLoadBalancer adapt(LoadBalancerClient client) { + return new DefaultServiceLoadBalancer(client); + } } diff --git a/components/camel-spring-cloud/src/main/java/org/apache/camel/spring/cloud/DefaultServiceLoadBalancer.java b/components/camel-spring-cloud/src/main/java/org/apache/camel/spring/cloud/DefaultServiceLoadBalancer.java new file mode 100644 index 0000000..5ab886b --- /dev/null +++ b/components/camel-spring-cloud/src/main/java/org/apache/camel/spring/cloud/DefaultServiceLoadBalancer.java @@ -0,0 +1,50 @@ +/** + * 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.spring.cloud; + +import org.apache.camel.cloud.ServiceDefinition; +import org.apache.camel.cloud.ServiceLoadBalancer; +import org.apache.camel.cloud.ServiceLoadBalancerFunction; +import org.apache.camel.impl.cloud.DefaultServiceDefinition; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; + +public class DefaultServiceLoadBalancer implements ServiceLoadBalancer { + private final LoadBalancerClient client; + + public DefaultServiceLoadBalancer(LoadBalancerClient client) { + this.client = client; + } + + @Override + public <T> T process(String serviceName, ServiceLoadBalancerFunction<T> function) throws Exception { + return client.execute(serviceName, instance -> { + return function.apply( + convertServiceInstanceToServiceDefinition(instance) + ); + }); + } + + protected ServiceDefinition convertServiceInstanceToServiceDefinition(ServiceInstance instance) { + return new DefaultServiceDefinition( + instance.getServiceId(), + instance.getHost(), + instance.getPort(), + instance.getMetadata() + ); + } +} diff --git a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowEndpoint.java b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowEndpoint.java index bd6ffa8..1165137 100644 --- a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowEndpoint.java +++ b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowEndpoint.java @@ -142,9 +142,9 @@ public class UndertowEndpoint extends DefaultEndpoint implements AsyncEndpoint, //------------------------------------------------------------------------- @Override - public Map<String, Object> getServiceProperties() { + public Map<String, String> getServiceProperties() { return CollectionHelper.immutableMapOf( - ServiceDefinition.SERVICE_META_PORT, httpURI.getPort(), + ServiceDefinition.SERVICE_META_PORT, Integer.toString(httpURI.getPort()), ServiceDefinition.SERVICE_META_PATH, httpURI.getPath(), ServiceDefinition.SERVICE_META_PROTOCOL, httpURI.getScheme() ); diff --git a/examples/camel-example-spring-cloud-serviceregistry/consumer/pom.xml b/examples/camel-example-spring-cloud-serviceregistry/consumer/pom.xml index c0c293c..31188c5 100644 --- a/examples/camel-example-spring-cloud-serviceregistry/consumer/pom.xml +++ b/examples/camel-example-spring-cloud-serviceregistry/consumer/pom.xml @@ -103,6 +103,10 @@ </dependency> <dependency> <groupId>org.apache.camel</groupId> + <artifactId>camel-spring-cloud-netflix-starter</artifactId> + </dependency> + <dependency> + <groupId>org.apache.camel</groupId> <artifactId>camel-spring-cloud-consul-starter</artifactId> </dependency> <dependency> diff --git a/examples/camel-example-spring-cloud-serviceregistry/consumer/src/main/resources/application.properties b/examples/camel-example-spring-cloud-serviceregistry/consumer/src/main/resources/application.properties index 0eaa50e..cfd926a 100644 --- a/examples/camel-example-spring-cloud-serviceregistry/consumer/src/main/resources/application.properties +++ b/examples/camel-example-spring-cloud-serviceregistry/consumer/src/main/resources/application.properties @@ -41,12 +41,3 @@ camel.rest.binding-mode = auto # Camel Service Call camel.cloud.service-call.component = undertow -# this should not be needed but there is a bug or misbehavior -# on spring cloud netflix side that prevent ribbon load -# balancer to propagate metadata from i.e. consul, see: -# -# https://github.com/spring-cloud/spring-cloud-consul/issues/424 -# -camel.cloud.ribbon.load-balancer.enabled = false -camel.cloud.service-call.default-load-balancer = true -camel.cloud.service-call.service-chooser = roundrobin -- To stop receiving notification emails like this one, please contact lburgazz...@apache.org.