You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by lb...@apache.org on 2017/01/11 12:04:17 UTC

[06/10] camel git commit: CAMEL-10638: Refactor ServiceCall EIP

http://git-wip-us.apache.org/repos/asf/camel/blob/a811f400/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java
----------------------------------------------------------------------
diff --git a/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java b/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java
index 41da245..6d94f9f 100644
--- a/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java
+++ b/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java
@@ -39,6 +39,7 @@ import org.apache.camel.core.osgi.OsgiCamelContextPublisher;
 import org.apache.camel.core.osgi.OsgiEventAdminNotifier;
 import org.apache.camel.core.osgi.utils.BundleDelegatingClassLoader;
 import org.apache.camel.core.xml.AbstractCamelContextFactoryBean;
+import org.apache.camel.core.xml.AbstractCamelFactoryBean;
 import org.apache.camel.core.xml.CamelJMXAgentDefinition;
 import org.apache.camel.core.xml.CamelPropertyPlaceholderDefinition;
 import org.apache.camel.core.xml.CamelServiceExporterDefinition;
@@ -57,12 +58,8 @@ import org.apache.camel.model.RouteBuilderDefinition;
 import org.apache.camel.model.RouteContextRefDefinition;
 import org.apache.camel.model.RouteDefinition;
 import org.apache.camel.model.ThreadPoolProfileDefinition;
+import org.apache.camel.model.cloud.ServiceCallConfigurationDefinition;
 import org.apache.camel.model.dataformat.DataFormatsDefinition;
-import org.apache.camel.model.remote.ConsulConfigurationDefinition;
-import org.apache.camel.model.remote.DnsConfigurationDefinition;
-import org.apache.camel.model.remote.EtcdConfigurationDefinition;
-import org.apache.camel.model.remote.KubernetesConfigurationDefinition;
-import org.apache.camel.model.remote.RibbonConfigurationDefinition;
 import org.apache.camel.model.rest.RestConfigurationDefinition;
 import org.apache.camel.model.rest.RestDefinition;
 import org.apache.camel.model.transformer.TransformersDefinition;
@@ -147,18 +144,16 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Blu
     @XmlElement(name = "streamCaching", type = CamelStreamCachingStrategyDefinition.class)
     private CamelStreamCachingStrategyDefinition camelStreamCachingStrategy;
     @XmlElements({
-        @XmlElement(name = "hystrixConfiguration", type = HystrixConfigurationDefinition.class),
-        @XmlElement(name = "kubernetesConfiguration", type = KubernetesConfigurationDefinition.class),
-        @XmlElement(name = "ribbonConfiguration", type = RibbonConfigurationDefinition.class),
-        @XmlElement(name = "consulConfiguration", type = ConsulConfigurationDefinition.class),
-        @XmlElement(name = "dnsConfiguration", type = DnsConfigurationDefinition.class),
-        @XmlElement(name = "etcdConfiguration", type = EtcdConfigurationDefinition.class),
         @XmlElement(name = "template", type = CamelProducerTemplateFactoryBean.class),
         @XmlElement(name = "fluentTemplate", type = CamelFluentProducerTemplateFactoryBean.class),
         @XmlElement(name = "consumerTemplate", type = CamelConsumerTemplateFactoryBean.class),
         @XmlElement(name = "proxy", type = CamelProxyFactoryBean.class),
         @XmlElement(name = "export", type = CamelServiceExporterDefinition.class),
         @XmlElement(name = "errorHandler", type = CamelErrorHandlerFactoryBean.class)})
+    private List<AbstractCamelFactoryBean<?>> beansFactory;
+    @XmlElements({
+        @XmlElement(name = "serviceCallConfiguration", type = ServiceCallConfigurationDefinition.class),
+        @XmlElement(name = "hystrixConfiguration", type = HystrixConfigurationDefinition.class)})
     private List<?> beans;
     @XmlElement(name = "routeBuilder")
     private List<RouteBuilderDefinition> builderRefs = new ArrayList<RouteBuilderDefinition>();
@@ -616,6 +611,15 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Blu
         this.camelStreamCachingStrategy = camelStreamCachingStrategy;
     }
 
+    public List<AbstractCamelFactoryBean<?>> getBeansFactory() {
+        return beansFactory;
+    }
+
+    public void setBeansFactory(List<AbstractCamelFactoryBean<?>> beansFactory) {
+        this.beansFactory = beansFactory;
+    }
+
+    @Override
     public List<?> getBeans() {
         return beans;
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/a811f400/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/handler/CamelNamespaceHandler.java
----------------------------------------------------------------------
diff --git a/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/handler/CamelNamespaceHandler.java b/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/handler/CamelNamespaceHandler.java
index e95f5e1..a4801f1 100644
--- a/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/handler/CamelNamespaceHandler.java
+++ b/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/handler/CamelNamespaceHandler.java
@@ -282,7 +282,7 @@ public class CamelNamespaceHandler implements NamespaceHandler {
         registerBeans(context, contextId, ccfb.getThreadPools());
         registerBeans(context, contextId, ccfb.getEndpoints());
         registerBeans(context, contextId, ccfb.getRedeliveryPolicies());
-        registerBeans(context, contextId, ccfb.getBeans());
+        registerBeans(context, contextId, ccfb.getBeansFactory());
 
         // Register processors
         MutablePassThroughMetadata beanProcessorFactory = context.createMetadata(MutablePassThroughMetadata.class);

http://git-wip-us.apache.org/repos/asf/camel/blob/a811f400/components/camel-cdi/src/main/java/org/apache/camel/cdi/XmlCdiBeanFactory.java
----------------------------------------------------------------------
diff --git a/components/camel-cdi/src/main/java/org/apache/camel/cdi/XmlCdiBeanFactory.java b/components/camel-cdi/src/main/java/org/apache/camel/cdi/XmlCdiBeanFactory.java
index a9aaf05..53d7a6b 100644
--- a/components/camel-cdi/src/main/java/org/apache/camel/cdi/XmlCdiBeanFactory.java
+++ b/components/camel-cdi/src/main/java/org/apache/camel/cdi/XmlCdiBeanFactory.java
@@ -193,8 +193,8 @@ final class XmlCdiBeanFactory {
         Set<SyntheticBean<?>> beans = new HashSet<>();
 
         // TODO: WARN log if the definition doesn't have an id
-        if (factory.getBeans() != null) {
-            factory.getBeans().stream()
+        if (factory.getBeansFactory() != null) {
+            factory.getBeansFactory().stream()
                 .filter(XmlCdiBeanFactory::hasId)
                 .map(bean -> camelContextBean(context, bean, url))
                 .forEach(beans::add);

http://git-wip-us.apache.org/repos/asf/camel/blob/a811f400/components/camel-cdi/src/main/java/org/apache/camel/cdi/xml/CamelContextFactoryBean.java
----------------------------------------------------------------------
diff --git a/components/camel-cdi/src/main/java/org/apache/camel/cdi/xml/CamelContextFactoryBean.java b/components/camel-cdi/src/main/java/org/apache/camel/cdi/xml/CamelContextFactoryBean.java
index 9299424..e5135f6 100644
--- a/components/camel-cdi/src/main/java/org/apache/camel/cdi/xml/CamelContextFactoryBean.java
+++ b/components/camel-cdi/src/main/java/org/apache/camel/cdi/xml/CamelContextFactoryBean.java
@@ -45,6 +45,7 @@ import org.apache.camel.core.xml.CamelServiceExporterDefinition;
 import org.apache.camel.core.xml.CamelStreamCachingStrategyDefinition;
 import org.apache.camel.impl.DefaultCamelContext;
 import org.apache.camel.model.ContextScanDefinition;
+import org.apache.camel.model.HystrixConfigurationDefinition;
 import org.apache.camel.model.InterceptDefinition;
 import org.apache.camel.model.InterceptFromDefinition;
 import org.apache.camel.model.InterceptSendToEndpointDefinition;
@@ -57,6 +58,7 @@ import org.apache.camel.model.RouteBuilderDefinition;
 import org.apache.camel.model.RouteContextRefDefinition;
 import org.apache.camel.model.RouteDefinition;
 import org.apache.camel.model.ThreadPoolProfileDefinition;
+import org.apache.camel.model.cloud.ServiceCallConfigurationDefinition;
 import org.apache.camel.model.dataformat.DataFormatsDefinition;
 import org.apache.camel.model.rest.RestConfigurationDefinition;
 import org.apache.camel.model.rest.RestDefinition;
@@ -159,9 +161,14 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Def
         @XmlElement(name = "consumerTemplate", type = ConsumerTemplateFactoryBean.class),
         @XmlElement(name = "redeliveryPolicyProfile", type = RedeliveryPolicyFactoryBean.class),
         @XmlElement(name = "template", type = ProducerTemplateFactoryBean.class),
-        @XmlElement(name = "threadPool", type = ThreadPoolFactoryBean.class)
+        @XmlElement(name = "threadPool", type = ThreadPoolFactoryBean.class),
     })
-    private List<AbstractCamelFactoryBean<?>> beans;
+    private List<AbstractCamelFactoryBean<?>> beansFactory;
+
+    @XmlElements({
+        @XmlElement(name = "serviceCallConfiguration", type = ServiceCallConfigurationDefinition.class),
+        @XmlElement(name = "hystrixConfiguration", type = HystrixConfigurationDefinition.class)})
+    private List<?> beans;
 
     @XmlElement(name = "errorHandler", type = ErrorHandlerDefinition.class)
     private List<ErrorHandlerDefinition> errorHandlers;
@@ -303,11 +310,20 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Def
         return context;
     }
 
-    public List<AbstractCamelFactoryBean<?>> getBeans() {
+    public List<AbstractCamelFactoryBean<?>> getBeansFactory() {
+        return beansFactory;
+    }
+
+    public void setBeansFactory(List<AbstractCamelFactoryBean<?>> beansFactory) {
+        this.beansFactory = beansFactory;
+    }
+
+    @Override
+    public List<?> getBeans() {
         return beans;
     }
 
-    public void setBeans(List<AbstractCamelFactoryBean<?>> beans) {
+    public void setBeans(List<?> beans) {
         this.beans = beans;
     }
 

http://git-wip-us.apache.org/repos/asf/camel/blob/a811f400/components/camel-cdi/src/test/java/org/apache/camel/cdi/test/XmlServiceCallConfigurationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-cdi/src/test/java/org/apache/camel/cdi/test/XmlServiceCallConfigurationTest.java b/components/camel-cdi/src/test/java/org/apache/camel/cdi/test/XmlServiceCallConfigurationTest.java
new file mode 100644
index 0000000..23e0b14
--- /dev/null
+++ b/components/camel-cdi/src/test/java/org/apache/camel/cdi/test/XmlServiceCallConfigurationTest.java
@@ -0,0 +1,79 @@
+/**
+ * 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.cdi.test;
+
+import java.nio.file.Paths;
+import javax.inject.Inject;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.cdi.CdiCamelExtension;
+import org.apache.camel.cdi.ImportResource;
+import org.apache.camel.model.cloud.ServiceCallConfigurationDefinition;
+import org.apache.camel.model.cloud.StaticServiceCallServiceDiscoveryConfiguration;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.asset.EmptyAsset;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+@RunWith(Arquillian.class)
+@ImportResource("imported-context.xml")
+public class XmlServiceCallConfigurationTest {
+
+    @Inject
+    private CamelContext context;
+
+    @Deployment
+    public static Archive<?> deployment() {
+        return ShrinkWrap.create(JavaArchive.class)
+            // Camel CDI
+            .addPackage(CdiCamelExtension.class.getPackage())
+            // Test Camel XML
+            .addAsResource(
+                Paths.get("src/test/resources/camel-context-service-call-configuration.xml").toFile(),
+                "imported-context.xml")
+            // Bean archive deployment descriptor
+            .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
+    }
+
+    @Test
+    public void testServiceDiscoveryConfiguration() {
+        ServiceCallConfigurationDefinition conf1 = context.getServiceCallConfiguration("conf1");
+        assertNotNull("No ServiceCallConfiguration (1)", conf1);
+        assertNotNull("No ServiceDiscoveryConfiguration (1)", conf1.getServiceDiscoveryConfiguration());
+
+        StaticServiceCallServiceDiscoveryConfiguration discovery1 = (StaticServiceCallServiceDiscoveryConfiguration)conf1.getServiceDiscoveryConfiguration();
+        assertEquals(1, discovery1.getServers().size());
+        assertEquals("localhost:9091", discovery1.getServers().get(0));
+
+        ServiceCallConfigurationDefinition conf2 = context.getServiceCallConfiguration("conf2");
+        assertNotNull("No ServiceCallConfiguration (2)", conf2);
+        assertNotNull("No ServiceDiscoveryConfiguration (2)", conf2.getServiceDiscoveryConfiguration());
+
+        StaticServiceCallServiceDiscoveryConfiguration discovery2 = (StaticServiceCallServiceDiscoveryConfiguration)conf2.getServiceDiscoveryConfiguration();
+        assertEquals(2, discovery2.getServers().size());
+        assertEquals("localhost:9092", discovery2.getServers().get(0));
+        assertEquals("localhost:9093,localhost:9094", discovery2.getServers().get(1));
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/a811f400/components/camel-cdi/src/test/resources/camel-context-service-call-configuration.xml
----------------------------------------------------------------------
diff --git a/components/camel-cdi/src/test/resources/camel-context-service-call-configuration.xml b/components/camel-cdi/src/test/resources/camel-context-service-call-configuration.xml
new file mode 100644
index 0000000..cb18c8b
--- /dev/null
+++ b/components/camel-cdi/src/test/resources/camel-context-service-call-configuration.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+        http://www.springframework.org/schema/beans
+        http://www.springframework.org/schema/beans/spring-beans.xsd
+        http://camel.apache.org/schema/spring
+        http://camel.apache.org/schema/spring/camel-spring.xsd">
+
+    <camelContext id="test" xmlns="http://camel.apache.org/schema/spring">
+
+        <serviceCallConfiguration id="conf1">
+            <staticServiceDiscovery>
+                <servers>localhost:9091</servers>
+            </staticServiceDiscovery>
+        </serviceCallConfiguration>
+
+        <serviceCallConfiguration id="conf2">
+            <staticServiceDiscovery>
+                <servers>localhost:9092</servers>
+                <servers>localhost:9093,localhost:9094</servers>
+            </staticServiceDiscovery>
+        </serviceCallConfiguration>
+
+        <route id="test1">
+            <from uri="direct:start1"/>
+            <serviceCall name="test" configurationRef="conf1"/>
+        </route>
+        <route id="test2">
+            <from uri="direct:start2"/>
+            <serviceCall name="test" configurationRef="conf2"/>
+        </route>
+
+    </camelContext>
+
+</beans>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/a811f400/components/camel-consul/pom.xml
----------------------------------------------------------------------
diff --git a/components/camel-consul/pom.xml b/components/camel-consul/pom.xml
index f660bf5..133d2ff 100644
--- a/components/camel-consul/pom.xml
+++ b/components/camel-consul/pom.xml
@@ -73,6 +73,11 @@
       <scope>test</scope>
     </dependency>
     <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-ribbon</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
       <groupId>org.apache.logging.log4j</groupId>
       <artifactId>log4j-api</artifactId>
       <scope>test</scope>

http://git-wip-us.apache.org/repos/asf/camel/blob/a811f400/components/camel-consul/src/main/java/org/apache/camel/component/consul/ConsulConfiguration.java
----------------------------------------------------------------------
diff --git a/components/camel-consul/src/main/java/org/apache/camel/component/consul/ConsulConfiguration.java b/components/camel-consul/src/main/java/org/apache/camel/component/consul/ConsulConfiguration.java
index e64cd77..dbf1466 100644
--- a/components/camel-consul/src/main/java/org/apache/camel/component/consul/ConsulConfiguration.java
+++ b/components/camel-consul/src/main/java/org/apache/camel/component/consul/ConsulConfiguration.java
@@ -70,6 +70,10 @@ public class ConsulConfiguration {
 
     private final CamelContext context;
 
+    public ConsulConfiguration() {
+        this.context = null;
+    }
+
     public ConsulConfiguration(CamelContext context) {
         this.context = context;
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/a811f400/components/camel-consul/src/main/java/org/apache/camel/component/consul/cloud/ConsulServiceDiscovery.java
----------------------------------------------------------------------
diff --git a/components/camel-consul/src/main/java/org/apache/camel/component/consul/cloud/ConsulServiceDiscovery.java b/components/camel-consul/src/main/java/org/apache/camel/component/consul/cloud/ConsulServiceDiscovery.java
new file mode 100644
index 0000000..104f65a
--- /dev/null
+++ b/components/camel-consul/src/main/java/org/apache/camel/component/consul/cloud/ConsulServiceDiscovery.java
@@ -0,0 +1,104 @@
+/**
+ * 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.cloud;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import com.orbitz.consul.Consul;
+import com.orbitz.consul.model.catalog.CatalogService;
+import com.orbitz.consul.model.health.ServiceHealth;
+import com.orbitz.consul.option.CatalogOptions;
+import com.orbitz.consul.option.ImmutableCatalogOptions;
+import org.apache.camel.cloud.ServiceDefinition;
+import org.apache.camel.component.consul.ConsulConfiguration;
+import org.apache.camel.impl.cloud.DefaultServiceDefinition;
+import org.apache.camel.impl.cloud.DefaultServiceDiscovery;
+import org.apache.camel.impl.cloud.DefaultServiceHealth;
+import org.apache.camel.util.ObjectHelper;
+
+public final class ConsulServiceDiscovery extends DefaultServiceDiscovery {
+    private final Consul client;
+    private final CatalogOptions catalogOptions;
+
+    public ConsulServiceDiscovery(ConsulConfiguration configuration) throws Exception {
+        this.client = configuration.createConsulClient();
+
+        ImmutableCatalogOptions.Builder builder = ImmutableCatalogOptions.builder();
+        if (ObjectHelper.isNotEmpty(configuration.getDc())) {
+            builder.datacenter(configuration.getDc());
+        }
+        if (ObjectHelper.isNotEmpty(configuration.getTags())) {
+            configuration.getTags().forEach(builder::tag);
+        }
+
+        catalogOptions = builder.build();
+    }
+
+    @Override
+    public List<ServiceDefinition> getUpdatedListOfServices(String name) {
+        List<CatalogService> services = client.catalogClient()
+            .getService(name, catalogOptions)
+            .getResponse();
+        List<ServiceHealth> healths = client.healthClient()
+            .getAllServiceInstances(name, catalogOptions)
+            .getResponse();
+
+        return services.stream()
+            .map(service -> newService(name, service, healths))
+            .collect(Collectors.toList());
+    }
+
+    // *************************
+    // Helpers
+    // *************************
+
+    private boolean isHealthy(ServiceHealth serviceHealth) {
+        return serviceHealth.getChecks().stream().allMatch(
+            check -> ObjectHelper.equal(check.getStatus(), "passing", true)
+        );
+    }
+
+    private ServiceDefinition newService(String serviceName, CatalogService service, List<ServiceHealth> serviceHealthList) {
+        Map<String, String> meta = new HashMap<>();
+        ObjectHelper.ifNotEmpty(service.getServiceId(), val -> meta.put("service_id", val));
+        ObjectHelper.ifNotEmpty(service.getNode(), val -> meta.put("node", val));
+        ObjectHelper.ifNotEmpty(service.getServiceName(), val -> meta.put("service_name", val));
+
+        List<String> tags = service.getServiceTags();
+        if (tags != null) {
+            for (String tag : service.getServiceTags()) {
+                String[] items = tag.split("=");
+                if (items.length == 1) {
+                    meta.put(items[0], items[0]);
+                } else if (items.length == 2) {
+                    meta.put(items[0], items[1]);
+                }
+            }
+        }
+
+        return new DefaultServiceDefinition(
+            serviceName,
+            service.getServiceAddress(),
+            service.getServicePort(),
+            meta,
+            new DefaultServiceHealth(serviceHealthList.stream().allMatch(this::isHealthy))
+        );
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/a811f400/components/camel-consul/src/main/java/org/apache/camel/component/consul/cloud/ConsulServiceDiscoveryFactory.java
----------------------------------------------------------------------
diff --git a/components/camel-consul/src/main/java/org/apache/camel/component/consul/cloud/ConsulServiceDiscoveryFactory.java b/components/camel-consul/src/main/java/org/apache/camel/component/consul/cloud/ConsulServiceDiscoveryFactory.java
new file mode 100644
index 0000000..9207d3e
--- /dev/null
+++ b/components/camel-consul/src/main/java/org/apache/camel/component/consul/cloud/ConsulServiceDiscoveryFactory.java
@@ -0,0 +1,124 @@
+/**
+ * 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.cloud;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.cloud.ServiceDiscovery;
+import org.apache.camel.cloud.ServiceDiscoveryFactory;
+import org.apache.camel.component.consul.ConsulConfiguration;
+import org.apache.camel.util.jsse.SSLContextParameters;
+
+public class ConsulServiceDiscoveryFactory implements ServiceDiscoveryFactory {
+    private final ConsulConfiguration configuration;
+
+    public ConsulServiceDiscoveryFactory() {
+        this.configuration = new ConsulConfiguration();
+    }
+
+    // *************************************************************************
+    // Properties
+    // *************************************************************************
+
+    public String getUrl() {
+        return configuration.getUrl();
+    }
+
+    public void setUrl(String url) {
+        configuration.setUrl(url);
+    }
+
+    public String getDc() {
+        return configuration.getDc();
+    }
+
+    public void setDc(String dc) {
+        configuration.setDc(dc);
+    }
+
+    public SSLContextParameters getSslContextParameters() {
+        return configuration.getSslContextParameters();
+    }
+
+    public void setSslContextParameters(SSLContextParameters sslContextParameters) {
+        configuration.setSslContextParameters(sslContextParameters);
+    }
+
+    public String getAclToken() {
+        return configuration.getAclToken();
+    }
+
+    public void setAclToken(String aclToken) {
+        configuration.setAclToken(aclToken);
+    }
+
+    public String getUserName() {
+        return configuration.getUserName();
+    }
+
+    public void setUserName(String userName) {
+        configuration.setUserName(userName);
+    }
+
+    public String getPassword() {
+        return configuration.getPassword();
+    }
+
+    public void setPassword(String password) {
+        configuration.setPassword(password);
+    }
+
+    public Long getConnectTimeoutMillis() {
+        return configuration.getConnectTimeoutMillis();
+    }
+
+    public void setConnectTimeoutMillis(Long connectTimeoutMillis) {
+        configuration.setConnectTimeoutMillis(connectTimeoutMillis);
+    }
+
+    public Long getReadTimeoutMillis() {
+        return configuration.getReadTimeoutMillis();
+    }
+
+    public void setReadTimeoutMillis(Long readTimeoutMillis) {
+        configuration.setReadTimeoutMillis(readTimeoutMillis);
+    }
+
+    public Long getWriteTimeoutMillis() {
+        return configuration.getWriteTimeoutMillis();
+    }
+
+    public void setWriteTimeoutMillis(Long writeTimeoutMillis) {
+        configuration.setWriteTimeoutMillis(writeTimeoutMillis);
+    }
+
+    public Integer getBlockSeconds() {
+        return configuration.getBlockSeconds();
+    }
+
+    public void setBlockSeconds(Integer blockSeconds) {
+        configuration.setBlockSeconds(blockSeconds);
+    }
+
+    // *************************************************************************
+    // Factory
+    // *************************************************************************
+
+    @Override
+    public ServiceDiscovery newInstance(CamelContext camelContext) throws Exception {
+        return new ConsulServiceDiscovery(configuration);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/a811f400/components/camel-consul/src/main/java/org/apache/camel/component/consul/processor/remote/ConsulServiceCallProcessor.java
----------------------------------------------------------------------
diff --git a/components/camel-consul/src/main/java/org/apache/camel/component/consul/processor/remote/ConsulServiceCallProcessor.java b/components/camel-consul/src/main/java/org/apache/camel/component/consul/processor/remote/ConsulServiceCallProcessor.java
deleted file mode 100644
index 7d98a8e..0000000
--- a/components/camel-consul/src/main/java/org/apache/camel/component/consul/processor/remote/ConsulServiceCallProcessor.java
+++ /dev/null
@@ -1,43 +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.processor.remote;
-
-import org.apache.camel.ExchangePattern;
-import org.apache.camel.component.consul.ConsulConfiguration;
-import org.apache.camel.impl.remote.DefaultServiceCallProcessor;
-import org.apache.camel.spi.ProcessorFactory;
-import org.apache.camel.spi.ServiceCallServer;
-import org.apache.camel.spi.ServiceCallServerListStrategy;
-
-/**
- * {@link ProcessorFactory} that creates the Consul implementation of the ServiceCall EIP.
- */
-public class ConsulServiceCallProcessor extends DefaultServiceCallProcessor<ServiceCallServer> {
-    public ConsulServiceCallProcessor(String name, String scheme, String uri, ExchangePattern exchangePattern, ConsulConfiguration conf) {
-        super(name, scheme, uri, exchangePattern);
-    }
-
-    @Override
-    public void setServerListStrategy(ServiceCallServerListStrategy<ServiceCallServer> serverListStrategy) {
-        if (!(serverListStrategy instanceof ConsulServiceCallServerListStrategy)) {
-            throw new IllegalArgumentException("ServerListStrategy is not an instance of ConsulServiceCallServerListStrategy");
-        }
-
-        super.setServerListStrategy(serverListStrategy);
-    }
-}

http://git-wip-us.apache.org/repos/asf/camel/blob/a811f400/components/camel-consul/src/main/java/org/apache/camel/component/consul/processor/remote/ConsulServiceCallProcessorFactory.java
----------------------------------------------------------------------
diff --git a/components/camel-consul/src/main/java/org/apache/camel/component/consul/processor/remote/ConsulServiceCallProcessorFactory.java b/components/camel-consul/src/main/java/org/apache/camel/component/consul/processor/remote/ConsulServiceCallProcessorFactory.java
deleted file mode 100644
index 064fac2..0000000
--- a/components/camel-consul/src/main/java/org/apache/camel/component/consul/processor/remote/ConsulServiceCallProcessorFactory.java
+++ /dev/null
@@ -1,67 +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.processor.remote;
-
-import java.util.Map;
-import java.util.Optional;
-
-import org.apache.camel.ExchangePattern;
-import org.apache.camel.component.consul.ConsulConfiguration;
-import org.apache.camel.impl.remote.DefaultServiceCallProcessor;
-import org.apache.camel.impl.remote.DefaultServiceCallProcessorFactory;
-import org.apache.camel.spi.ProcessorFactory;
-import org.apache.camel.spi.RouteContext;
-import org.apache.camel.spi.ServiceCallServer;
-import org.apache.camel.spi.ServiceCallServerListStrategy;
-import org.apache.camel.util.ObjectHelper;
-
-/**
- * {@link ProcessorFactory} that creates the Consul implementation of the ServiceCall EIP.
- */
-public class ConsulServiceCallProcessorFactory extends DefaultServiceCallProcessorFactory<ConsulConfiguration, ServiceCallServer> {
-    @Override
-    protected ConsulConfiguration createConfiguration(RouteContext routeContext) throws Exception {
-        return new ConsulConfiguration(routeContext.getCamelContext());
-    }
-
-    @Override
-    protected DefaultServiceCallProcessor createProcessor(
-            String name,
-            String component,
-            String uri,
-            ExchangePattern mep,
-            ConsulConfiguration conf,
-            Map<String, String> properties) throws Exception {
-
-        return new ConsulServiceCallProcessor(name, component, uri, mep, conf);
-    }
-
-    @Override
-    protected Optional<ServiceCallServerListStrategy> builtInServerListStrategy(ConsulConfiguration conf, String name) throws Exception {
-        ServiceCallServerListStrategy strategy = null;
-        if (ObjectHelper.equal("ondemand", name, true)) {
-            strategy = new ConsulServiceCallServerListStrategies.OnDemand(conf);
-        }
-
-        return Optional.ofNullable(strategy);
-    }
-
-    @Override
-    protected ServiceCallServerListStrategy<ServiceCallServer> createDefaultServerListStrategy(ConsulConfiguration conf) throws Exception {
-        return new ConsulServiceCallServerListStrategies.OnDemand(conf);
-    }
-}

http://git-wip-us.apache.org/repos/asf/camel/blob/a811f400/components/camel-consul/src/main/java/org/apache/camel/component/consul/processor/remote/ConsulServiceCallServerListStrategies.java
----------------------------------------------------------------------
diff --git a/components/camel-consul/src/main/java/org/apache/camel/component/consul/processor/remote/ConsulServiceCallServerListStrategies.java b/components/camel-consul/src/main/java/org/apache/camel/component/consul/processor/remote/ConsulServiceCallServerListStrategies.java
deleted file mode 100644
index 81f95ff..0000000
--- a/components/camel-consul/src/main/java/org/apache/camel/component/consul/processor/remote/ConsulServiceCallServerListStrategies.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.processor.remote;
-
-import java.util.List;
-import java.util.stream.Collectors;
-
-import com.orbitz.consul.model.catalog.CatalogService;
-import com.orbitz.consul.model.health.ServiceHealth;
-import org.apache.camel.component.consul.ConsulConfiguration;
-import org.apache.camel.spi.ServiceCallServer;
-
-public final class ConsulServiceCallServerListStrategies {
-    private ConsulServiceCallServerListStrategies() {
-    }
-
-    public static final class OnDemand extends ConsulServiceCallServerListStrategy {
-        public OnDemand(ConsulConfiguration configuration) throws Exception {
-            super(configuration);
-        }
-
-        @Override
-        public List<ServiceCallServer> getUpdatedListOfServers(String name) {
-            List<CatalogService> services = getCatalogClient()
-                .getService(name, getCatalogOptions())
-                .getResponse();
-
-            List<ServiceHealth> healths = getHealthClient()
-                .getAllServiceInstances(name, getCatalogOptions())
-                .getResponse();
-
-            return services.stream()
-                .filter(service -> !hasFailingChecks(service, healths))
-                .map(this::newServer)
-                .collect(Collectors.toList());
-        }
-
-        @Override
-        public String toString() {
-            return "OnDemand";
-        }
-    }
-
-    // *************************************************************************
-    // Helpers
-    // *************************************************************************
-
-    public static ConsulServiceCallServerListStrategy onDemand(ConsulConfiguration configuration) throws Exception {
-        return new OnDemand(configuration);
-    }
-}

http://git-wip-us.apache.org/repos/asf/camel/blob/a811f400/components/camel-consul/src/main/java/org/apache/camel/component/consul/processor/remote/ConsulServiceCallServerListStrategy.java
----------------------------------------------------------------------
diff --git a/components/camel-consul/src/main/java/org/apache/camel/component/consul/processor/remote/ConsulServiceCallServerListStrategy.java b/components/camel-consul/src/main/java/org/apache/camel/component/consul/processor/remote/ConsulServiceCallServerListStrategy.java
deleted file mode 100644
index 116b2fc..0000000
--- a/components/camel-consul/src/main/java/org/apache/camel/component/consul/processor/remote/ConsulServiceCallServerListStrategy.java
+++ /dev/null
@@ -1,128 +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.processor.remote;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import com.orbitz.consul.CatalogClient;
-import com.orbitz.consul.Consul;
-import com.orbitz.consul.HealthClient;
-import com.orbitz.consul.model.catalog.CatalogService;
-import com.orbitz.consul.model.health.HealthCheck;
-import com.orbitz.consul.model.health.ServiceHealth;
-import com.orbitz.consul.option.CatalogOptions;
-import com.orbitz.consul.option.ImmutableCatalogOptions;
-import org.apache.camel.component.consul.ConsulConfiguration;
-import org.apache.camel.impl.remote.DefaultServiceCallServer;
-import org.apache.camel.impl.remote.DefaultServiceCallServerListStrategy;
-import org.apache.camel.spi.ServiceCallServer;
-import org.apache.camel.util.ObjectHelper;
-
-import static org.apache.camel.util.ObjectHelper.ifNotEmpty;
-
-
-abstract class ConsulServiceCallServerListStrategy extends DefaultServiceCallServerListStrategy<ServiceCallServer> {
-    private final Consul client;
-    private final CatalogOptions catalogOptions;
-
-    ConsulServiceCallServerListStrategy(ConsulConfiguration configuration) throws Exception {
-        this.client = configuration.createConsulClient();
-
-        ImmutableCatalogOptions.Builder builder = ImmutableCatalogOptions.builder();
-        if (ObjectHelper.isNotEmpty(configuration.getDc())) {
-            builder.datacenter(configuration.getDc());
-        }
-        if (ObjectHelper.isNotEmpty(configuration.getTags())) {
-            configuration.getTags().forEach(builder::tag);
-        }
-
-        catalogOptions = builder.build();
-    }
-
-    @Override
-    public String toString() {
-        return "ConsulServiceCallServerListStrategy";
-    }
-
-    // *************************
-    // Getter
-    // *************************
-
-    protected Consul getClient() {
-        return client;
-    }
-
-    protected CatalogClient getCatalogClient() {
-        return client.catalogClient();
-    }
-
-    protected HealthClient getHealthClient() {
-        return client.healthClient();
-    }
-
-    protected CatalogOptions getCatalogOptions() {
-        return catalogOptions;
-    }
-
-    // *************************
-    // Helpers
-    // *************************
-
-    protected boolean isNotHealthy(HealthCheck check) {
-        final String status = check.getStatus();
-        return status != null && !status.equalsIgnoreCase("passing");
-    }
-
-    protected boolean isNotHealthy(ServiceHealth health) {
-        return health.getChecks().stream().anyMatch(this::isNotHealthy);
-    }
-
-    protected boolean isCheckOnService(ServiceHealth check, CatalogService service) {
-        return check.getService().getService().equalsIgnoreCase(service.getServiceName());
-    }
-
-    protected boolean hasFailingChecks(CatalogService service, List<ServiceHealth> healths) {
-        return healths.stream().anyMatch(health -> isCheckOnService(health, service) && isNotHealthy(health));
-    }
-
-    protected ServiceCallServer newServer(CatalogService service) {
-        Map<String, String> meta = new HashMap<>();
-        ifNotEmpty(service.getServiceId(), val -> meta.put("service_id", val));
-        ifNotEmpty(service.getNode(), val -> meta.put("node", val));
-        ifNotEmpty(service.getServiceName(), val -> meta.put("service_name", val));
-
-        List<String> tags = service.getServiceTags();
-        if (tags != null) {
-            for (String tag : service.getServiceTags()) {
-                String[] items = tag.split("=");
-                if (items.length == 1) {
-                    meta.put(items[0], items[0]);
-                } else if (items.length == 2) {
-                    meta.put(items[0], items[1]);
-                }
-            }
-        }
-
-        return new DefaultServiceCallServer(
-            service.getServiceAddress(),
-            service.getServicePort(),
-            meta
-        );
-    }
-}

http://git-wip-us.apache.org/repos/asf/camel/blob/a811f400/components/camel-consul/src/main/resources/META-INF/services/org/apache/camel/cloud/consul-service-discovery
----------------------------------------------------------------------
diff --git a/components/camel-consul/src/main/resources/META-INF/services/org/apache/camel/cloud/consul-service-discovery b/components/camel-consul/src/main/resources/META-INF/services/org/apache/camel/cloud/consul-service-discovery
new file mode 100644
index 0000000..b8019a2
--- /dev/null
+++ b/components/camel-consul/src/main/resources/META-INF/services/org/apache/camel/cloud/consul-service-discovery
@@ -0,0 +1,17 @@
+#
+# 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.
+#
+class=org.apache.camel.component.consul.cloud.ConsulServiceDiscoveryFactory

http://git-wip-us.apache.org/repos/asf/camel/blob/a811f400/components/camel-consul/src/main/resources/META-INF/services/org/apache/camel/model/ServiceCallDefinition
----------------------------------------------------------------------
diff --git a/components/camel-consul/src/main/resources/META-INF/services/org/apache/camel/model/ServiceCallDefinition b/components/camel-consul/src/main/resources/META-INF/services/org/apache/camel/model/ServiceCallDefinition
deleted file mode 100644
index 3082d38..0000000
--- a/components/camel-consul/src/main/resources/META-INF/services/org/apache/camel/model/ServiceCallDefinition
+++ /dev/null
@@ -1,18 +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.
-#
-
-class=org.apache.camel.component.consul.processor.remote.ConsulServiceCallProcessorFactory

http://git-wip-us.apache.org/repos/asf/camel/blob/a811f400/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/ConsulServiceCallRouteTest.java
----------------------------------------------------------------------
diff --git a/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/ConsulServiceCallRouteTest.java b/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/ConsulServiceCallRouteTest.java
new file mode 100644
index 0000000..c32ec3e
--- /dev/null
+++ b/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/ConsulServiceCallRouteTest.java
@@ -0,0 +1,118 @@
+/**
+ * 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.cloud;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.orbitz.consul.AgentClient;
+import com.orbitz.consul.model.agent.ImmutableRegistration;
+import com.orbitz.consul.model.agent.Registration;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.cloud.ServiceDiscovery;
+import org.apache.camel.component.consul.ConsulConfiguration;
+import org.apache.camel.component.consul.ConsulTestSupport;
+import org.junit.Test;
+
+public class ConsulServiceCallRouteTest extends ConsulTestSupport {
+    private static final String SERVICE_NAME = "http-service";
+    private static final int SERVICE_COUNT = 5;
+    private static final int SERVICE_PORT_BASE = 8080;
+
+    private AgentClient client;
+    private List<Registration> registrations;
+    private List<String> expectedBodies;
+
+    // *************************************************************************
+    // Setup / tear down
+    // *************************************************************************
+
+    @Override
+    protected void doPreSetup() throws Exception {
+        client = getConsul().agentClient();
+
+        registrations = new ArrayList<>(SERVICE_COUNT);
+        expectedBodies = new ArrayList<>(SERVICE_COUNT);
+
+        for (int i = 0; i < SERVICE_COUNT; i++) {
+            Registration r = ImmutableRegistration.builder()
+                .id("service-" + i)
+                .name(SERVICE_NAME)
+                .address("127.0.0.1")
+                .port(SERVICE_PORT_BASE + i)
+                .build();
+
+            client.register(r);
+
+            registrations.add(r);
+            expectedBodies.add("ping on " + r.getPort().get());
+        }
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        super.tearDown();
+
+
+        registrations.forEach(r -> client.deregister(r.getId()));
+    }
+
+    // *************************************************************************
+    // Test
+    // *************************************************************************
+
+    @Test
+    public void testServiceCall() throws Exception {
+        getMockEndpoint("mock:result").expectedMessageCount(SERVICE_COUNT);
+        getMockEndpoint("mock:result").expectedBodiesReceivedInAnyOrder(expectedBodies);
+
+        registrations.forEach(r -> template.sendBody("direct:start", "ping"));
+
+        assertMockEndpointsSatisfied();
+    }
+
+    // *************************************************************************
+    // Route
+    // *************************************************************************
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                ConsulConfiguration configuration = new ConsulConfiguration(null);
+                ServiceDiscovery discovery = new ConsulServiceDiscovery(configuration);
+
+                from("direct:start")
+                    .serviceCall()
+                        .name(SERVICE_NAME)
+                        .component("http")
+                        .serviceDiscovery(discovery)
+                        .end()
+                    .to("log:org.apache.camel.component.consul.processor.service?level=INFO&showAll=true&multiline=true")
+                    .to("mock:result");
+
+                registrations.forEach(r ->
+                    fromF("jetty:http://%s:%d", r.getAddress().get(), r.getPort().get())
+                        .transform().simple("${in.body} on " + r.getPort().get())
+                );
+            }
+        };
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/a811f400/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/ConsulServiceDiscoveryTest.java
----------------------------------------------------------------------
diff --git a/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/ConsulServiceDiscoveryTest.java b/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/ConsulServiceDiscoveryTest.java
new file mode 100644
index 0000000..8046f1d
--- /dev/null
+++ b/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/ConsulServiceDiscoveryTest.java
@@ -0,0 +1,90 @@
+/**
+ * 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.cloud;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.orbitz.consul.AgentClient;
+import com.orbitz.consul.Consul;
+import com.orbitz.consul.model.agent.ImmutableRegistration;
+import com.orbitz.consul.model.agent.Registration;
+import org.apache.camel.cloud.ServiceDefinition;
+import org.apache.camel.cloud.ServiceDiscovery;
+import org.apache.camel.component.consul.ConsulConfiguration;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class ConsulServiceDiscoveryTest {
+    private AgentClient client;
+    private List<Registration> registrations;
+
+    @Before
+    public void setUp() throws Exception {
+        client = Consul.builder().build().agentClient();
+        registrations = new ArrayList<>(3);
+
+        for (int i = 0; i < 3; i++) {
+            Registration r = ImmutableRegistration.builder()
+                .id("service-" + i)
+                .name("my-service")
+                .address("127.0.0.1")
+                .addTags("a-tag")
+                .addTags("key1=value1")
+                .addTags("key2=value2")
+                .port(9000 + i)
+                .build();
+
+            client.register(r);
+            registrations.add(r);
+        }
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        registrations.forEach(r -> client.deregister(r.getId()));
+    }
+
+    // *************************************************************************
+    // Test
+    // *************************************************************************
+
+    @Test
+    public void testServiceDiscovery() throws Exception {
+        ConsulConfiguration configuration = new ConsulConfiguration(null);
+        ServiceDiscovery discovery = new ConsulServiceDiscovery(configuration);
+
+        List<ServiceDefinition> services = discovery.getUpdatedListOfServices("my-service");
+        assertNotNull(services);
+        assertEquals(3, services.size());
+
+        for (ServiceDefinition service : services) {
+            assertFalse(service.getMetadata().isEmpty());
+            assertTrue(service.getMetadata().containsKey("service_name"));
+            assertTrue(service.getMetadata().containsKey("service_id"));
+            assertTrue(service.getMetadata().containsKey("a-tag"));
+            assertTrue(service.getMetadata().containsKey("key1"));
+            assertTrue(service.getMetadata().containsKey("key2"));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/a811f400/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/SpringConsulDefaultServiceCallRouteTest.java
----------------------------------------------------------------------
diff --git a/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/SpringConsulDefaultServiceCallRouteTest.java b/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/SpringConsulDefaultServiceCallRouteTest.java
new file mode 100644
index 0000000..05b28d7
--- /dev/null
+++ b/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/SpringConsulDefaultServiceCallRouteTest.java
@@ -0,0 +1,28 @@
+/**
+ * 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.cloud;
+
+import org.springframework.context.support.AbstractApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+public class SpringConsulDefaultServiceCallRouteTest extends SpringConsulServiceCallRouteTest {
+    @Override
+    protected AbstractApplicationContext createApplicationContext() {
+        return new ClassPathXmlApplicationContext("org/apache/camel/component/consul/cloud/SpringConsulDefaultServiceCallRouteTest.xml");
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/a811f400/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/SpringConsulRibbonServiceCallRouteTest.java
----------------------------------------------------------------------
diff --git a/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/SpringConsulRibbonServiceCallRouteTest.java b/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/SpringConsulRibbonServiceCallRouteTest.java
new file mode 100644
index 0000000..70eebfb
--- /dev/null
+++ b/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/SpringConsulRibbonServiceCallRouteTest.java
@@ -0,0 +1,28 @@
+/**
+ * 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.cloud;
+
+import org.springframework.context.support.AbstractApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+public class SpringConsulRibbonServiceCallRouteTest extends SpringConsulServiceCallRouteTest {
+    @Override
+    protected AbstractApplicationContext createApplicationContext() {
+        return new ClassPathXmlApplicationContext("org/apache/camel/component/consul/cloud/SpringConsulRibbonServiceCallRouteTest.xml");
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/a811f400/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/SpringConsulServiceCallRouteTest.java
----------------------------------------------------------------------
diff --git a/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/SpringConsulServiceCallRouteTest.java b/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/SpringConsulServiceCallRouteTest.java
new file mode 100644
index 0000000..81517be
--- /dev/null
+++ b/components/camel-consul/src/test/java/org/apache/camel/component/consul/cloud/SpringConsulServiceCallRouteTest.java
@@ -0,0 +1,96 @@
+/**
+ * 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.cloud;
+
+import java.util.Arrays;
+import java.util.List;
+
+import com.orbitz.consul.AgentClient;
+import com.orbitz.consul.Consul;
+import com.orbitz.consul.model.agent.ImmutableRegistration;
+import com.orbitz.consul.model.agent.Registration;
+import org.apache.camel.test.spring.CamelSpringTestSupport;
+import org.junit.Test;
+
+public abstract class SpringConsulServiceCallRouteTest extends CamelSpringTestSupport {
+    private AgentClient client;
+    private List<Registration> registrations;
+
+    // *************************************************************************
+    // Setup / tear down
+    // *************************************************************************
+
+    @Override
+    public void doPreSetup() throws Exception {
+        this.client = Consul.builder().build().agentClient();
+        this.registrations = Arrays.asList(
+            ImmutableRegistration.builder()
+                .id("service-1")
+                .name("http-service-1")
+                .address("127.0.0.1")
+                .port(9091)
+                .build(),
+            ImmutableRegistration.builder()
+                .id("service-2")
+                .name("http-service-1")
+                .address("127.0.0.1")
+                .port(9092)
+                .build(),
+            ImmutableRegistration.builder()
+                .id("service-3")
+                .name("http-service-2")
+                .address("127.0.0.1")
+                .port(9093)
+                .build(),
+            ImmutableRegistration.builder()
+                .id("service-4")
+                .name("http-service-2")
+                .address("127.0.0.1")
+                .port(9094)
+                .build()
+        );
+
+        this.registrations.forEach(client::register);
+        super.doPreSetup();
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        super.tearDown();
+        registrations.forEach(r -> client.deregister(r.getId()));
+    }
+
+    // *************************************************************************
+    // Test
+    // *************************************************************************
+
+    @Test
+    public void testServiceCall() throws Exception {
+        getMockEndpoint("mock:result-1").expectedMessageCount(2);
+        getMockEndpoint("mock:result-1").expectedBodiesReceivedInAnyOrder("service-1 9091", "service-1 9092");
+        getMockEndpoint("mock:result-2").expectedMessageCount(2);
+        getMockEndpoint("mock:result-2").expectedBodiesReceivedInAnyOrder("service-2 9093", "service-2 9094");
+
+        template.sendBody("direct:start", "service-1");
+        template.sendBody("direct:start", "service-1");
+        template.sendBody("direct:start", "service-2");
+        template.sendBody("direct:start", "service-2");
+
+        assertMockEndpointsSatisfied();
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/a811f400/components/camel-consul/src/test/java/org/apache/camel/component/consul/policy/ConsulRoutePolicyMain.java
----------------------------------------------------------------------
diff --git a/components/camel-consul/src/test/java/org/apache/camel/component/consul/policy/ConsulRoutePolicyMain.java b/components/camel-consul/src/test/java/org/apache/camel/component/consul/policy/ConsulRoutePolicyMain.java
index d5831c1..447f5b3 100644
--- a/components/camel-consul/src/test/java/org/apache/camel/component/consul/policy/ConsulRoutePolicyMain.java
+++ b/components/camel-consul/src/test/java/org/apache/camel/component/consul/policy/ConsulRoutePolicyMain.java
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.camel.component.consul.policy;
 
 import org.apache.camel.builder.RouteBuilder;

http://git-wip-us.apache.org/repos/asf/camel/blob/a811f400/components/camel-consul/src/test/java/org/apache/camel/component/consul/processor/remote/ConsulServiceCallRouteTest.java
----------------------------------------------------------------------
diff --git a/components/camel-consul/src/test/java/org/apache/camel/component/consul/processor/remote/ConsulServiceCallRouteTest.java b/components/camel-consul/src/test/java/org/apache/camel/component/consul/processor/remote/ConsulServiceCallRouteTest.java
deleted file mode 100644
index a76580b..0000000
--- a/components/camel-consul/src/test/java/org/apache/camel/component/consul/processor/remote/ConsulServiceCallRouteTest.java
+++ /dev/null
@@ -1,114 +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.processor.remote;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import com.orbitz.consul.AgentClient;
-import com.orbitz.consul.model.agent.ImmutableRegistration;
-import com.orbitz.consul.model.agent.Registration;
-import org.apache.camel.RoutesBuilder;
-import org.apache.camel.builder.RouteBuilder;
-import org.apache.camel.component.consul.ConsulTestSupport;
-import org.junit.Ignore;
-import org.junit.Test;
-
-@Ignore("A consul server is needed for this test ")
-public class ConsulServiceCallRouteTest extends ConsulTestSupport {
-    private static final String SERVICE_NAME = "http-service";
-    private static final int SERVICE_COUNT = 5;
-    private static final int SERVICE_PORT_BASE = 8080;
-
-    private AgentClient client;
-    private List<Registration> registrations;
-    private List<String> expectedBodies;
-
-    // *************************************************************************
-    // Setup / tear down
-    // *************************************************************************
-
-    @Override
-    protected void doPreSetup() throws Exception {
-        client = getConsul().agentClient();
-
-        registrations = new ArrayList<>(SERVICE_COUNT);
-        expectedBodies = new ArrayList<>(SERVICE_COUNT);
-
-        for (int i = 0; i < SERVICE_COUNT; i++) {
-            Registration r = ImmutableRegistration.builder()
-                .id("service-" + i)
-                .name(SERVICE_NAME)
-                .address("127.0.0.1")
-                .port(SERVICE_PORT_BASE + i)
-                .build();
-
-            client.register(r);
-
-            registrations.add(r);
-            expectedBodies.add("ping on " + r.getPort().get());
-        }
-    }
-
-    @Override
-    public void tearDown() throws Exception {
-        super.tearDown();
-        registrations.forEach(r -> client.deregister(r.getId()));
-    }
-
-    // *************************************************************************
-    // Test
-    // *************************************************************************
-
-    @Test
-    public void testServiceCall() throws Exception {
-        getMockEndpoint("mock:result").expectedMessageCount(SERVICE_COUNT);
-        getMockEndpoint("mock:result").expectedBodiesReceivedInAnyOrder(expectedBodies);
-
-        registrations.forEach(r -> template.sendBody("direct:start", "ping"));
-
-        assertMockEndpointsSatisfied();
-    }
-
-    // *************************************************************************
-    // Route
-    // *************************************************************************
-
-    @Override
-    protected RoutesBuilder createRouteBuilder() throws Exception {
-        return new RouteBuilder() {
-            @Override
-            public void configure() throws Exception {
-                from("direct:start")
-                    .serviceCall()
-                        .name(SERVICE_NAME)
-                        .consulConfiguration()
-                            .component("http")
-                            .loadBalancer("roundrobin")
-                            .serverListStrategy("ondemand")
-                        .end()
-                    .to("log:org.apache.camel.component.consul.processor.service?level=INFO&showAll=true&multiline=true")
-                    .to("mock:result");
-
-                registrations.forEach(r ->
-                    fromF("jetty:http://%s:%d", r.getAddress().get(), r.getPort().get())
-                        .transform().simple("${in.body} on " + r.getPort().get())
-                );
-            }
-        };
-    }
-}

http://git-wip-us.apache.org/repos/asf/camel/blob/a811f400/components/camel-consul/src/test/java/org/apache/camel/component/consul/processor/remote/ConsulServiceCallServerListStrategiesTest.java
----------------------------------------------------------------------
diff --git a/components/camel-consul/src/test/java/org/apache/camel/component/consul/processor/remote/ConsulServiceCallServerListStrategiesTest.java b/components/camel-consul/src/test/java/org/apache/camel/component/consul/processor/remote/ConsulServiceCallServerListStrategiesTest.java
deleted file mode 100644
index 65738e0..0000000
--- a/components/camel-consul/src/test/java/org/apache/camel/component/consul/processor/remote/ConsulServiceCallServerListStrategiesTest.java
+++ /dev/null
@@ -1,92 +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.processor.remote;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import com.orbitz.consul.AgentClient;
-import com.orbitz.consul.Consul;
-import com.orbitz.consul.model.agent.ImmutableRegistration;
-import com.orbitz.consul.model.agent.Registration;
-import org.apache.camel.component.consul.ConsulConfiguration;
-import org.apache.camel.spi.ServiceCallServer;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-@Ignore("A consul server is needed for this test ")
-public class ConsulServiceCallServerListStrategiesTest {
-    private AgentClient client;
-    private List<Registration> registrations;
-
-    @Before
-    public void setUp() throws Exception {
-        client = Consul.builder().build().agentClient();
-        registrations = new ArrayList<>(3);
-
-        for (int i = 0; i < 3; i++) {
-            Registration r = ImmutableRegistration.builder()
-                .id("service-" + i)
-                .name("my-service")
-                .address("127.0.0.1")
-                .addTags("a-tag")
-                .addTags("key1=value1")
-                .addTags("key2=value2")
-                .port(9000 + i)
-                .build();
-
-            client.register(r);
-            registrations.add(r);
-        }
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        registrations.forEach(r -> client.deregister(r.getId()));
-    }
-
-    // *************************************************************************
-    // Test
-    // *************************************************************************
-
-    @Test
-    public void testOnDemand() throws Exception {
-        ConsulConfiguration configuration = new ConsulConfiguration(null);
-        ConsulServiceCallServerListStrategy strategy = ConsulServiceCallServerListStrategies.onDemand(configuration);
-
-        List<ServiceCallServer> servers = strategy.getUpdatedListOfServers("my-service");
-        assertNotNull(servers);
-        assertEquals(3, servers.size());
-
-        for (ServiceCallServer server : servers) {
-            assertFalse(server.getMetadata().isEmpty());
-            assertTrue(server.getMetadata().containsKey("service_name"));
-            assertTrue(server.getMetadata().containsKey("service_id"));
-            assertTrue(server.getMetadata().containsKey("a-tag"));
-            assertTrue(server.getMetadata().containsKey("key1"));
-            assertTrue(server.getMetadata().containsKey("key2"));
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/camel/blob/a811f400/components/camel-consul/src/test/resources/org/apache/camel/component/consul/cloud/SpringConsulDefaultServiceCallRouteTest.xml
----------------------------------------------------------------------
diff --git a/components/camel-consul/src/test/resources/org/apache/camel/component/consul/cloud/SpringConsulDefaultServiceCallRouteTest.xml b/components/camel-consul/src/test/resources/org/apache/camel/component/consul/cloud/SpringConsulDefaultServiceCallRouteTest.xml
new file mode 100644
index 0000000..c4d0950
--- /dev/null
+++ b/components/camel-consul/src/test/resources/org/apache/camel/component/consul/cloud/SpringConsulDefaultServiceCallRouteTest.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+         http://www.springframework.org/schema/beans
+         http://www.springframework.org/schema/beans/spring-beans.xsd
+         http://camel.apache.org/schema/spring
+         http://camel.apache.org/schema/spring/camel-spring.xsd">
+
+  <camelContext xmlns="http://camel.apache.org/schema/spring">
+
+    <!-- shared config -->
+    <serviceCallConfiguration id="shared-config" serviceChooserRef="round-robin">
+      <consulServiceDiscovery readTimeoutMillis="1444" url="http://localhost:8500"/>
+    </serviceCallConfiguration>
+
+    <route>
+      <from uri="direct:start"/>
+      <choice>
+        <when>
+          <simple>${body} == 'service-1'</simple>
+          <serviceCall name="http-service-1">
+            <consulServiceDiscovery readTimeoutMillis="1222" url="http://localhost:8500"/>
+          </serviceCall>
+          <to uri="mock:result-1"/>
+        </when>
+        <when>
+          <simple>${body} == 'service-2'</simple>
+          <serviceCall name="http-service-2">
+            <consulServiceDiscovery readTimeoutMillis="1333" url="http://localhost:8500"/>
+          </serviceCall>
+          <to uri="mock:result-2"/>
+        </when>
+        <when>
+          <simple>${body} == 'service-3'</simple>
+          <serviceCall name="http-service-3" configurationRef="shared-config"/>
+          <to uri="mock:result-2"/>
+        </when>
+      </choice>
+    </route>
+
+    <route>
+      <from uri="jetty:http://localhost:9091"/>
+      <transform>
+        <simple>${body} 9091</simple>
+      </transform>
+    </route>
+
+    <route>
+      <from uri="jetty:http://localhost:9092"/>
+      <transform>
+        <simple>${body} 9092</simple>
+      </transform>
+    </route>
+
+    <route>
+      <from uri="jetty:http://localhost:9093"/>
+      <transform>
+        <simple>${body} 9093</simple>
+      </transform>
+    </route>
+
+    <route>
+      <from uri="jetty:http://localhost:9094"/>
+      <transform>
+        <simple>${body} 9094</simple>
+      </transform>
+    </route>
+  </camelContext>
+
+</beans>

http://git-wip-us.apache.org/repos/asf/camel/blob/a811f400/components/camel-consul/src/test/resources/org/apache/camel/component/consul/cloud/SpringConsulRibbonServiceCallRouteTest.xml
----------------------------------------------------------------------
diff --git a/components/camel-consul/src/test/resources/org/apache/camel/component/consul/cloud/SpringConsulRibbonServiceCallRouteTest.xml b/components/camel-consul/src/test/resources/org/apache/camel/component/consul/cloud/SpringConsulRibbonServiceCallRouteTest.xml
new file mode 100644
index 0000000..ac1b642
--- /dev/null
+++ b/components/camel-consul/src/test/resources/org/apache/camel/component/consul/cloud/SpringConsulRibbonServiceCallRouteTest.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+         http://www.springframework.org/schema/beans
+         http://www.springframework.org/schema/beans/spring-beans.xsd
+         http://camel.apache.org/schema/spring
+         http://camel.apache.org/schema/spring/camel-spring.xsd">
+
+  <camelContext xmlns="http://camel.apache.org/schema/spring">
+    <!--
+    <serviceCallConfiguration id="service-2">
+      <consulServiceDiscovery"/>
+    </serviceCallConfiguration>
+    -->
+
+    <route>
+      <from uri="direct:start"/>
+      <choice>
+        <when>
+          <simple>${body} == 'service-1'</simple>
+          <serviceCall name="http-service-1">
+            <consulServiceDiscovery readTimeoutMillis="1222" url="http://localhost:8500"/>
+            <ribbonLoadBalancer/>
+          </serviceCall>
+          <to uri="mock:result-1"/>
+        </when>
+        <when>
+          <simple>${body} == 'service-2'</simple>
+          <serviceCall name="http-service-2">
+            <consulServiceDiscovery readTimeoutMillis="1333" url="http://localhost:8500"/>
+            <ribbonLoadBalancer/>
+          </serviceCall>
+          <to uri="mock:result-2"/>
+        </when>
+      </choice>
+    </route>
+
+    <route>
+      <from uri="jetty:http://localhost:9091"/>
+      <transform>
+        <simple>${body} 9091</simple>
+      </transform>
+    </route>
+
+    <route>
+      <from uri="jetty:http://localhost:9092"/>
+      <transform>
+        <simple>${body} 9092</simple>
+      </transform>
+    </route>
+
+    <route>
+      <from uri="jetty:http://localhost:9093"/>
+      <transform>
+        <simple>${body} 9093</simple>
+      </transform>
+    </route>
+
+    <route>
+      <from uri="jetty:http://localhost:9094"/>
+      <transform>
+        <simple>${body} 9094</simple>
+      </transform>
+    </route>
+  </camelContext>
+
+</beans>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/a811f400/components/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
----------------------------------------------------------------------
diff --git a/components/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java b/components/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
index a4bb342..a5ce3f7 100644
--- a/components/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
+++ b/components/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
@@ -66,6 +66,7 @@ import org.apache.camel.model.RouteContextRefDefinition;
 import org.apache.camel.model.RouteDefinition;
 import org.apache.camel.model.RouteDefinitionHelper;
 import org.apache.camel.model.ThreadPoolProfileDefinition;
+import org.apache.camel.model.cloud.ServiceCallConfigurationDefinition;
 import org.apache.camel.model.dataformat.DataFormatsDefinition;
 import org.apache.camel.model.rest.RestConfigurationDefinition;
 import org.apache.camel.model.rest.RestContainer;
@@ -775,6 +776,10 @@ public abstract class AbstractCamelContextFactoryBean<T extends ModelCamelContex
 
     public abstract String getDependsOn();
 
+    public abstract List<AbstractCamelFactoryBean<?>> getBeansFactory();
+
+    public abstract List<?> getBeans();
+
     // Implementation methods
     // -------------------------------------------------------------------------
 
@@ -851,6 +856,15 @@ public abstract class AbstractCamelContextFactoryBean<T extends ModelCamelContex
         if (getRestConfiguration() != null) {
             ctx.setRestConfiguration(getRestConfiguration().asRestConfiguration(ctx));
         }
+        if (getBeans() != null) {
+            for (Object bean : getBeans()) {
+                if (bean instanceof ServiceCallConfigurationDefinition) {
+                    @SuppressWarnings("unchecked")
+                    ServiceCallConfigurationDefinition configuration = (ServiceCallConfigurationDefinition)bean;
+                    ctx.addServiceCallConfiguration(configuration.getId(), configuration);
+                }
+            }
+        }
     }
 
     protected void initThreadPoolProfiles(T context) throws Exception {

http://git-wip-us.apache.org/repos/asf/camel/blob/a811f400/components/camel-dns/src/main/java/org/apache/camel/component/dns/cloud/DnsServiceDiscovery.java
----------------------------------------------------------------------
diff --git a/components/camel-dns/src/main/java/org/apache/camel/component/dns/cloud/DnsServiceDiscovery.java b/components/camel-dns/src/main/java/org/apache/camel/component/dns/cloud/DnsServiceDiscovery.java
new file mode 100644
index 0000000..003fd8a
--- /dev/null
+++ b/components/camel-dns/src/main/java/org/apache/camel/component/dns/cloud/DnsServiceDiscovery.java
@@ -0,0 +1,102 @@
+/**
+ * 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.dns.cloud;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.cloud.ServiceDefinition;
+import org.apache.camel.component.dns.DnsConfiguration;
+import org.apache.camel.impl.cloud.DefaultServiceDefinition;
+import org.apache.camel.impl.cloud.DefaultServiceDiscovery;
+import org.apache.camel.util.ObjectHelper;
+import org.xbill.DNS.Lookup;
+import org.xbill.DNS.Record;
+import org.xbill.DNS.SRVRecord;
+import org.xbill.DNS.TextParseException;
+import org.xbill.DNS.Type;
+
+
+public final class DnsServiceDiscovery extends DefaultServiceDiscovery {
+    private static final Comparator<SRVRecord> COMPARATOR = comparator();
+    private final DnsConfiguration configuration;
+    private final ConcurrentHashMap<String, Lookup> cache;
+
+    public DnsServiceDiscovery(DnsConfiguration configuration) {
+        this.configuration = configuration;
+        this.cache = new ConcurrentHashMap<>();
+    }
+
+    @Override
+    public List<ServiceDefinition> getUpdatedListOfServices(String name) {
+        final Lookup lookup = cache.computeIfAbsent(name, this::createLookup);
+        final Record[] records = lookup.run();
+
+        List<ServiceDefinition> services;
+        if (Objects.nonNull(records) && lookup.getResult() == Lookup.SUCCESSFUL) {
+            services = Arrays.stream(records)
+                .filter(SRVRecord.class::isInstance)
+                .map(SRVRecord.class::cast)
+                .sorted(COMPARATOR)
+                .map(record -> asService(name, record))
+                .collect(Collectors.toList());
+        } else {
+            services = Collections.emptyList();
+        }
+
+        return services;
+    }
+
+    private Lookup createLookup(String name) {
+        try {
+            return new Lookup(
+                String.format("%s.%s.%s", name, configuration.getProto(), configuration.getDomain()),
+                Type.SRV);
+        } catch (TextParseException e) {
+            throw new RuntimeCamelException(e);
+        }
+    }
+
+    private static Comparator<SRVRecord> comparator() {
+        Comparator<SRVRecord> byPriority = (e1, e2) -> Integer.compare(e2.getPriority(), e1.getPriority());
+        Comparator<SRVRecord> byWeight = (e1, e2) -> Integer.compare(e2.getWeight(), e1.getWeight());
+
+        return byPriority.thenComparing(byWeight);
+    }
+
+    private static ServiceDefinition asService(String serviceName, SRVRecord record) {
+        Map<String, String> meta = new HashMap<>();
+        ObjectHelper.ifNotEmpty(record.getPriority(), val -> meta.put("priority", Integer.toString(val)));
+        ObjectHelper.ifNotEmpty(record.getWeight(), val -> meta.put("weight", Integer.toString(val)));
+
+        return new DefaultServiceDefinition(
+            serviceName,
+            record.getTarget().toString(true),
+            record.getPort(),
+            meta
+        );
+    }
+}