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 5314b540ab1b7add858a26a92c71911f0fe4539e
Author: lburgazzoli <lburgazz...@gmail.com>
AuthorDate: Mon May 14 14:49:37 2018 +0200

    CAMEL-12485: camel cloud : create camel-service component
---
 .../org/apache/camel/util/CollectionHelper.java    |  45 +++
 components/camel-consul/pom.xml                    |   5 +
 .../consul/cloud/ConsulServiceRegistry.java        |   9 +-
 .../ConsulServiceCallWithRegistrationTest.java     |   4 +-
 .../camel/http/common/HttpCommonEndpoint.java      |  12 +-
 .../camel/component/undertow/UndertowEndpoint.java |  17 +-
 components/camel-zookeeper/pom.xml                 |  10 +
 .../zookeeper/cloud/ZooKeeperServiceDiscovery.java |   5 +-
 .../cloud/ZooKeeperServiceDiscoveryFactory.java    |   4 -
 .../zookeeper/cloud/ZooKeeperServiceRegistry.java  | 394 +++++++++++++++++++++
 .../ZooKeeperServiceRegistryConfiguration.java     |  78 ++++
 .../cloud/ZooKeeperServiceDiscoveryTest.java       |   2 +-
 .../ZooKeeperServiceRegistrationTestBase.java      | 140 ++++++++
 ...RegistrationWithRoutePolicyAndMetadataTest.java |  40 +++
 ...viceRegistrationWithRoutePolicyFactoryTest.java |  46 +++
 ...eperServiceRegistrationWithRoutePolicyTest.java |  38 ++
 ...erviceRegistrationWithServiceComponentTest.java |  56 +++
 components/pom.xml                                 |   2 +-
 parent/pom.xml                                     |   2 +-
 .../camel-consul-starter/pom.xml                   |  76 ++++
 .../ConsulServiceDiscoveryAutoConfiguration.java   |   1 -
 .../ConsulServiceRegistryAutoConfiguration.java}   |  23 +-
 .../ConsulServiceRegistryConfiguration.java}       |  11 +-
 .../cluster/ConsulClusterServiceConfiguration.java |   2 +-
 .../src/main/resources/META-INF/spring.factories   |   9 +-
 .../cloud/ConsulServiceDiscoveryDisabledTest.java  |  64 ----
 .../cloud/ConsulServiceDiscoveryEnabledTest.java   |  65 ----
 .../cloud/ConsulServiceDiscoveryTest.java          |  63 ++++
 .../springboot/cloud/ConsulServiceRegistryIT.java  |  98 +++++
 .../cloud/support/ConsulContainerLogger.java       |  31 ++
 .../cloud/support/ConsulContainerSupport.java      |  46 +++
 .../cloud/support/ConsulContainerWaitStrategy.java |  48 +++
 .../src/test/resources/logback.xml                 |   1 +
 .../camel-zookeeper-starter/pom.xml                |   7 +
 ...ZooKeeperServiceRegistryAutoConfiguration.java} |  23 +-
 .../ZooKeeperServiceRegistryConfiguration.java}    |  11 +-
 .../ZooKeeperClusterServiceAutoConfiguration.java  |   2 +-
 .../ZooKeeperClusterServiceConfiguration.java      |   2 +-
 .../src/main/resources/META-INF/spring.factories   |   5 +-
 .../cloud/ZooKeeperServiceRegistryTest.java        | 264 ++++++++++++++
 .../resources/application.properties}              |   4 +-
 .../src/test/resources/logback.xml                 |   3 +-
 platforms/spring-boot/spring-boot-dm/pom.xml       |   1 +
 43 files changed, 1564 insertions(+), 205 deletions(-)

diff --git 
a/camel-core/src/main/java/org/apache/camel/util/CollectionHelper.java 
b/camel-core/src/main/java/org/apache/camel/util/CollectionHelper.java
index 168e5ad..283682d 100644
--- a/camel-core/src/main/java/org/apache/camel/util/CollectionHelper.java
+++ b/camel-core/src/main/java/org/apache/camel/util/CollectionHelper.java
@@ -28,6 +28,7 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.Supplier;
 
 import org.w3c.dom.NodeList;
 
@@ -170,4 +171,48 @@ public final class CollectionHelper {
             ? Collections.emptyMap()
             : Collections.unmodifiableMap(new HashMap<>(map));
     }
+
+
+    /**
+     * Build a map from varargs.
+     */
+    public static <K, V> Map<K, V> mapOf(Supplier<Map<K,V>> creator, K key, V 
value, Object... keyVals) {
+        Map<K, V> map = creator.get();
+        map.put(key, value);
+
+        for(int i = 0; i < keyVals.length; i += 2) {
+            map.put(
+                (K) keyVals[i],
+                (V) keyVals[i + 1]
+            );
+        }
+
+        return map;
+    }
+
+
+    /**
+     * Build an immutable map from varargs.
+     */
+    public static <K, V> Map<K, V> immutableMapOf(Supplier<Map<K,V>> creator, 
K key, V value, Object... keyVals) {
+        return Collections.unmodifiableMap(
+            mapOf(creator, key, value, keyVals)
+        );
+    }
+
+    /**
+     * Build a map from varargs.
+     */
+    public static <K, V> Map<K, V> mapOf(K key, V value, Object... keyVals) {
+        return mapOf(HashMap::new, key, value, keyVals);
+    }
+
+    /**
+     * Build an immutable map from varargs.
+     */
+    public static <K, V> Map<K, V> immutableMapOf(K key, V value, Object... 
keyVals) {
+        return Collections.unmodifiableMap(
+            mapOf(HashMap::new, key, value, keyVals)
+        );
+    }
 }
diff --git a/components/camel-consul/pom.xml b/components/camel-consul/pom.xml
index 4d735c7..e5807ec 100644
--- a/components/camel-consul/pom.xml
+++ b/components/camel-consul/pom.xml
@@ -71,6 +71,11 @@
     </dependency>
     <dependency>
       <groupId>org.apache.camel</groupId>
+      <artifactId>camel-undertow</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
       <artifactId>camel-master</artifactId>
       <scope>test</scope>
     </dependency>
diff --git 
a/components/camel-consul/src/main/java/org/apache/camel/component/consul/cloud/ConsulServiceRegistry.java
 
b/components/camel-consul/src/main/java/org/apache/camel/component/consul/cloud/ConsulServiceRegistry.java
index 2028936..9396207e 100644
--- 
a/components/camel-consul/src/main/java/org/apache/camel/component/consul/cloud/ConsulServiceRegistry.java
+++ 
b/components/camel-consul/src/main/java/org/apache/camel/component/consul/cloud/ConsulServiceRegistry.java
@@ -228,9 +228,9 @@ public class ConsulServiceRegistry extends 
AbstractServiceRegistry {
         }
     }
 
-    // *********************************************
-    //
-    // *********************************************
+    // ****************
+    // Registry
+    // ****************
 
     @Override
     public void register(ServiceDefinition definition) {
@@ -303,6 +303,9 @@ public class ConsulServiceRegistry extends 
AbstractServiceRegistry {
         }
 
         client.agentClient().deregister(definition.getId());
+
+        //remove the serviceId to the list of known server
+        serviceList.remove(definition.getId());
     }
 
     private String computeServiceHost(ServiceDefinition definition) {
diff --git 
a/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/ConsulServiceCallWithRegistrationTest.java
 
b/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/ConsulServiceCallWithRegistrationTest.java
index b0efaab..2bbd547 100644
--- 
a/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/ConsulServiceCallWithRegistrationTest.java
+++ 
b/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/ConsulServiceCallWithRegistrationTest.java
@@ -80,7 +80,7 @@ public class ConsulServiceCallWithRegistrationTest extends 
ConsulTestSupport {
                     .end()
                     .log("${body}");
 
-                fromF("jetty:http://%s:%d/service/path";, SERVICE_HOST, port)
+                fromF("undertow:http://%s:%d/service/path";, SERVICE_HOST, port)
                     .routeId(serviceId)
                     .routeGroup(serviceName)
                     .routePolicy(new ServiceRegistrationRoutePolicy())
@@ -116,7 +116,7 @@ public class ConsulServiceCallWithRegistrationTest extends 
ConsulTestSupport {
                     .end()
                     .log("${body}");
 
-                fromF("jetty:http://%s:%d/service/path";, SERVICE_HOST, port)
+                fromF("undertow:http://%s:%d/service/path";, SERVICE_HOST, port)
                     .routeId(serviceId)
                     .routeGroup(serviceName)
                     .routePolicy(new ServiceRegistrationRoutePolicy())
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 9e9e196..e7d465e 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
@@ -18,7 +18,6 @@ package org.apache.camel.http.common;
 
 import java.net.URI;
 import java.net.URISyntaxException;
-import java.util.HashMap;
 import java.util.Map;
 
 import org.apache.camel.cloud.DiscoverableService;
@@ -30,6 +29,7 @@ import org.apache.camel.spi.HeaderFilterStrategyAware;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.UriParam;
 import org.apache.camel.spi.UriPath;
+import org.apache.camel.util.CollectionHelper;
 
 public abstract class HttpCommonEndpoint extends DefaultEndpoint implements 
HeaderFilterStrategyAware, DiscoverableService {
 
@@ -202,11 +202,11 @@ public abstract class HttpCommonEndpoint extends 
DefaultEndpoint implements Head
 
     @Override
     public Map<String, Object> getServiceProperties() {
-        return new HashMap<String, Object>() {{
-            put(ServiceDefinition.SERVICE_META_PORT, getPort());
-            put(ServiceDefinition.SERVICE_META_PATH, getPath());
-            put(ServiceDefinition.SERVICE_META_PROTOCOL, getProtocol());
-        }};
+        return CollectionHelper.immutableMapOf(
+            ServiceDefinition.SERVICE_META_PORT, getPort(),
+            ServiceDefinition.SERVICE_META_PATH, getPath(),
+            ServiceDefinition.SERVICE_META_PROTOCOL, getProtocol()
+        );
     }
 
     // Properties
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 23c8caa..bd6ffa8 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
@@ -30,6 +30,8 @@ import org.apache.camel.Message;
 import org.apache.camel.PollingConsumer;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
+import org.apache.camel.cloud.DiscoverableService;
+import org.apache.camel.cloud.ServiceDefinition;
 import org.apache.camel.component.undertow.UndertowConstants.EventType;
 import org.apache.camel.component.undertow.handlers.CamelWebSocketHandler;
 import org.apache.camel.http.common.cookie.CookieHandler;
@@ -40,6 +42,7 @@ import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
 import org.apache.camel.spi.UriPath;
+import org.apache.camel.util.CollectionHelper;
 import org.apache.camel.util.jsse.SSLContextParameters;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -52,7 +55,7 @@ import org.xnio.Options;
  */
 @UriEndpoint(firstVersion = "2.16.0", scheme = "undertow", title = "Undertow", 
syntax = "undertow:httpURI",
         consumerClass = UndertowConsumer.class, label = "http,websocket", 
lenientProperties = true)
-public class UndertowEndpoint extends DefaultEndpoint implements 
AsyncEndpoint, HeaderFilterStrategyAware {
+public class UndertowEndpoint extends DefaultEndpoint implements 
AsyncEndpoint, HeaderFilterStrategyAware, DiscoverableService {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(UndertowEndpoint.class);
     private UndertowComponent component;
@@ -135,6 +138,18 @@ public class UndertowEndpoint extends DefaultEndpoint 
implements AsyncEndpoint,
         return true;
     }
 
+    // Service Registration
+    //-------------------------------------------------------------------------
+
+    @Override
+    public Map<String, Object> getServiceProperties() {
+        return CollectionHelper.immutableMapOf(
+            ServiceDefinition.SERVICE_META_PORT, httpURI.getPort(),
+            ServiceDefinition.SERVICE_META_PATH, httpURI.getPath(),
+            ServiceDefinition.SERVICE_META_PROTOCOL, httpURI.getScheme()
+        );
+    }
+
     public Exchange createExchange(HttpServerExchange httpExchange) throws 
Exception {
         Exchange exchange = createExchange(ExchangePattern.InOut);
 
diff --git a/components/camel-zookeeper/pom.xml 
b/components/camel-zookeeper/pom.xml
index 0aaaedc..31b04ee 100644
--- a/components/camel-zookeeper/pom.xml
+++ b/components/camel-zookeeper/pom.xml
@@ -99,11 +99,21 @@
     </dependency>
     <dependency>
       <groupId>org.apache.camel</groupId>
+      <artifactId>camel-undertow</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
       <artifactId>camel-master</artifactId>
       <scope>test</scope>
     </dependency>
     <dependency>
       <groupId>org.apache.camel</groupId>
+      <artifactId>camel-service</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
       <artifactId>camel-test-spring</artifactId>
       <scope>test</scope>
     </dependency>  
diff --git 
a/components/camel-zookeeper/src/main/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceDiscovery.java
 
b/components/camel-zookeeper/src/main/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceDiscovery.java
index 3a7dde9..a46ce09 100644
--- 
a/components/camel-zookeeper/src/main/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceDiscovery.java
+++ 
b/components/camel-zookeeper/src/main/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceDiscovery.java
@@ -118,9 +118,8 @@ public class ZooKeeperServiceDiscovery extends 
DefaultServiceDiscovery {
                     Map<String, String> meta = new HashMap<>();
                     ObjectHelper.ifNotEmpty(si.getPayload(), meta::putAll);
 
-                    meta.put("service_name", si.getName());
-                    meta.put("service_id", si.getId());
-                    meta.put("service_type", si.getServiceType().name());
+                    meta.putIfAbsent(ServiceDefinition.SERVICE_META_NAME, 
si.getName());
+                    meta.putIfAbsent(ServiceDefinition.SERVICE_META_ID, 
si.getId());
 
                     return new DefaultServiceDefinition(
                         si.getName(),
diff --git 
a/components/camel-zookeeper/src/main/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceDiscoveryFactory.java
 
b/components/camel-zookeeper/src/main/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceDiscoveryFactory.java
index b3b0604..25c29f9 100644
--- 
a/components/camel-zookeeper/src/main/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceDiscoveryFactory.java
+++ 
b/components/camel-zookeeper/src/main/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceDiscoveryFactory.java
@@ -167,10 +167,6 @@ public class ZooKeeperServiceDiscoveryFactory implements 
ServiceDiscoveryFactory
         configuration.setConnectionTimeoutUnit(connectionTimeoutUnit);
     }
 
-    public ZooKeeperCuratorConfiguration copy() {
-        return configuration.copy();
-    }
-
     public List<AuthInfo> getAuthInfoList() {
         return configuration.getAuthInfoList();
     }
diff --git 
a/components/camel-zookeeper/src/main/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceRegistry.java
 
b/components/camel-zookeeper/src/main/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceRegistry.java
new file mode 100644
index 0000000..89fb08d
--- /dev/null
+++ 
b/components/camel-zookeeper/src/main/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceRegistry.java
@@ -0,0 +1,394 @@
+/**
+ * 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.component.zookeeper.cloud;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.camel.cloud.ServiceDefinition;
+import org.apache.camel.component.zookeeper.ZooKeeperCuratorHelper;
+import org.apache.camel.impl.cloud.AbstractServiceRegistry;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.curator.RetryPolicy;
+import org.apache.curator.framework.AuthInfo;
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.x.discovery.ServiceDiscovery;
+import org.apache.curator.x.discovery.ServiceInstance;
+import org.codehaus.jackson.map.annotate.JsonRootName;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ZooKeeperServiceRegistry extends AbstractServiceRegistry {
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(ZooKeeperServiceRegistry.class);
+
+    private final Set<String> serviceList;
+    private final boolean managedInstance;
+    private ZooKeeperServiceRegistryConfiguration configuration;
+    private CuratorFramework curator;
+    private ServiceDiscovery<MetaData> serviceDiscovery;
+
+    public ZooKeeperServiceRegistry() {
+        this.serviceList =  ConcurrentHashMap.newKeySet();
+        this.configuration = new ZooKeeperServiceRegistryConfiguration();
+        this.curator = configuration.getCuratorFramework();
+        this.managedInstance = Objects.isNull(curator);
+    }
+
+    public ZooKeeperServiceRegistry(ZooKeeperServiceRegistryConfiguration 
configuration) {
+        this.serviceList =  ConcurrentHashMap.newKeySet();
+        this.configuration = configuration.copy();
+        this.curator = configuration.getCuratorFramework();
+        this.managedInstance = Objects.isNull(curator);
+    }
+
+    // ****************
+    // Properties
+    // ****************
+
+    public ZooKeeperServiceRegistryConfiguration getConfiguration() {
+        return configuration;
+    }
+
+    public void setConfiguration(ZooKeeperServiceRegistryConfiguration 
configuration) {
+        this.configuration = configuration.copy();
+    }
+
+    public CuratorFramework getCuratorFramework() {
+        return configuration.getCuratorFramework();
+    }
+
+    public void setCuratorFramework(CuratorFramework curatorFramework) {
+        configuration.setCuratorFramework(curatorFramework);
+    }
+
+    public List<String> getNodes() {
+        return configuration.getNodes();
+    }
+
+    public void setNodes(String nodes) {
+        configuration.setNodes(nodes);
+    }
+
+    public void setNodes(List<String> nodes) {
+        configuration.setNodes(nodes);
+    }
+
+    public String getNamespace() {
+        return configuration.getNamespace();
+    }
+
+    public void setNamespace(String namespace) {
+        configuration.setNamespace(namespace);
+    }
+
+    public long getReconnectBaseSleepTime() {
+        return configuration.getReconnectBaseSleepTime();
+    }
+
+    public void setReconnectBaseSleepTime(long reconnectBaseSleepTime) {
+        configuration.setReconnectBaseSleepTime(reconnectBaseSleepTime);
+    }
+
+    public void setReconnectBaseSleepTime(long reconnectBaseSleepTime, 
TimeUnit reconnectBaseSleepTimeUnit) {
+        configuration.setReconnectBaseSleepTime(reconnectBaseSleepTime, 
reconnectBaseSleepTimeUnit);
+    }
+
+    public TimeUnit getReconnectBaseSleepTimeUnit() {
+        return configuration.getReconnectBaseSleepTimeUnit();
+    }
+
+    public void setReconnectBaseSleepTimeUnit(TimeUnit 
reconnectBaseSleepTimeUnit) {
+        
configuration.setReconnectBaseSleepTimeUnit(reconnectBaseSleepTimeUnit);
+    }
+
+    public long getReconnectMaxSleepTime() {
+        return configuration.getReconnectMaxSleepTime();
+    }
+
+    public void setReconnectMaxSleepTime(long reconnectMaxSleepTime) {
+        configuration.setReconnectMaxSleepTime(reconnectMaxSleepTime);
+    }
+
+    public void setReconnectMaxSleepTime(long reconnectMaxSleepTime, TimeUnit 
reconnectBaseSleepTimeUnit) {
+        configuration.setReconnectMaxSleepTime(reconnectMaxSleepTime, 
reconnectBaseSleepTimeUnit);
+    }
+
+    public TimeUnit getReconnectMaxSleepTimeUnit() {
+        return configuration.getReconnectMaxSleepTimeUnit();
+    }
+
+    public void setReconnectMaxSleepTimeUnit(TimeUnit 
reconnectMaxSleepTimeUnit) {
+        configuration.setReconnectMaxSleepTimeUnit(reconnectMaxSleepTimeUnit);
+    }
+
+    public int getReconnectMaxRetries() {
+        return configuration.getReconnectMaxRetries();
+    }
+
+    public void setReconnectMaxRetries(int reconnectMaxRetries) {
+        configuration.setReconnectMaxRetries(reconnectMaxRetries);
+    }
+
+    public long getSessionTimeout() {
+        return configuration.getSessionTimeout();
+    }
+
+    public void setSessionTimeout(long sessionTimeout) {
+        configuration.setSessionTimeout(sessionTimeout);
+    }
+
+    public void setSessionTimeout(long sessionTimeout, TimeUnit 
sessionTimeoutUnit) {
+        configuration.setSessionTimeout(sessionTimeout, sessionTimeoutUnit);
+    }
+
+    public TimeUnit getSessionTimeoutUnit() {
+        return configuration.getSessionTimeoutUnit();
+    }
+
+    public void setSessionTimeoutUnit(TimeUnit sessionTimeoutUnit) {
+        configuration.setSessionTimeoutUnit(sessionTimeoutUnit);
+    }
+
+    public long getConnectionTimeout() {
+        return configuration.getConnectionTimeout();
+    }
+
+    public void setConnectionTimeout(long connectionTimeout) {
+        configuration.setConnectionTimeout(connectionTimeout);
+    }
+
+    public void setConnectionTimeout(long connectionTimeout, TimeUnit 
connectionTimeotUnit) {
+        configuration.setConnectionTimeout(connectionTimeout, 
connectionTimeotUnit);
+    }
+
+    public TimeUnit getConnectionTimeoutUnit() {
+        return configuration.getConnectionTimeoutUnit();
+    }
+
+    public void setConnectionTimeoutUnit(TimeUnit connectionTimeoutUnit) {
+        configuration.setConnectionTimeoutUnit(connectionTimeoutUnit);
+    }
+
+    public List<AuthInfo> getAuthInfoList() {
+        return configuration.getAuthInfoList();
+    }
+
+    public void setAuthInfoList(List<AuthInfo> authInfoList) {
+        configuration.setAuthInfoList(authInfoList);
+    }
+
+    public long getMaxCloseWait() {
+        return configuration.getMaxCloseWait();
+    }
+
+    public void setMaxCloseWait(long maxCloseWait) {
+        configuration.setMaxCloseWait(maxCloseWait);
+    }
+
+    public TimeUnit getMaxCloseWaitUnit() {
+        return configuration.getMaxCloseWaitUnit();
+    }
+
+    public void setMaxCloseWaitUnit(TimeUnit maxCloseWaitUnit) {
+        configuration.setMaxCloseWaitUnit(maxCloseWaitUnit);
+    }
+
+    public RetryPolicy getRetryPolicy() {
+        return configuration.getRetryPolicy();
+    }
+
+    public void setRetryPolicy(RetryPolicy retryPolicy) {
+        configuration.setRetryPolicy(retryPolicy);
+    }
+
+    public String getBasePath() {
+        return configuration.getBasePath();
+    }
+
+    public void setBasePath(String basePath) {
+        configuration.setBasePath(basePath);
+    }
+
+    public boolean isDeregisterServicesOnStop() {
+        return configuration.isDeregisterServicesOnStop();
+    }
+
+    public void setDeregisterServicesOnStop(boolean deregisterServicesOnStop) {
+        configuration.setDeregisterServicesOnStop(deregisterServicesOnStop);
+    }
+
+    public boolean isOverrideServiceHost() {
+        return configuration.isOverrideServiceHost();
+    }
+
+    public void setOverrideServiceHost(boolean overrideServiceHost) {
+        configuration.setOverrideServiceHost(overrideServiceHost);
+    }
+
+    public String getServiceHost() {
+        return configuration.getServiceHost();
+    }
+
+    public void setServiceHost(String serviceHost) {
+        configuration.setServiceHost(serviceHost);
+    }
+
+    // ****************
+    // Lifecycle
+    // ****************
+
+    @Override
+    protected void doStart() throws Exception {
+        if (curator == null) {
+            // Validation
+            ObjectHelper.notNull(getCamelContext(), "Camel Context");
+            ObjectHelper.notNull(configuration.getBasePath(), "ZooKeeper base 
path");
+
+            LOGGER.debug("Starting ZooKeeper Curator with namespace '{}', 
nodes: '{}'",
+                configuration.getNamespace(),
+                String.join(",", configuration.getNodes())
+            );
+
+            curator = ZooKeeperCuratorHelper.createCurator(configuration);
+            curator.start();
+        }
+
+        if (serviceDiscovery == null) {
+            // Validation
+            ObjectHelper.notNull(configuration.getBasePath(), "ZooKeeper base 
path");
+
+            LOGGER.debug("Starting ZooKeeper ServiceDiscoveryBuilder with base 
path '{}'",
+                configuration.getBasePath()
+            );
+
+            serviceDiscovery = 
ZooKeeperCuratorHelper.createServiceDiscovery(configuration, curator, 
MetaData.class);
+            serviceDiscovery.start();
+        }
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        if (serviceDiscovery != null) {
+            try {
+                if (configuration.isDeregisterServicesOnStop()) {
+                    for (String serviceName: serviceDiscovery.queryForNames()) 
{
+                        for (ServiceInstance<MetaData> serviceInstance: 
serviceDiscovery.queryForInstances(serviceName)) {
+                            if (serviceList.contains(serviceInstance.getId())) 
{
+                                
serviceDiscovery.unregisterService(serviceInstance);
+
+                                // remove the serviceId to the list of known 
server
+                                serviceList.remove(serviceInstance.getId());
+                            }
+                        }
+                    }
+                }
+
+                serviceDiscovery.close();
+            } catch (Exception e) {
+                LOGGER.warn("Error closing Curator ServiceDiscovery", e);
+            }
+        }
+
+        if (curator != null && managedInstance) {
+            curator.close();
+        }
+    }
+
+    // ****************
+    // Registry
+    // ****************
+
+    @Override
+    public void register(ServiceDefinition definition) {
+        if (definition.getId() == null) {
+            throw new IllegalArgumentException("Service ID must be defined 
(definition=" + definition + ")");
+        }
+        if (definition.getName() == null) {
+            throw new IllegalArgumentException("Service Name must be defined 
(definition=" + definition + ")");
+        }
+
+        try {
+            ServiceInstance<MetaData> instance = 
ServiceInstance.<MetaData>builder()
+                .address(computeServiceHost(definition))
+                .port(definition.getPort())
+                .name(definition.getName())
+                .id(definition.getId())
+                .payload(new MetaData(definition.getMetadata()))
+                .build();
+
+            serviceDiscovery.registerService(instance);
+
+            // add the serviceId to the list of known server
+            serviceList.add(definition.getId());
+        } catch (Exception e) {
+            LOGGER.warn("", e);
+        }
+    }
+
+    @Override
+    public void deregister(ServiceDefinition definition) {
+        if (definition.getId() == null) {
+            throw new IllegalArgumentException("Service ID must be defined 
(definition=" + definition + ")");
+        }
+        if (definition.getName() == null) {
+            throw new IllegalArgumentException("Service Name must be defined 
(definition=" + definition + ")");
+        }
+
+        try {
+            for (ServiceInstance<MetaData> serviceInstance: 
serviceDiscovery.queryForInstances(definition.getName())) {
+                if (Objects.equals(serviceInstance.getId(), 
definition.getId())) {
+                    serviceDiscovery.unregisterService(serviceInstance);
+
+                    // remove the serviceId to the list of known server
+                    serviceList.remove((serviceInstance.getId()));
+                }
+            }
+        } catch (Exception e) {
+            LOGGER.warn("", e);
+        }
+    }
+
+    // *********************************************
+    // Helpers
+    // *********************************************
+
+
+    private String computeServiceHost(ServiceDefinition definition) {
+        String host = definition.getHost();
+
+        if (configuration.isOverrideServiceHost() && 
configuration.getServiceHost() != null) {
+            host = configuration.getServiceHost();
+        }
+
+        return ObjectHelper.notNull(host, "service host");
+    }
+
+    @JsonRootName("meta")
+    public static final class MetaData extends HashMap<String, String> {
+        public MetaData() {
+        }
+
+        public MetaData(Map<? extends String, ? extends String> meta) {
+            super(meta);
+        }
+    }
+}
diff --git 
a/components/camel-zookeeper/src/main/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceRegistryConfiguration.java
 
b/components/camel-zookeeper/src/main/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceRegistryConfiguration.java
new file mode 100644
index 0000000..fd4d6aa
--- /dev/null
+++ 
b/components/camel-zookeeper/src/main/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceRegistryConfiguration.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.component.zookeeper.cloud;
+
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.component.zookeeper.ZooKeeperCuratorConfiguration;
+
+public class ZooKeeperServiceRegistryConfiguration extends 
ZooKeeperCuratorConfiguration {
+    /**
+     * Should we remove all the registered services know by this registry on 
stop?
+     */
+    private boolean deregisterServicesOnStop = true;
+
+    /**
+     * Should we override the service host if given ?
+     */
+    private boolean overrideServiceHost = true;
+
+    /**
+     * Service host.
+     */
+    private String serviceHost;
+
+    // ***********************************************
+    // Properties
+    // ***********************************************
+
+    public boolean isDeregisterServicesOnStop() {
+        return deregisterServicesOnStop;
+    }
+
+    public void setDeregisterServicesOnStop(boolean deregisterServicesOnStop) {
+        this.deregisterServicesOnStop = deregisterServicesOnStop;
+    }
+
+    public boolean isOverrideServiceHost() {
+        return overrideServiceHost;
+    }
+
+    public void setOverrideServiceHost(boolean overrideServiceHost) {
+        this.overrideServiceHost = overrideServiceHost;
+    }
+
+    public String getServiceHost() {
+        return serviceHost;
+    }
+
+    public void setServiceHost(String serviceHost) {
+        this.serviceHost = serviceHost;
+    }
+
+    // ***********************************************
+    //
+    // ***********************************************
+
+    @Override
+    public ZooKeeperServiceRegistryConfiguration copy() {
+        try {
+            return (ZooKeeperServiceRegistryConfiguration)super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new RuntimeCamelException(e);
+        }
+    }
+}
diff --git 
a/components/camel-zookeeper/src/test/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceDiscoveryTest.java
 
b/components/camel-zookeeper/src/test/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceDiscoveryTest.java
index e6d5551..82eca2d 100644
--- 
a/components/camel-zookeeper/src/test/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceDiscoveryTest.java
+++ 
b/components/camel-zookeeper/src/test/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceDiscoveryTest.java
@@ -92,7 +92,7 @@ public class ZooKeeperServiceDiscoveryTest {
                             i ->  {
                                 return i.getPort() == service.getPort()
                                     && i.getAddress().equals(service.getHost())
-                                    && 
i.getId().equals(service.getMetadata().get("service_id"))
+                                    && 
i.getId().equals(service.getMetadata().get(ServiceDefinition.SERVICE_META_ID))
                                     && i.getName().equals(service.getName());
                             }
                         ).count()
diff --git 
a/components/camel-zookeeper/src/test/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceRegistrationTestBase.java
 
b/components/camel-zookeeper/src/test/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceRegistrationTestBase.java
new file mode 100644
index 0000000..99b08a1
--- /dev/null
+++ 
b/components/camel-zookeeper/src/test/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceRegistrationTestBase.java
@@ -0,0 +1,140 @@
+/**
+ * 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.component.zookeeper.cloud;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.cloud.ServiceDefinition;
+import org.apache.camel.component.zookeeper.ZooKeeperTestSupport;
+import org.apache.camel.test.AvailablePortFinder;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.CuratorFrameworkFactory;
+import org.apache.curator.retry.ExponentialBackoffRetry;
+import org.apache.curator.utils.CloseableUtils;
+import org.apache.curator.x.discovery.ServiceDiscovery;
+import org.apache.curator.x.discovery.ServiceDiscoveryBuilder;
+import org.apache.curator.x.discovery.ServiceInstance;
+import org.apache.curator.x.discovery.details.JsonInstanceSerializer;
+import org.junit.Test;
+
+public abstract class ZooKeeperServiceRegistrationTestBase extends 
CamelTestSupport {
+    protected final static String SERVICE_ID = UUID.randomUUID().toString();
+    protected final static String SERVICE_NAME = "my-service";
+    protected final static String SERVICE_HOST = "localhost";
+    protected static final String SERVICE_PATH = "/camel";
+    protected final static int SERVICE_PORT = 
AvailablePortFinder.getNextAvailable();
+    protected final static int SERVER_PORT = 
AvailablePortFinder.getNextAvailable();
+
+    protected ZooKeeperTestSupport.TestZookeeperServer server;
+    protected CuratorFramework curator;
+    protected ServiceDiscovery<ZooKeeperServiceRegistry.MetaData> discovery;
+
+    // ***********************
+    // Lifecycle
+    // ***********************
+
+    @Override
+    protected void doPreSetup() throws Exception {
+        super.doPreSetup();
+
+        server = new ZooKeeperTestSupport.TestZookeeperServer(SERVER_PORT, 
true);
+        ZooKeeperTestSupport.waitForServerUp("127.0.0.1:" + SERVER_PORT, 1000);
+
+        curator = CuratorFrameworkFactory.builder()
+            .connectString("127.0.0.1:" + SERVER_PORT)
+            .retryPolicy(new ExponentialBackoffRetry(1000, 3))
+            .build();
+
+        discovery = 
ServiceDiscoveryBuilder.builder(ZooKeeperServiceRegistry.MetaData.class)
+            .client(curator)
+            .basePath(SERVICE_PATH)
+            .serializer(new 
JsonInstanceSerializer<>(ZooKeeperServiceRegistry.MetaData.class))
+            .build();
+
+        curator.start();
+        discovery.start();
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        super.tearDown();
+
+        CloseableUtils.closeQuietly(discovery);
+        CloseableUtils.closeQuietly(curator);
+
+        server.shutdown();
+    }
+
+
+    protected Map<String, String> getMetadata() {
+        return Collections.emptyMap();
+    }
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        final CamelContext context = super.createCamelContext();
+
+        ZooKeeperServiceRegistry registry = new ZooKeeperServiceRegistry();
+        registry.setId(context.getUuidGenerator().generateUuid());
+        registry.setCamelContext(context());
+        registry.setNodes("localhost:" + SERVER_PORT);
+        registry.setBasePath(SERVICE_PATH);
+        registry.setServiceHost(SERVICE_HOST);
+        registry.setOverrideServiceHost(true);
+
+        context.addService(registry, true, false);
+
+        return context;
+    }
+
+    @Test
+    public void testRegistrationFromRoute() throws Exception {
+
+        // the service should not be registered as the route is not running
+        assertTrue(discovery.queryForInstances(SERVICE_NAME).isEmpty());
+
+        // let start the route
+        context().startRoute(SERVICE_ID);
+
+        // check that service has been registered
+        Collection<ServiceInstance<ZooKeeperServiceRegistry.MetaData>> 
services = discovery.queryForInstances(SERVICE_NAME);
+        assertEquals(1, services.size());
+
+        ServiceInstance<ZooKeeperServiceRegistry.MetaData> instance = 
services.iterator().next();
+        assertEquals(SERVICE_PORT, (int)instance.getPort());
+        assertEquals("localhost", instance.getAddress());
+        assertEquals("http", 
instance.getPayload().get(ServiceDefinition.SERVICE_META_PROTOCOL));
+        assertEquals("/service/endpoint", 
instance.getPayload().get(ServiceDefinition.SERVICE_META_PATH));
+
+        getMetadata().forEach(
+            (k, v) -> {
+                assertEquals(v, instance.getPayload().get(k));
+            }
+        );
+
+        // let stop the route
+        context().stopRoute(SERVICE_ID);
+
+        // the service should be removed once the route is stopped
+        assertTrue(discovery.queryForInstances(SERVICE_NAME).isEmpty());
+    }
+}
diff --git 
a/components/camel-zookeeper/src/test/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceRegistrationWithRoutePolicyAndMetadataTest.java
 
b/components/camel-zookeeper/src/test/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceRegistrationWithRoutePolicyAndMetadataTest.java
new file mode 100644
index 0000000..f7d7dc6
--- /dev/null
+++ 
b/components/camel-zookeeper/src/test/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceRegistrationWithRoutePolicyAndMetadataTest.java
@@ -0,0 +1,40 @@
+/**
+ * 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.component.zookeeper.cloud;
+
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.cloud.ServiceDefinition;
+import org.apache.camel.impl.cloud.ServiceRegistrationRoutePolicy;
+
+public class ZooKeeperServiceRegistrationWithRoutePolicyAndMetadataTest 
extends ZooKeeperServiceRegistrationTestBase {
+    @Override
+    protected RoutesBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                fromF("jetty:http://0.0.0.0:%d/service/endpoint";, SERVICE_PORT)
+                    .routeId(SERVICE_ID)
+                    .routeProperty(ServiceDefinition.SERVICE_META_ID, 
SERVICE_ID)
+                    .routeProperty(ServiceDefinition.SERVICE_META_NAME, 
SERVICE_NAME)
+                    .routePolicy(new ServiceRegistrationRoutePolicy())
+                    .noAutoStartup()
+                    .to("log:service-registry?level=INFO");
+            }
+        };
+    }
+}
diff --git 
a/components/camel-zookeeper/src/test/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceRegistrationWithRoutePolicyFactoryTest.java
 
b/components/camel-zookeeper/src/test/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceRegistrationWithRoutePolicyFactoryTest.java
new file mode 100644
index 0000000..6e90224
--- /dev/null
+++ 
b/components/camel-zookeeper/src/test/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceRegistrationWithRoutePolicyFactoryTest.java
@@ -0,0 +1,46 @@
+/**
+ * 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.component.zookeeper.cloud;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.impl.cloud.ServiceRegistrationRoutePolicyFactory;
+
+public class ZooKeeperServiceRegistrationWithRoutePolicyFactoryTest extends 
ZooKeeperServiceRegistrationTestBase {
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        CamelContext context = super.createCamelContext();
+        context.addRoutePolicyFactory(new 
ServiceRegistrationRoutePolicyFactory());
+
+        return context;
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                fromF("jetty:http://0.0.0.0:%d/service/endpoint";, SERVICE_PORT)
+                    .routeId(SERVICE_ID)
+                    .routeGroup(SERVICE_NAME)
+                    .noAutoStartup()
+                    .to("log:service-registry?level=INFO");
+            }
+        };
+    }
+}
diff --git 
a/components/camel-zookeeper/src/test/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceRegistrationWithRoutePolicyTest.java
 
b/components/camel-zookeeper/src/test/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceRegistrationWithRoutePolicyTest.java
new file mode 100644
index 0000000..aa52d94
--- /dev/null
+++ 
b/components/camel-zookeeper/src/test/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceRegistrationWithRoutePolicyTest.java
@@ -0,0 +1,38 @@
+/**
+ * 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.component.zookeeper.cloud;
+
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.impl.cloud.ServiceRegistrationRoutePolicy;
+
+public class ZooKeeperServiceRegistrationWithRoutePolicyTest extends 
ZooKeeperServiceRegistrationTestBase {
+    @Override
+    protected RoutesBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                fromF("jetty:http://0.0.0.0:%d/service/endpoint";, SERVICE_PORT)
+                    .routeId(SERVICE_ID)
+                    .routeGroup(SERVICE_NAME)
+                    .routePolicy(new ServiceRegistrationRoutePolicy())
+                    .noAutoStartup()
+                    .to("log:service-registry?level=INFO");
+            }
+        };
+    }
+}
diff --git 
a/components/camel-zookeeper/src/test/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceRegistrationWithServiceComponentTest.java
 
b/components/camel-zookeeper/src/test/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceRegistrationWithServiceComponentTest.java
new file mode 100644
index 0000000..23d70b7
--- /dev/null
+++ 
b/components/camel-zookeeper/src/test/java/org/apache/camel/component/zookeeper/cloud/ZooKeeperServiceRegistrationWithServiceComponentTest.java
@@ -0,0 +1,56 @@
+/**
+ * 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.component.zookeeper.cloud;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.service.ServiceComponent;
+import org.apache.camel.impl.JndiRegistry;
+
+public class ZooKeeperServiceRegistrationWithServiceComponentTest extends 
ZooKeeperServiceRegistrationTestBase {
+
+    protected Map<String, String> getMetadata() {
+        return new HashMap<String, String>() {{
+            put("service.type", "zookeeper");
+        }};
+    }
+
+    @Override
+    protected JndiRegistry createRegistry() throws Exception {
+        JndiRegistry registry = super.createRegistry();
+        registry.bind("service", new ServiceComponent());
+
+        return registry;
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                
fromF("service:%s:jetty:http://0.0.0.0:%d/service/endpoint?service.type=zookeeper";,
 SERVICE_NAME, SERVICE_PORT)
+                    .routeId(SERVICE_ID)
+                    .routeGroup(SERVICE_NAME)
+                    .noAutoStartup()
+                    .to("log:service-registry?level=INFO");
+            }
+        };
+    }
+}
diff --git a/components/pom.xml b/components/pom.xml
index 8651841..f52a668 100644
--- a/components/pom.xml
+++ b/components/pom.xml
@@ -56,6 +56,7 @@
     <module>camel-jetty-common</module>
     <module>camel-jetty</module>
     <module>camel-jetty9</module>
+    <module>camel-undertow</module>
     <module>camel-cxf</module>
     <module>camel-cxf-transport</module>
     <module>camel-jms</module>
@@ -302,7 +303,6 @@
     <module>camel-thrift</module>
     <module>camel-twilio</module>
     <module>camel-twitter</module>
-    <module>camel-undertow</module>
     <module>camel-univocity-parsers</module>
     <module>camel-urlrewrite</module>
     <module>camel-velocity</module>
diff --git a/parent/pom.xml b/parent/pom.xml
index 0d00ad6..0d56081 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -680,7 +680,7 @@
     <stringtemplate-version>4.0.8</stringtemplate-version>
     <tagsoup-bundle-version>1.2.1_1</tagsoup-bundle-version>
     <tagsoup-version>1.2.1</tagsoup-version>
-    <testcontainers-version>1.7.2</testcontainers-version>
+    <testcontainers-version>1.7.3</testcontainers-version>
     <testng-version>6.14.2</testng-version>
     <tinybundles-version>2.1.1</tinybundles-version>
     <tika-version>1.18</tika-version>
diff --git 
a/platforms/spring-boot/components-starter/camel-consul-starter/pom.xml 
b/platforms/spring-boot/components-starter/camel-consul-starter/pom.xml
index 476c55b..f878775 100644
--- a/platforms/spring-boot/components-starter/camel-consul-starter/pom.xml
+++ b/platforms/spring-boot/components-starter/camel-consul-starter/pom.xml
@@ -39,6 +39,20 @@
       <artifactId>camel-consul</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <!-- testing -->
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-jetty</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <!-- testing (docker) -->
+    <dependency>
+      <groupId>org.testcontainers</groupId>
+      <artifactId>testcontainers</artifactId>
+      <version>${testcontainers-version}</version>
+      <scope>test</scope>
+    </dependency>
     <!--START OF GENERATED CODE-->
     <dependency>
       <groupId>org.apache.camel</groupId>
@@ -50,4 +64,66 @@
     </dependency>
     <!--END OF GENERATED CODE-->
   </dependencies>
+  <profiles>
+    <!-- activate integration test if the docker socket file is accessible -->
+    <profile>
+      <id>consul-integration-tests-docker-file</id>
+      <activation>
+        <file>
+          <exists>/var/run/docker.sock</exists>
+        </file>
+      </activation>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-failsafe-plugin</artifactId>
+            <configuration>
+              <systemPropertyVariables>
+                <visibleassertions.silence>true</visibleassertions.silence>
+              </systemPropertyVariables>
+            </configuration>
+            <executions>
+              <execution>
+                <goals>
+                  <goal>integration-test</goal>
+                  <goal>verify</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+    <!-- activate integration test if the DOCKER_HOST env var is set -->
+    <profile>
+      <id>consul-integration-tests-docker-env</id>
+      <activation>
+        <property>
+          <name>env.DOCKER_HOST</name>
+        </property>
+      </activation>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-failsafe-plugin</artifactId>
+            <configuration>
+              <systemPropertyVariables>
+                <visibleassertions.silence>true</visibleassertions.silence>
+              </systemPropertyVariables>
+            </configuration>
+            <executions>
+              <execution>
+                <goals>
+                  <goal>integration-test</goal>
+                  <goal>verify</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
 </project>
diff --git 
a/platforms/spring-boot/components-starter/camel-consul-starter/src/main/java/org/apache/camel/component/consul/springboot/cloud/ConsulServiceDiscoveryAutoConfiguration.java
 
b/platforms/spring-boot/components-starter/camel-consul-starter/src/main/java/org/apache/camel/component/consul/springboot/cloud/ConsulServiceDiscoveryAutoConfiguration.java
index ec4e9d3..79e2134 100644
--- 
a/platforms/spring-boot/components-starter/camel-consul-starter/src/main/java/org/apache/camel/component/consul/springboot/cloud/ConsulServiceDiscoveryAutoConfiguration.java
+++ 
b/platforms/spring-boot/components-starter/camel-consul-starter/src/main/java/org/apache/camel/component/consul/springboot/cloud/ConsulServiceDiscoveryAutoConfiguration.java
@@ -23,7 +23,6 @@ import javax.annotation.PostConstruct;
 import org.apache.camel.CamelContext;
 import org.apache.camel.cloud.ServiceDiscovery;
 import org.apache.camel.component.consul.cloud.ConsulServiceDiscoveryFactory;
-import 
org.apache.camel.component.consul.springboot.ConsulComponentConfiguration;
 import 
org.apache.camel.model.cloud.springboot.ConsulServiceCallServiceDiscoveryConfigurationCommon;
 import 
org.apache.camel.model.cloud.springboot.ConsulServiceCallServiceDiscoveryConfigurationProperties;
 import org.apache.camel.spring.boot.CamelAutoConfiguration;
diff --git 
a/platforms/spring-boot/components-starter/camel-zookeeper-starter/src/main/java/org/apache/camel/component/zookeeper/cluster/springboot/ZooKeeperClusterServiceAutoConfiguration.java
 
b/platforms/spring-boot/components-starter/camel-consul-starter/src/main/java/org/apache/camel/component/consul/springboot/cloud/ConsulServiceRegistryAutoConfiguration.java
similarity index 63%
copy from 
platforms/spring-boot/components-starter/camel-zookeeper-starter/src/main/java/org/apache/camel/component/zookeeper/cluster/springboot/ZooKeeperClusterServiceAutoConfiguration.java
copy to 
platforms/spring-boot/components-starter/camel-consul-starter/src/main/java/org/apache/camel/component/consul/springboot/cloud/ConsulServiceRegistryAutoConfiguration.java
index c34d82e..e44af74 100644
--- 
a/platforms/spring-boot/components-starter/camel-zookeeper-starter/src/main/java/org/apache/camel/component/zookeeper/cluster/springboot/ZooKeeperClusterServiceAutoConfiguration.java
+++ 
b/platforms/spring-boot/components-starter/camel-consul-starter/src/main/java/org/apache/camel/component/consul/springboot/cloud/ConsulServiceRegistryAutoConfiguration.java
@@ -14,14 +14,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.component.zookeeper.cluster.springboot;
+package org.apache.camel.component.consul.springboot.cloud;
 
-import org.apache.camel.cluster.CamelClusterService;
-import org.apache.camel.component.zookeeper.cluster.ZooKeeperClusterService;
+import org.apache.camel.component.consul.cloud.ConsulServiceRegistry;
 import org.apache.camel.spring.boot.CamelAutoConfiguration;
-import 
org.apache.camel.spring.boot.cluster.ClusteredRouteControllerAutoConfiguration;
 import org.apache.camel.util.IntrospectionSupport;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.config.ConfigurableBeanFactory;
 import org.springframework.boot.autoconfigure.AutoConfigureBefore;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -31,17 +28,15 @@ import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Scope;
 
 @Configuration
-@AutoConfigureBefore({ ClusteredRouteControllerAutoConfiguration.class, 
CamelAutoConfiguration.class })
-@ConditionalOnProperty(prefix = "camel.component.zookeeper.cluster.service", 
name = "enabled")
-@EnableConfigurationProperties(ZooKeeperClusterServiceConfiguration.class)
-public class ZooKeeperClusterServiceAutoConfiguration {
-    @Autowired
-    private ZooKeeperClusterServiceConfiguration configuration;
+@AutoConfigureBefore(CamelAutoConfiguration.class)
+@ConditionalOnProperty(prefix = "camel.component.consul.service-registry", 
name = "enabled")
+@EnableConfigurationProperties(ConsulServiceRegistryConfiguration.class)
+public class ConsulServiceRegistryAutoConfiguration {
 
-    @Bean(name = "zookeeper-cluster-service")
+    @Bean(name = "consul-service-registry")
     @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
-    public CamelClusterService zookeeperClusterService() throws Exception {
-        ZooKeeperClusterService service = new ZooKeeperClusterService();
+    public ConsulServiceRegistry 
consulServiceRegistry(ConsulServiceRegistryConfiguration configuration) throws 
Exception {
+        ConsulServiceRegistry service = new ConsulServiceRegistry();
 
         IntrospectionSupport.setProperties(
             service,
diff --git 
a/platforms/spring-boot/components-starter/camel-consul-starter/src/main/java/org/apache/camel/component/consul/springboot/cluster/ConsulClusterServiceConfiguration.java
 
b/platforms/spring-boot/components-starter/camel-consul-starter/src/main/java/org/apache/camel/component/consul/springboot/cloud/ConsulServiceRegistryConfiguration.java
similarity index 81%
copy from 
platforms/spring-boot/components-starter/camel-consul-starter/src/main/java/org/apache/camel/component/consul/springboot/cluster/ConsulClusterServiceConfiguration.java
copy to 
platforms/spring-boot/components-starter/camel-consul-starter/src/main/java/org/apache/camel/component/consul/springboot/cloud/ConsulServiceRegistryConfiguration.java
index 6cb1bf9..d9e457d 100644
--- 
a/platforms/spring-boot/components-starter/camel-consul-starter/src/main/java/org/apache/camel/component/consul/springboot/cluster/ConsulClusterServiceConfiguration.java
+++ 
b/platforms/spring-boot/components-starter/camel-consul-starter/src/main/java/org/apache/camel/component/consul/springboot/cloud/ConsulServiceRegistryConfiguration.java
@@ -14,22 +14,21 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.component.consul.springboot.cluster;
+package org.apache.camel.component.consul.springboot.cloud;
 
 import java.util.Map;
 
-import org.apache.camel.component.consul.cluster.ConsulClusterConfiguration;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 
-@ConfigurationProperties(prefix = "camel.component.consul.cluster.service")
-public class ConsulClusterServiceConfiguration extends 
ConsulClusterConfiguration {
+@ConfigurationProperties(prefix = "camel.component.consul.service-registry")
+public class ConsulServiceRegistryConfiguration extends 
org.apache.camel.component.consul.cloud.ConsulServiceRegistryConfiguration {
     /**
-     * Sets if the zookeeper cluster service should be enabled or not, default 
is false.
+     * Sets if the consul service registry should be enabled or not, default 
is false.
      */
     private boolean enabled;
 
     /**
-     * Cluster Service ID
+     * Service Registry ID
      */
     private String id;
 
diff --git 
a/platforms/spring-boot/components-starter/camel-consul-starter/src/main/java/org/apache/camel/component/consul/springboot/cluster/ConsulClusterServiceConfiguration.java
 
b/platforms/spring-boot/components-starter/camel-consul-starter/src/main/java/org/apache/camel/component/consul/springboot/cluster/ConsulClusterServiceConfiguration.java
index 6cb1bf9..01600ff 100644
--- 
a/platforms/spring-boot/components-starter/camel-consul-starter/src/main/java/org/apache/camel/component/consul/springboot/cluster/ConsulClusterServiceConfiguration.java
+++ 
b/platforms/spring-boot/components-starter/camel-consul-starter/src/main/java/org/apache/camel/component/consul/springboot/cluster/ConsulClusterServiceConfiguration.java
@@ -24,7 +24,7 @@ import 
org.springframework.boot.context.properties.ConfigurationProperties;
 @ConfigurationProperties(prefix = "camel.component.consul.cluster.service")
 public class ConsulClusterServiceConfiguration extends 
ConsulClusterConfiguration {
     /**
-     * Sets if the zookeeper cluster service should be enabled or not, default 
is false.
+     * Sets if the consul cluster service should be enabled or not, default is 
false.
      */
     private boolean enabled;
 
diff --git 
a/platforms/spring-boot/components-starter/camel-consul-starter/src/main/resources/META-INF/spring.factories
 
b/platforms/spring-boot/components-starter/camel-consul-starter/src/main/resources/META-INF/spring.factories
index 1e63a81..a8142d0 100644
--- 
a/platforms/spring-boot/components-starter/camel-consul-starter/src/main/resources/META-INF/spring.factories
+++ 
b/platforms/spring-boot/components-starter/camel-consul-starter/src/main/resources/META-INF/spring.factories
@@ -15,7 +15,8 @@
 ## limitations under the License.
 ## ---------------------------------------------------------------------------
 org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
-org.apache.camel.component.consul.springboot.ConsulComponentAutoConfiguration,\
-org.apache.camel.component.consul.springboot.cloud.ConsulServiceDiscoveryAutoConfiguration,\
-org.apache.camel.component.consul.springboot.cluster.ConsulClusterServiceAutoConfiguration,\
-org.apache.camel.component.consul.springboot.health.HealthCheckRepositoryAutoConfiguration
\ No newline at end of file
+    
org.apache.camel.component.consul.springboot.ConsulComponentAutoConfiguration,\
+    
org.apache.camel.component.consul.springboot.cloud.ConsulServiceDiscoveryAutoConfiguration,\
+    
org.apache.camel.component.consul.springboot.cloud.ConsulServiceRegistryAutoConfiguration,\
+    
org.apache.camel.component.consul.springboot.cluster.ConsulClusterServiceAutoConfiguration,\
+    
org.apache.camel.component.consul.springboot.health.HealthCheckRepositoryAutoConfiguration
\ No newline at end of file
diff --git 
a/platforms/spring-boot/components-starter/camel-consul-starter/src/test/java/org/apache/camel/component/consul/springboot/cloud/ConsulServiceDiscoveryDisabledTest.java
 
b/platforms/spring-boot/components-starter/camel-consul-starter/src/test/java/org/apache/camel/component/consul/springboot/cloud/ConsulServiceDiscoveryDisabledTest.java
deleted file mode 100644
index 01cc252..0000000
--- 
a/platforms/spring-boot/components-starter/camel-consul-starter/src/test/java/org/apache/camel/component/consul/springboot/cloud/ConsulServiceDiscoveryDisabledTest.java
+++ /dev/null
@@ -1,64 +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.component.consul.springboot.cloud;
-
-import java.util.Map;
-
-import org.apache.camel.cloud.ServiceDiscovery;
-import 
org.apache.camel.model.cloud.springboot.ConsulServiceCallServiceDiscoveryConfigurationProperties;
-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.context.ApplicationContext;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.test.annotation.DirtiesContext;
-import org.springframework.test.context.junit4.SpringRunner;
-
-@RunWith(SpringRunner.class)
-@DirtiesContext
-@SpringBootApplication
-@SpringBootTest(
-    classes = {
-        ConsulServiceDiscoveryEnabledTest.TestConfiguration.class
-    },
-    properties = {
-        "debug=false",
-        "camel.cloud.consul.service-discovery.enabled=false"
-})
-public class ConsulServiceDiscoveryDisabledTest {
-    @Autowired
-    ApplicationContext context;
-
-    @Test
-    public void testConfiguration() throws Exception {
-        Map<String, ?> beans;
-
-        beans = 
context.getBeansOfType(ConsulServiceCallServiceDiscoveryConfigurationProperties.class);
-        Assert.assertTrue(beans.isEmpty());
-
-        beans = context.getBeansOfType(ServiceDiscovery.class);
-        Assert.assertFalse(beans.isEmpty());
-        Assert.assertFalse(beans.containsKey("consul-service-discovery"));
-    }
-
-    @Configuration
-    public static class TestConfiguration {
-    }
-}
diff --git 
a/platforms/spring-boot/components-starter/camel-consul-starter/src/test/java/org/apache/camel/component/consul/springboot/cloud/ConsulServiceDiscoveryEnabledTest.java
 
b/platforms/spring-boot/components-starter/camel-consul-starter/src/test/java/org/apache/camel/component/consul/springboot/cloud/ConsulServiceDiscoveryEnabledTest.java
deleted file mode 100644
index cedfde5..0000000
--- 
a/platforms/spring-boot/components-starter/camel-consul-starter/src/test/java/org/apache/camel/component/consul/springboot/cloud/ConsulServiceDiscoveryEnabledTest.java
+++ /dev/null
@@ -1,65 +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.component.consul.springboot.cloud;
-
-import java.util.Map;
-
-import org.apache.camel.cloud.ServiceDiscovery;
-import 
org.apache.camel.model.cloud.springboot.ConsulServiceCallServiceDiscoveryConfigurationProperties;
-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.context.ApplicationContext;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.test.annotation.DirtiesContext;
-import org.springframework.test.context.junit4.SpringRunner;
-
-@RunWith(SpringRunner.class)
-@DirtiesContext
-@SpringBootApplication
-@SpringBootTest(
-    classes = {
-        ConsulServiceDiscoveryEnabledTest.TestConfiguration.class
-    },
-    properties = {
-        "debug=false",
-        "camel.cloud.consul.service-discovery.enabled=true"
-})
-public class ConsulServiceDiscoveryEnabledTest {
-    @Autowired
-    ApplicationContext context;
-
-    @Test
-    public void testConfiguration() throws Exception {
-        Map<String, ?> beans;
-
-        beans = 
context.getBeansOfType(ConsulServiceCallServiceDiscoveryConfigurationProperties.class);
-        Assert.assertFalse(beans.isEmpty());
-        Assert.assertEquals(1, beans.size());
-
-        beans = context.getBeansOfType(ServiceDiscovery.class);
-        Assert.assertFalse(beans.isEmpty());
-        Assert.assertTrue(beans.containsKey("consul-service-discovery"));
-    }
-
-    @Configuration
-    public static class TestConfiguration {
-    }
-}
diff --git 
a/platforms/spring-boot/components-starter/camel-consul-starter/src/test/java/org/apache/camel/component/consul/springboot/cloud/ConsulServiceDiscoveryTest.java
 
b/platforms/spring-boot/components-starter/camel-consul-starter/src/test/java/org/apache/camel/component/consul/springboot/cloud/ConsulServiceDiscoveryTest.java
new file mode 100644
index 0000000..1d2b30d
--- /dev/null
+++ 
b/platforms/spring-boot/components-starter/camel-consul-starter/src/test/java/org/apache/camel/component/consul/springboot/cloud/ConsulServiceDiscoveryTest.java
@@ -0,0 +1,63 @@
+/**
+ * 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.component.consul.springboot.cloud;
+
+import org.apache.camel.cloud.ServiceDiscovery;
+import 
org.apache.camel.model.cloud.springboot.ConsulServiceCallServiceDiscoveryConfigurationProperties;
+import org.junit.Test;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.runner.ApplicationContextRunner;
+import org.springframework.context.annotation.Configuration;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ConsulServiceDiscoveryTest {
+    @Test
+    public void testConsulServiceDiscoveryDisabled() {
+        new ApplicationContextRunner()
+            .withUserConfiguration(TestConfiguration.class)
+            .withPropertyValues(
+                "spring.main.banner-mode=off",
+                "camel.cloud.consul.service-discovery.enabled=false")
+            .run(
+                context -> {
+                    
assertThat(context).doesNotHaveBean(ConsulServiceCallServiceDiscoveryConfigurationProperties.class);
+                    
assertThat(context).getBeans(ServiceDiscovery.class).doesNotContainKeys("consul-service-discovery");
+                }
+            );
+    }
+
+    @Test
+    public void testConsulServiceDiscoveryEnabled() {
+        new ApplicationContextRunner()
+            .withUserConfiguration(TestConfiguration.class)
+            .withPropertyValues(
+                "spring.main.banner-mode=off",
+                "camel.cloud.consul.service-discovery.enabled=true")
+            .run(
+                context -> {
+                    
assertThat(context).hasSingleBean(ConsulServiceCallServiceDiscoveryConfigurationProperties.class);
+                    
assertThat(context).getBeans(ServiceDiscovery.class).containsKeys("consul-service-discovery");
+                }
+            );
+    }
+
+    @EnableAutoConfiguration
+    @Configuration
+    public static class TestConfiguration {
+    }
+}
diff --git 
a/platforms/spring-boot/components-starter/camel-consul-starter/src/test/java/org/apache/camel/component/consul/springboot/cloud/ConsulServiceRegistryIT.java
 
b/platforms/spring-boot/components-starter/camel-consul-starter/src/test/java/org/apache/camel/component/consul/springboot/cloud/ConsulServiceRegistryIT.java
new file mode 100644
index 0000000..b3045d9
--- /dev/null
+++ 
b/platforms/spring-boot/components-starter/camel-consul-starter/src/test/java/org/apache/camel/component/consul/springboot/cloud/ConsulServiceRegistryIT.java
@@ -0,0 +1,98 @@
+/**
+ * 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.component.consul.springboot.cloud;
+
+import java.util.List;
+import java.util.UUID;
+
+import com.orbitz.consul.Consul;
+import com.orbitz.consul.model.catalog.CatalogService;
+import org.apache.camel.CamelContext;
+import org.apache.camel.cloud.ServiceRegistry;
+import 
org.apache.camel.component.consul.springboot.cloud.support.ConsulContainerSupport;
+import org.apache.camel.impl.cloud.DefaultServiceDefinition;
+import org.junit.Rule;
+import org.junit.Test;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.runner.ApplicationContextRunner;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.util.SocketUtils;
+import org.testcontainers.containers.GenericContainer;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ConsulServiceRegistryIT {
+    protected static final String SERVICE_ID = UUID.randomUUID().toString();
+    protected static final String SERVICE_NAME = "my-service";
+    protected static final String SERVICE_HOST = "localhost";
+    protected static final int SERVICE_PORT = 
SocketUtils.findAvailableTcpPort();
+
+    @Rule
+    public GenericContainer container = 
ConsulContainerSupport.consulContainer();
+
+    @Test
+    public void testServiceRegistry() {
+        new ApplicationContextRunner()
+            .withUserConfiguration(TestConfiguration.class)
+            .withPropertyValues(
+                "debug=false",
+                "spring.main.banner-mode=OFF",
+                "spring.application.name=" + UUID.randomUUID().toString(),
+                "camel.component.consul.service-registry.enabled=true",
+                "camel.component.consul.service-registry.url=" + 
ConsulContainerSupport.consulUrl(container),
+                "camel.component.consul.service-registry.id=" + 
UUID.randomUUID().toString(),
+                
"camel.component.consul.service-registry.service-host=localhost")
+            .run(
+                context -> {
+                    assertThat(context).hasSingleBean(CamelContext.class);
+                    assertThat(context).hasSingleBean(ServiceRegistry.class);
+
+                    final CamelContext camelContext =  
context.getBean(CamelContext.class);
+                    final ServiceRegistry serviceRegistry = 
camelContext.hasService(ServiceRegistry.class);
+
+                    assertThat(serviceRegistry).isNotNull();
+
+                    serviceRegistry.register(
+                        DefaultServiceDefinition.builder()
+                            .withHost(SERVICE_HOST)
+                            .withPort(SERVICE_PORT)
+                            .withName(SERVICE_NAME)
+                            .withId(SERVICE_ID)
+                            .build()
+                    );
+
+                    final Consul client = 
Consul.builder().withUrl(ConsulContainerSupport.consulUrl(container)).build();
+                    final List<CatalogService> services = 
client.catalogClient().getService(SERVICE_NAME).getResponse();
+
+                    assertThat(services).hasSize(1);
+                    
assertThat(services).first().hasFieldOrPropertyWithValue("serviceId", 
SERVICE_ID);
+                    
assertThat(services).first().hasFieldOrPropertyWithValue("serviceName", 
SERVICE_NAME);
+                    
assertThat(services).first().hasFieldOrPropertyWithValue("serviceAddress", 
SERVICE_HOST);
+                    
assertThat(services).first().hasFieldOrPropertyWithValue("servicePort", 
SERVICE_PORT);
+                }
+            );
+    }
+
+    // *************************************
+    // Config
+    // *************************************
+
+    @EnableAutoConfiguration
+    @Configuration
+    public static class TestConfiguration {
+    }
+}
diff --git 
a/platforms/spring-boot/components-starter/camel-consul-starter/src/test/java/org/apache/camel/component/consul/springboot/cloud/support/ConsulContainerLogger.java
 
b/platforms/spring-boot/components-starter/camel-consul-starter/src/test/java/org/apache/camel/component/consul/springboot/cloud/support/ConsulContainerLogger.java
new file mode 100644
index 0000000..533c3cf
--- /dev/null
+++ 
b/platforms/spring-boot/components-starter/camel-consul-starter/src/test/java/org/apache/camel/component/consul/springboot/cloud/support/ConsulContainerLogger.java
@@ -0,0 +1,31 @@
+/**
+ * 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.component.consul.springboot.cloud.support;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testcontainers.containers.output.Slf4jLogConsumer;
+
+public final class ConsulContainerLogger extends Slf4jLogConsumer {
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(ConsulContainerLogger.class);
+
+    public ConsulContainerLogger() {
+        super(LOGGER);
+
+        withPrefix("consul");
+    }
+}
diff --git 
a/platforms/spring-boot/components-starter/camel-consul-starter/src/test/java/org/apache/camel/component/consul/springboot/cloud/support/ConsulContainerSupport.java
 
b/platforms/spring-boot/components-starter/camel-consul-starter/src/test/java/org/apache/camel/component/consul/springboot/cloud/support/ConsulContainerSupport.java
new file mode 100644
index 0000000..9a101de
--- /dev/null
+++ 
b/platforms/spring-boot/components-starter/camel-consul-starter/src/test/java/org/apache/camel/component/consul/springboot/cloud/support/ConsulContainerSupport.java
@@ -0,0 +1,46 @@
+/**
+ * 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.component.consul.springboot.cloud.support;
+
+import com.orbitz.consul.Consul;
+import org.testcontainers.containers.GenericContainer;
+
+public final class ConsulContainerSupport {
+    private ConsulContainerSupport() {
+    }
+
+    public static GenericContainer consulContainer() {
+        return new GenericContainer("consul:1.0.0")
+            .withExposedPorts(Consul.DEFAULT_HTTP_PORT)
+            .waitingFor(new ConsulContainerWaitStrategy())
+            .withLogConsumer(new ConsulContainerLogger())
+            .withCommand(
+                "agent",
+                "-dev",
+                "-server",
+                "-bootstrap",
+                "-client",
+                "0.0.0.0",
+                "-log-level",
+                "trace"
+            );
+    }
+
+    public static  String consulUrl(GenericContainer container) {
+        return String.format("http://%s:%d";, 
container.getContainerIpAddress(), 
container.getMappedPort(Consul.DEFAULT_HTTP_PORT));
+    }
+}
diff --git 
a/platforms/spring-boot/components-starter/camel-consul-starter/src/test/java/org/apache/camel/component/consul/springboot/cloud/support/ConsulContainerWaitStrategy.java
 
b/platforms/spring-boot/components-starter/camel-consul-starter/src/test/java/org/apache/camel/component/consul/springboot/cloud/support/ConsulContainerWaitStrategy.java
new file mode 100644
index 0000000..79633b0
--- /dev/null
+++ 
b/platforms/spring-boot/components-starter/camel-consul-starter/src/test/java/org/apache/camel/component/consul/springboot/cloud/support/ConsulContainerWaitStrategy.java
@@ -0,0 +1,48 @@
+/**
+ * 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.component.consul.springboot.cloud.support;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import com.github.dockerjava.api.DockerClient;
+import org.testcontainers.DockerClientFactory;
+import org.testcontainers.containers.ContainerLaunchException;
+import org.testcontainers.containers.output.WaitingConsumer;
+import org.testcontainers.containers.wait.strategy.AbstractWaitStrategy;
+import org.testcontainers.utility.LogUtils;
+
+public final class ConsulContainerWaitStrategy extends AbstractWaitStrategy {
+    @Override
+    protected void waitUntilReady() {
+        final DockerClient client = DockerClientFactory.instance().client();
+        final WaitingConsumer waitingConsumer = new WaitingConsumer();
+
+        LogUtils.followOutput(client, waitStrategyTarget.getContainerId(), 
waitingConsumer);
+
+        try {
+            waitingConsumer.waitUntil(
+                f -> f.getUtf8String().contains("Synced node info"),
+                startupTimeout.getSeconds(),
+                TimeUnit.SECONDS,
+                1
+            );
+        } catch (TimeoutException e) {
+            throw new ContainerLaunchException("Timed out");
+        }
+    }
+}
\ No newline at end of file
diff --git 
a/platforms/spring-boot/components-starter/camel-consul-starter/src/test/resources/logback.xml
 
b/platforms/spring-boot/components-starter/camel-consul-starter/src/test/resources/logback.xml
index 9b17d4a..972efdc0 100644
--- 
a/platforms/spring-boot/components-starter/camel-consul-starter/src/test/resources/logback.xml
+++ 
b/platforms/spring-boot/components-starter/camel-consul-starter/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/platforms/spring-boot/components-starter/camel-zookeeper-starter/pom.xml 
b/platforms/spring-boot/components-starter/camel-zookeeper-starter/pom.xml
index 7c274d2..f6996a0 100644
--- a/platforms/spring-boot/components-starter/camel-zookeeper-starter/pom.xml
+++ b/platforms/spring-boot/components-starter/camel-zookeeper-starter/pom.xml
@@ -39,6 +39,13 @@
       <artifactId>camel-zookeeper</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <!-- testing -->
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-jetty</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
     <!--START OF GENERATED CODE-->
     <dependency>
       <groupId>org.apache.camel</groupId>
diff --git 
a/platforms/spring-boot/components-starter/camel-zookeeper-starter/src/main/java/org/apache/camel/component/zookeeper/cluster/springboot/ZooKeeperClusterServiceAutoConfiguration.java
 
b/platforms/spring-boot/components-starter/camel-zookeeper-starter/src/main/java/org/apache/camel/component/zookeeper/springboot/cloud/ZooKeeperServiceRegistryAutoConfiguration.java
similarity index 63%
copy from 
platforms/spring-boot/components-starter/camel-zookeeper-starter/src/main/java/org/apache/camel/component/zookeeper/cluster/springboot/ZooKeeperClusterServiceAutoConfiguration.java
copy to 
platforms/spring-boot/components-starter/camel-zookeeper-starter/src/main/java/org/apache/camel/component/zookeeper/springboot/cloud/ZooKeeperServiceRegistryAutoConfiguration.java
index c34d82e..16d9722 100644
--- 
a/platforms/spring-boot/components-starter/camel-zookeeper-starter/src/main/java/org/apache/camel/component/zookeeper/cluster/springboot/ZooKeeperClusterServiceAutoConfiguration.java
+++ 
b/platforms/spring-boot/components-starter/camel-zookeeper-starter/src/main/java/org/apache/camel/component/zookeeper/springboot/cloud/ZooKeeperServiceRegistryAutoConfiguration.java
@@ -14,14 +14,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.component.zookeeper.cluster.springboot;
+package org.apache.camel.component.zookeeper.springboot.cloud;
 
-import org.apache.camel.cluster.CamelClusterService;
-import org.apache.camel.component.zookeeper.cluster.ZooKeeperClusterService;
+import org.apache.camel.component.zookeeper.cloud.ZooKeeperServiceRegistry;
 import org.apache.camel.spring.boot.CamelAutoConfiguration;
-import 
org.apache.camel.spring.boot.cluster.ClusteredRouteControllerAutoConfiguration;
 import org.apache.camel.util.IntrospectionSupport;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.config.ConfigurableBeanFactory;
 import org.springframework.boot.autoconfigure.AutoConfigureBefore;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -31,17 +28,15 @@ import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Scope;
 
 @Configuration
-@AutoConfigureBefore({ ClusteredRouteControllerAutoConfiguration.class, 
CamelAutoConfiguration.class })
-@ConditionalOnProperty(prefix = "camel.component.zookeeper.cluster.service", 
name = "enabled")
-@EnableConfigurationProperties(ZooKeeperClusterServiceConfiguration.class)
-public class ZooKeeperClusterServiceAutoConfiguration {
-    @Autowired
-    private ZooKeeperClusterServiceConfiguration configuration;
+@AutoConfigureBefore(CamelAutoConfiguration.class)
+@ConditionalOnProperty(prefix = "camel.component.zookeeper.service-registry", 
name = "enabled")
+@EnableConfigurationProperties(ZooKeeperServiceRegistryConfiguration.class)
+public class ZooKeeperServiceRegistryAutoConfiguration {
 
-    @Bean(name = "zookeeper-cluster-service")
+    @Bean(name = "zookeeper-service-registry")
     @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
-    public CamelClusterService zookeeperClusterService() throws Exception {
-        ZooKeeperClusterService service = new ZooKeeperClusterService();
+    public ZooKeeperServiceRegistry 
zookeeperServiceRegistry(ZooKeeperServiceRegistryConfiguration configuration) 
throws Exception {
+        ZooKeeperServiceRegistry service = new ZooKeeperServiceRegistry();
 
         IntrospectionSupport.setProperties(
             service,
diff --git 
a/platforms/spring-boot/components-starter/camel-consul-starter/src/main/java/org/apache/camel/component/consul/springboot/cluster/ConsulClusterServiceConfiguration.java
 
b/platforms/spring-boot/components-starter/camel-zookeeper-starter/src/main/java/org/apache/camel/component/zookeeper/springboot/cloud/ZooKeeperServiceRegistryConfiguration.java
similarity index 81%
copy from 
platforms/spring-boot/components-starter/camel-consul-starter/src/main/java/org/apache/camel/component/consul/springboot/cluster/ConsulClusterServiceConfiguration.java
copy to 
platforms/spring-boot/components-starter/camel-zookeeper-starter/src/main/java/org/apache/camel/component/zookeeper/springboot/cloud/ZooKeeperServiceRegistryConfiguration.java
index 6cb1bf9..699e8c8 100644
--- 
a/platforms/spring-boot/components-starter/camel-consul-starter/src/main/java/org/apache/camel/component/consul/springboot/cluster/ConsulClusterServiceConfiguration.java
+++ 
b/platforms/spring-boot/components-starter/camel-zookeeper-starter/src/main/java/org/apache/camel/component/zookeeper/springboot/cloud/ZooKeeperServiceRegistryConfiguration.java
@@ -14,22 +14,21 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.component.consul.springboot.cluster;
+package org.apache.camel.component.zookeeper.springboot.cloud;
 
 import java.util.Map;
 
-import org.apache.camel.component.consul.cluster.ConsulClusterConfiguration;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 
-@ConfigurationProperties(prefix = "camel.component.consul.cluster.service")
-public class ConsulClusterServiceConfiguration extends 
ConsulClusterConfiguration {
+@ConfigurationProperties(prefix = "camel.component.zookeeper.service-registry")
+public class ZooKeeperServiceRegistryConfiguration extends 
org.apache.camel.component.zookeeper.cloud.ZooKeeperServiceRegistryConfiguration
 {
     /**
-     * Sets if the zookeeper cluster service should be enabled or not, default 
is false.
+     * Sets if the zookeeper service registry should be enabled or not, 
default is false.
      */
     private boolean enabled;
 
     /**
-     * Cluster Service ID
+     * Service Registry ID
      */
     private String id;
 
diff --git 
a/platforms/spring-boot/components-starter/camel-zookeeper-starter/src/main/java/org/apache/camel/component/zookeeper/cluster/springboot/ZooKeeperClusterServiceAutoConfiguration.java
 
b/platforms/spring-boot/components-starter/camel-zookeeper-starter/src/main/java/org/apache/camel/component/zookeeper/springboot/cluster/ZooKeeperClusterServiceAutoConfiguration.java
similarity index 97%
rename from 
platforms/spring-boot/components-starter/camel-zookeeper-starter/src/main/java/org/apache/camel/component/zookeeper/cluster/springboot/ZooKeeperClusterServiceAutoConfiguration.java
rename to 
platforms/spring-boot/components-starter/camel-zookeeper-starter/src/main/java/org/apache/camel/component/zookeeper/springboot/cluster/ZooKeeperClusterServiceAutoConfiguration.java
index c34d82e..5017b92 100644
--- 
a/platforms/spring-boot/components-starter/camel-zookeeper-starter/src/main/java/org/apache/camel/component/zookeeper/cluster/springboot/ZooKeeperClusterServiceAutoConfiguration.java
+++ 
b/platforms/spring-boot/components-starter/camel-zookeeper-starter/src/main/java/org/apache/camel/component/zookeeper/springboot/cluster/ZooKeeperClusterServiceAutoConfiguration.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.component.zookeeper.cluster.springboot;
+package org.apache.camel.component.zookeeper.springboot.cluster;
 
 import org.apache.camel.cluster.CamelClusterService;
 import org.apache.camel.component.zookeeper.cluster.ZooKeeperClusterService;
diff --git 
a/platforms/spring-boot/components-starter/camel-zookeeper-starter/src/main/java/org/apache/camel/component/zookeeper/cluster/springboot/ZooKeeperClusterServiceConfiguration.java
 
b/platforms/spring-boot/components-starter/camel-zookeeper-starter/src/main/java/org/apache/camel/component/zookeeper/springboot/cluster/ZooKeeperClusterServiceConfiguration.java
similarity index 97%
rename from 
platforms/spring-boot/components-starter/camel-zookeeper-starter/src/main/java/org/apache/camel/component/zookeeper/cluster/springboot/ZooKeeperClusterServiceConfiguration.java
rename to 
platforms/spring-boot/components-starter/camel-zookeeper-starter/src/main/java/org/apache/camel/component/zookeeper/springboot/cluster/ZooKeeperClusterServiceConfiguration.java
index 1feb5af..fffa14e 100644
--- 
a/platforms/spring-boot/components-starter/camel-zookeeper-starter/src/main/java/org/apache/camel/component/zookeeper/cluster/springboot/ZooKeeperClusterServiceConfiguration.java
+++ 
b/platforms/spring-boot/components-starter/camel-zookeeper-starter/src/main/java/org/apache/camel/component/zookeeper/springboot/cluster/ZooKeeperClusterServiceConfiguration.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.component.zookeeper.cluster.springboot;
+package org.apache.camel.component.zookeeper.springboot.cluster;
 
 import java.util.Map;
 
diff --git 
a/platforms/spring-boot/components-starter/camel-zookeeper-starter/src/main/resources/META-INF/spring.factories
 
b/platforms/spring-boot/components-starter/camel-zookeeper-starter/src/main/resources/META-INF/spring.factories
index f3a7b4b..383172c 100644
--- 
a/platforms/spring-boot/components-starter/camel-zookeeper-starter/src/main/resources/META-INF/spring.factories
+++ 
b/platforms/spring-boot/components-starter/camel-zookeeper-starter/src/main/resources/META-INF/spring.factories
@@ -15,5 +15,6 @@
 ## limitations under the License.
 ## ---------------------------------------------------------------------------
 org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
-org.apache.camel.component.zookeeper.springboot.ZooKeeperComponentAutoConfiguration,\
-org.apache.camel.component.zookeeper.cluster.springboot.ZooKeeperClusterServiceAutoConfiguration
+    
org.apache.camel.component.zookeeper.springboot.ZooKeeperComponentAutoConfiguration,\
+    
org.apache.camel.component.zookeeper.springboot.cloud.ZooKeeperServiceRegistryAutoConfiguration,\
+    
org.apache.camel.component.zookeeper.springboot.cluster.ZooKeeperClusterServiceAutoConfiguration
diff --git 
a/platforms/spring-boot/components-starter/camel-zookeeper-starter/src/test/java/org/apache/camel/component/zookeeper/springboot/cloud/ZooKeeperServiceRegistryTest.java
 
b/platforms/spring-boot/components-starter/camel-zookeeper-starter/src/test/java/org/apache/camel/component/zookeeper/springboot/cloud/ZooKeeperServiceRegistryTest.java
new file mode 100644
index 0000000..7243d61
--- /dev/null
+++ 
b/platforms/spring-boot/components-starter/camel-zookeeper-starter/src/test/java/org/apache/camel/component/zookeeper/springboot/cloud/ZooKeeperServiceRegistryTest.java
@@ -0,0 +1,264 @@
+/**
+ * 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.component.zookeeper.springboot.cloud;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.util.Collection;
+import java.util.UUID;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.cloud.ServiceRegistry;
+import org.apache.camel.component.zookeeper.cloud.ZooKeeperServiceRegistry;
+import org.apache.camel.impl.cloud.DefaultServiceDefinition;
+import org.apache.camel.test.AvailablePortFinder;
+import org.apache.camel.util.IOHelper;
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.CuratorFrameworkFactory;
+import org.apache.curator.retry.ExponentialBackoffRetry;
+import org.apache.curator.utils.CloseableUtils;
+import org.apache.curator.x.discovery.ServiceDiscovery;
+import org.apache.curator.x.discovery.ServiceDiscoveryBuilder;
+import org.apache.curator.x.discovery.ServiceInstance;
+import org.apache.curator.x.discovery.details.JsonInstanceSerializer;
+import org.apache.zookeeper.server.NIOServerCnxnFactory;
+import org.apache.zookeeper.server.ZooKeeperServer;
+import org.apache.zookeeper.server.persistence.FileTxnSnapLog;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.rules.TestName;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.test.context.runner.ApplicationContextRunner;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.util.SocketUtils;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ZooKeeperServiceRegistryTest {
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(ZooKeeperServiceRegistryTest.class);
+
+    private static final String SERVICE_PATH = "/camel";
+    private static final String SERVICE_ID = UUID.randomUUID().toString();
+    private static final String SERVICE_NAME = "my-service";
+    private static final String SERVICE_HOST = "localhost";
+    private static final int SERVICE_PORT = SocketUtils.findAvailableTcpPort();
+
+    @Rule
+    public final TestName testName = new TestName();
+    @Rule
+    public final TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+    @Test
+    public void testServiceRegistry() throws Exception {
+        final ZooKeeperTestServer zkServer = new 
ZooKeeperTestServer(temporaryFolder.newFolder());
+        zkServer.start();
+
+        final ZooKeeperTestClient zkClient = new 
ZooKeeperTestClient(zkServer.serverList());
+        zkClient.start();
+
+        try {
+            new ApplicationContextRunner()
+                .withUserConfiguration(TestConfiguration.class)
+                .withPropertyValues(
+                    "debug=false",
+                    "spring.main.banner-mode=OFF",
+                    "spring.application.name=" + UUID.randomUUID().toString(),
+                    "camel.component.zookeeper.service-registry.enabled=true",
+                    "camel.component.zookeeper.service-registry.nodes=" + 
zkServer.serverList(),
+                    "camel.component.zookeeper.service-registry.id=" + 
UUID.randomUUID().toString(),
+                    "camel.component.zookeeper.service-registry.base-path=" + 
SERVICE_PATH,
+                    
"camel.component.zookeeper.service-registry.service-host=localhost")
+                .run(
+                    context -> {
+                        assertThat(context).hasSingleBean(CamelContext.class);
+                        
assertThat(context).hasSingleBean(ServiceRegistry.class);
+
+                        final CamelContext camelContext = 
context.getBean(CamelContext.class);
+                        final ServiceRegistry serviceRegistry = 
camelContext.hasService(ServiceRegistry.class);
+
+                        assertThat(serviceRegistry).isNotNull();
+
+                        serviceRegistry.register(
+                            DefaultServiceDefinition.builder()
+                                .withHost(SERVICE_HOST)
+                                .withPort(SERVICE_PORT)
+                                .withName(SERVICE_NAME)
+                                .withId(SERVICE_ID)
+                                .build()
+                        );
+
+                        final 
Collection<ServiceInstance<ZooKeeperServiceRegistry.MetaData>> services = 
zkClient.discovery().queryForInstances(SERVICE_NAME);
+
+                        assertThat(services).hasSize(1);
+                        
assertThat(services).first().hasFieldOrPropertyWithValue("id", SERVICE_ID);
+                        
assertThat(services).first().hasFieldOrPropertyWithValue("name", SERVICE_NAME);
+                        
assertThat(services).first().hasFieldOrPropertyWithValue("address", 
SERVICE_HOST);
+                        
assertThat(services).first().hasFieldOrPropertyWithValue("port", SERVICE_PORT);
+                    }
+                );
+        } finally {
+            zkClient.stop();
+            zkServer.stop();
+        }
+    }
+
+    // *************************************
+    // Config
+    // *************************************
+
+    @EnableAutoConfiguration
+    @Configuration
+    public static class TestConfiguration {
+    }
+
+    // *************************************
+    // Helpers
+    // *************************************
+
+    public static class ZooKeeperTestServer {
+        private NIOServerCnxnFactory connectionFactory;
+        private ZooKeeperServer zkServer;
+
+        public ZooKeeperTestServer(File root) throws Exception {
+            zkServer = new ZooKeeperServer();
+
+            File dataDir = new File(root, "log");
+            File snapDir = new File(root, "data");
+            FileTxnSnapLog ftxn = new FileTxnSnapLog(dataDir, snapDir);
+
+            zkServer.setTxnLogFactory(ftxn);
+            zkServer.setTickTime(1000);
+
+            connectionFactory = new NIOServerCnxnFactory();
+            connectionFactory.configure(new InetSocketAddress("localhost", 
AvailablePortFinder.getNextAvailable()), 0);
+            connectionFactory.startup(zkServer);
+        }
+
+        public String serverList() {
+            return "localhost:" + connectionFactory.getLocalPort();
+        }
+
+        private String send4LetterWord(String hp, String cmd) throws 
IOException {
+            String split[] = hp.split(":");
+            String host = split[0];
+            int port;
+            try {
+                port = Integer.parseInt(split[1]);
+            } catch (RuntimeException e) {
+                throw new RuntimeException("Problem parsing " + hp + 
e.toString());
+            }
+
+            Socket sock = new Socket(host, port);
+            BufferedReader reader = null;
+            try {
+                OutputStream outstream = sock.getOutputStream();
+                outstream.write(cmd.getBytes());
+                outstream.flush();
+
+                reader = IOHelper.buffered(new 
InputStreamReader(sock.getInputStream()));
+                StringBuilder sb = new StringBuilder();
+                String line;
+                while ((line = reader.readLine()) != null) {
+                    sb.append(line + "\n");
+                }
+                return sb.toString();
+            } finally {
+                sock.close();
+                if (reader != null) {
+                    reader.close();
+                }
+            }
+        }
+
+        public void start() throws Exception {
+            long start = System.currentTimeMillis();
+            while (true) {
+                try {
+                    String result = send4LetterWord(serverList(), "stat");
+                    if (result.startsWith("Zookeeper version:")) {
+                        return;
+                    }
+                } catch (IOException e) {
+                    LOGGER.info("server {} not up {}", LOGGER, e);
+                }
+
+                if (System.currentTimeMillis() > start + 1000) {
+                    break;
+                }
+                try {
+                    Thread.sleep(250);
+                } catch (InterruptedException e) {
+                    // ignore
+                }
+            }
+        }
+
+        public void stop() throws Exception {
+            connectionFactory.shutdown();
+            connectionFactory.join();
+            zkServer.shutdown();
+
+            while (zkServer.isRunning()) {
+                zkServer.shutdown();
+                Thread.sleep(100);
+            }
+        }
+    }
+
+    public static class ZooKeeperTestClient {
+        private final CuratorFramework curator;
+        private final ServiceDiscovery<ZooKeeperServiceRegistry.MetaData> 
discovery;
+
+        public ZooKeeperTestClient(String nodes) {
+            curator = CuratorFrameworkFactory.builder()
+                .connectString(nodes)
+                .retryPolicy(new ExponentialBackoffRetry(1000, 3))
+                .build();
+            discovery = 
ServiceDiscoveryBuilder.builder(ZooKeeperServiceRegistry.MetaData.class)
+                .client(curator)
+                .basePath(SERVICE_PATH)
+                .serializer(new 
JsonInstanceSerializer<>(ZooKeeperServiceRegistry.MetaData.class))
+                .build();
+        }
+
+        public CuratorFramework curator() {
+            return curator;
+        }
+
+        public ServiceDiscovery<ZooKeeperServiceRegistry.MetaData> discovery() 
{
+            return discovery;
+        }
+
+        public void start() throws Exception {
+            curator.start();
+            discovery.start();
+        }
+
+        public void stop() throws Exception {
+            CloseableUtils.closeQuietly(discovery);
+            CloseableUtils.closeQuietly(curator);
+        }
+    }
+}
diff --git 
a/platforms/spring-boot/components-starter/camel-zookeeper-starter/src/main/resources/META-INF/spring.factories
 
b/platforms/spring-boot/components-starter/camel-zookeeper-starter/src/test/resources/application.properties
similarity index 79%
copy from 
platforms/spring-boot/components-starter/camel-zookeeper-starter/src/main/resources/META-INF/spring.factories
copy to 
platforms/spring-boot/components-starter/camel-zookeeper-starter/src/test/resources/application.properties
index f3a7b4b..2f91fc3 100644
--- 
a/platforms/spring-boot/components-starter/camel-zookeeper-starter/src/main/resources/META-INF/spring.factories
+++ 
b/platforms/spring-boot/components-starter/camel-zookeeper-starter/src/test/resources/application.properties
@@ -14,6 +14,4 @@
 ## See the License for the specific language governing permissions and
 ## limitations under the License.
 ## ---------------------------------------------------------------------------
-org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
-org.apache.camel.component.zookeeper.springboot.ZooKeeperComponentAutoConfiguration,\
-org.apache.camel.component.zookeeper.cluster.springboot.ZooKeeperClusterServiceAutoConfiguration
+spring.main.banner-mode=off
diff --git 
a/platforms/spring-boot/components-starter/camel-consul-starter/src/test/resources/logback.xml
 
b/platforms/spring-boot/components-starter/camel-zookeeper-starter/src/test/resources/logback.xml
similarity index 92%
copy from 
platforms/spring-boot/components-starter/camel-consul-starter/src/test/resources/logback.xml
copy to 
platforms/spring-boot/components-starter/camel-zookeeper-starter/src/test/resources/logback.xml
index 9b17d4a..3e6fbd7 100644
--- 
a/platforms/spring-boot/components-starter/camel-consul-starter/src/test/resources/logback.xml
+++ 
b/platforms/spring-boot/components-starter/camel-zookeeper-starter/src/test/resources/logback.xml
@@ -31,10 +31,11 @@
     <encoder>
       <pattern>%d{HH:mm:ss.SSS} [%-15.15thread] %-5level %-30.30logger - 
%msg%n</pattern>
     </encoder>
-    <file>target/camel-consul-starter-test.log</file>
+    <file>target/camel-zookeeper-starter-test.log</file>
   </appender>
 
   <root level="INFO">
+    <!--<appender-ref ref="STDOUT"/>-->
     <appender-ref ref="FILE"/>
   </root>
 
diff --git a/platforms/spring-boot/spring-boot-dm/pom.xml 
b/platforms/spring-boot/spring-boot-dm/pom.xml
index 4503db3..73ab6c2 100644
--- a/platforms/spring-boot/spring-boot-dm/pom.xml
+++ b/platforms/spring-boot/spring-boot-dm/pom.xml
@@ -47,6 +47,7 @@
     <!-- Needed by BOM generator-->
     <avro-version>1.8.2</avro-version>
     <jackson-version>1.9.12</jackson-version>
+    <testcontainers-version>1.7.3</testcontainers-version>
 
     <!-- Needed by starters -->
     <egit-github-core-version>2.1.5</egit-github-core-version>

-- 
To stop receiving notification emails like this one, please contact
lburgazz...@apache.org.

Reply via email to