CAMEL-9988: Create an Etcd based ServiceCall EIP
Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/bafe28e4 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/bafe28e4 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/bafe28e4 Branch: refs/heads/master Commit: bafe28e477d6bc3419fba3a5806d6cd09fe86e58 Parents: dbfcd60 Author: lburgazzoli <lburgazz...@gmail.com> Authored: Tue Jun 7 10:29:19 2016 +0200 Committer: lburgazzoli <lburgazz...@gmail.com> Committed: Tue Jun 7 16:30:43 2016 +0200 ---------------------------------------------------------------------- .../remote/DefaultServiceCallProcessor.java | 12 +- .../DefaultServiceCallProcessorFactory.java | 22 ++-- .../remote/EtcdConfigurationDefinition.java | 125 +++++++++++++++++++ .../model/remote/ServiceCallDefinition.java | 9 ++ .../org/apache/camel/model/remote/jaxb.index | 1 + .../blueprint/CamelContextFactoryBean.java | 1 + components/camel-etcd/pom.xml | 15 +++ .../component/etcd/AbstractEtcdEndpoint.java | 33 +---- .../camel/component/etcd/EtcdComponent.java | 2 +- .../camel/component/etcd/EtcdConfiguration.java | 58 +++++++++ .../apache/camel/component/etcd/EtcdHelper.java | 9 ++ .../processor/remote/EtcdProcessorFactory.java | 24 ---- .../remote/EtcdServiceCallProcessor.java | 43 +++++++ .../remote/EtcdServiceCallProcessorFactory.java | 68 ++++++++++ .../processor/remote/EtcdServiceCallServer.java | 59 +++++++++ .../EtcdServiceCallServerListStrategies.java | 83 ++++++++++++ .../EtcdServiceCallServerListStrategy.java | 74 +++++++++++ .../apache/camel/model/ServiceCallDefinition | 18 +++ .../camel/component/etcd/EtcdKeysTest.java | 2 +- .../camel/component/etcd/EtcdStatsTest.java | 2 +- .../apache/camel/component/etcd/EtcdTest.java | 45 ------- .../camel/component/etcd/EtcdTestSupport.java | 45 +++++++ .../camel/component/etcd/EtcdWatchTest.java | 2 +- .../remote/EtcdServiceCallRouteTest.java | 117 +++++++++++++++++ .../camel/spring/CamelContextFactoryBean.java | 5 +- .../spring/handler/CamelNamespaceHandler.java | 14 +-- 26 files changed, 757 insertions(+), 131 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/bafe28e4/camel-core/src/main/java/org/apache/camel/impl/remote/DefaultServiceCallProcessor.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/impl/remote/DefaultServiceCallProcessor.java b/camel-core/src/main/java/org/apache/camel/impl/remote/DefaultServiceCallProcessor.java index 31b145c..9340406 100644 --- a/camel-core/src/main/java/org/apache/camel/impl/remote/DefaultServiceCallProcessor.java +++ b/camel-core/src/main/java/org/apache/camel/impl/remote/DefaultServiceCallProcessor.java @@ -234,12 +234,12 @@ public class DefaultServiceCallProcessor<S extends ServiceCallServer> extends Se List<S> servers = serverListStrategy.getUpdatedListOfServers(serviceName); if (servers == null || servers.isEmpty()) { exchange.setException(new RejectedExecutionException("No active services with name " + name)); - } - - // let the client load balancer chose which server to use - server = servers.size() > 1 ? loadBalancer.chooseServer(servers) : servers.get(0); - if (server == null) { - exchange.setException(new RejectedExecutionException("No active services with name " + name)); + } else { + // let the client load balancer chose which server to use + server = servers.size() > 1 ? loadBalancer.chooseServer(servers) : servers.get(0); + if (server == null) { + exchange.setException(new RejectedExecutionException("No active services with name " + name)); + } } } catch (Throwable e) { exchange.setException(e); http://git-wip-us.apache.org/repos/asf/camel/blob/bafe28e4/camel-core/src/main/java/org/apache/camel/impl/remote/DefaultServiceCallProcessorFactory.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/impl/remote/DefaultServiceCallProcessorFactory.java b/camel-core/src/main/java/org/apache/camel/impl/remote/DefaultServiceCallProcessorFactory.java index 0cdc0f4..d74023e 100644 --- a/camel-core/src/main/java/org/apache/camel/impl/remote/DefaultServiceCallProcessorFactory.java +++ b/camel-core/src/main/java/org/apache/camel/impl/remote/DefaultServiceCallProcessorFactory.java @@ -84,16 +84,16 @@ public abstract class DefaultServiceCallProcessorFactory<C, S extends ServiceCal throw new IllegalStateException("The ServiceCall: " + definition + " must be configured before it can be used."); } - // extract the properties from the configuration from the model - Map<String, Object> parameters = new HashMap<>(); - if (configRef != null) { - IntrospectionSupport.getProperties(configRef, parameters, null); - } - if (config != null) { - IntrospectionSupport.getProperties(config, parameters, null); - } - if (cfg != null) { + // extract the properties from the configuration from the model + Map<String, Object> parameters = new HashMap<>(); + if (configRef != null) { + IntrospectionSupport.getProperties(configRef, parameters, null); + } + if (config != null) { + IntrospectionSupport.getProperties(config, parameters, null); + } + IntrospectionSupport.setProperties(cfg, parameters); } @@ -139,10 +139,10 @@ public abstract class DefaultServiceCallProcessorFactory<C, S extends ServiceCal Map<String, String> properties = configureProperties(routeContext, config, configRef); DefaultServiceCallProcessor processor = createProcessor(name, component, uri, mep, cfg, properties); - if (sl != null && processor.getServerListStrategy() != null) { + if (sl != null && processor.getServerListStrategy() == null) { processor.setServerListStrategy(sl); } - if (lb != null && processor.getLoadBalancer() != null) { + if (lb != null && processor.getLoadBalancer() == null) { processor.setLoadBalancer(lb); } http://git-wip-us.apache.org/repos/asf/camel/blob/bafe28e4/camel-core/src/main/java/org/apache/camel/model/remote/EtcdConfigurationDefinition.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/model/remote/EtcdConfigurationDefinition.java b/camel-core/src/main/java/org/apache/camel/model/remote/EtcdConfigurationDefinition.java new file mode 100644 index 0000000..1edd5f0 --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/model/remote/EtcdConfigurationDefinition.java @@ -0,0 +1,125 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.camel.model.remote; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlRootElement; + +import org.apache.camel.spi.Metadata; + +/** + * Etcd remote service call configuration + */ +@Metadata(label = "eip,routing,remote") +@XmlRootElement(name = "etcdConfiguration") +@XmlAccessorType(XmlAccessType.FIELD) +public class EtcdConfigurationDefinition extends ServiceCallConfigurationDefinition { + @XmlAttribute + private String uris; + @XmlAttribute @Metadata(label = "security") + private String userName; + @XmlAttribute @Metadata(label = "security") + private String password; + @XmlAttribute + private Long timeout; + @XmlAttribute @Metadata(defaultValue = "/services/") + private String servicePath = "/services/"; + + public EtcdConfigurationDefinition() { + } + + public EtcdConfigurationDefinition(ServiceCallDefinition parent) { + super(parent); + } + + // ------------------------------------------------------------------------- + // Getter/Setter + // ------------------------------------------------------------------------- + + public String getUris() { + return uris; + } + + public void setUris(String uris) { + this.uris = uris; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public Long getTimeout() { + return timeout; + } + + public void setTimeout(Long timeout) { + this.timeout = timeout; + } + + public String getServicePath() { + return servicePath; + } + + public void setServicePath(String servicePath) { + this.servicePath = servicePath; + } + + + // ------------------------------------------------------------------------- + // Fluent API + // ------------------------------------------------------------------------- + + public EtcdConfigurationDefinition uris(String uris) { + setUris(uris); + return this; + } + + public EtcdConfigurationDefinition userName(String userName) { + setUserName(userName); + return this; + } + + public EtcdConfigurationDefinition password(String password) { + setPassword(password); + return this; + } + + public EtcdConfigurationDefinition timeout(Long timeout) { + setTimeout(timeout); + return this; + } + + public EtcdConfigurationDefinition servicePath(String servicePath) { + setServicePath(servicePath); + return this; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/bafe28e4/camel-core/src/main/java/org/apache/camel/model/remote/ServiceCallDefinition.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/model/remote/ServiceCallDefinition.java b/camel-core/src/main/java/org/apache/camel/model/remote/ServiceCallDefinition.java index ed1c2aa..a778b96 100644 --- a/camel-core/src/main/java/org/apache/camel/model/remote/ServiceCallDefinition.java +++ b/camel-core/src/main/java/org/apache/camel/model/remote/ServiceCallDefinition.java @@ -135,6 +135,15 @@ public class ServiceCallDefinition extends NoOutputDefinition<ServiceCallDefinit } /** + * Configures the Service Call EIP using Etcd + * <p/> + * Use <tt>end</tt> when configuration is complete, to return back to the Service Call EIP. + */ + public EtcdConfigurationDefinition etcdConfiguration() { + serviceCallConfiguration = new EtcdConfigurationDefinition(this); + return (EtcdConfigurationDefinition) serviceCallConfiguration; + } + /** * Configures the ServiceCall using the given configuration */ public ServiceCallDefinition serviceCallConfiguration(ServiceCallConfigurationDefinition configuration) { http://git-wip-us.apache.org/repos/asf/camel/blob/bafe28e4/camel-core/src/main/resources/org/apache/camel/model/remote/jaxb.index ---------------------------------------------------------------------- diff --git a/camel-core/src/main/resources/org/apache/camel/model/remote/jaxb.index b/camel-core/src/main/resources/org/apache/camel/model/remote/jaxb.index index 6d7d250..8100bd3 100644 --- a/camel-core/src/main/resources/org/apache/camel/model/remote/jaxb.index +++ b/camel-core/src/main/resources/org/apache/camel/model/remote/jaxb.index @@ -15,6 +15,7 @@ ## limitations under the License. ## ------------------------------------------------------------------------ ConsulConfigurationDefinition +EtcdConfigurationDefinition KubernetesConfigurationDefinition RibbonConfigurationDefinition ServiceCallDefinition http://git-wip-us.apache.org/repos/asf/camel/blob/bafe28e4/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 1ca4507..dda9a98 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 @@ -147,6 +147,7 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Blu @XmlElement(name = "kubernetesConfiguration", type = KubernetesConfigurationDefinition.class, required = false), @XmlElement(name = "ribbonConfiguration", type = RibbonConfigurationDefinition.class, required = false), @XmlElement(name = "consulConfiguration", type = RibbonConfigurationDefinition.class, required = false), + @XmlElement(name = "etcdConfiguration", type = RibbonConfigurationDefinition.class, required = false), @XmlElement(name = "template", type = CamelProducerTemplateFactoryBean.class, required = false), @XmlElement(name = "consumerTemplate", type = CamelConsumerTemplateFactoryBean.class, required = false), @XmlElement(name = "proxy", type = CamelProxyFactoryBean.class, required = false), http://git-wip-us.apache.org/repos/asf/camel/blob/bafe28e4/components/camel-etcd/pom.xml ---------------------------------------------------------------------- diff --git a/components/camel-etcd/pom.xml b/components/camel-etcd/pom.xml index 1868850..4e307b9 100644 --- a/components/camel-etcd/pom.xml +++ b/components/camel-etcd/pom.xml @@ -83,6 +83,21 @@ <artifactId>camel-test</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-test-spring</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-http</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-jetty</artifactId> + <scope>test</scope> + </dependency> </dependencies> http://git-wip-us.apache.org/repos/asf/camel/blob/bafe28e4/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/AbstractEtcdEndpoint.java ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/AbstractEtcdEndpoint.java b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/AbstractEtcdEndpoint.java index 6847d85..423d482 100644 --- a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/AbstractEtcdEndpoint.java +++ b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/AbstractEtcdEndpoint.java @@ -16,11 +16,7 @@ */ package org.apache.camel.component.etcd; -import java.net.URI; -import javax.net.ssl.SSLContext; - import mousio.etcd4j.EtcdClient; -import mousio.etcd4j.EtcdSecurityContext; import org.apache.camel.impl.DefaultEndpoint; import org.apache.camel.spi.Metadata; import org.apache.camel.spi.UriEndpoint; @@ -68,33 +64,6 @@ public abstract class AbstractEtcdEndpoint extends DefaultEndpoint { } public EtcdClient createClient() throws Exception { - String[] uris; - if (configuration.getUris() != null) { - uris = configuration.getUris().split(","); - } else { - uris = EtcdConstants.ETCD_DEFAULT_URIS.split(","); - } - - URI[] etcdUriList = new URI[uris.length]; - - int i = 0; - for (String uri : uris) { - etcdUriList[i++] = URI.create(getCamelContext().resolvePropertyPlaceholders(uri)); - } - - return new EtcdClient( - new EtcdSecurityContext( - createSslContext(configuration), - configuration.getUserName(), - configuration.getPassword()), - etcdUriList - ); - } - - private SSLContext createSslContext(EtcdConfiguration configuration) throws Exception { - if (configuration.getSslContextParameters() != null) { - return configuration.getSslContextParameters().createSSLContext(getCamelContext()); - } - return null; + return configuration.createClient(); } } http://git-wip-us.apache.org/repos/asf/camel/blob/bafe28e4/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdComponent.java ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdComponent.java b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdComponent.java index 3b81579..9c07b2a 100644 --- a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdComponent.java +++ b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdComponent.java @@ -49,7 +49,7 @@ public class EtcdComponent extends UriEndpointComponent { } EtcdNamespace namespace = getCamelContext().getTypeConverter().mandatoryConvertTo(EtcdNamespace.class, ns); - EtcdConfiguration configuration = loadConfiguration(new EtcdConfiguration(), parameters); + EtcdConfiguration configuration = loadConfiguration(new EtcdConfiguration(getCamelContext()), parameters); if (namespace != null) { // path must start with leading slash http://git-wip-us.apache.org/repos/asf/camel/blob/bafe28e4/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdConfiguration.java ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdConfiguration.java b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdConfiguration.java index 5edad92..2f80e8d 100644 --- a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdConfiguration.java +++ b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdConfiguration.java @@ -16,6 +16,11 @@ */ package org.apache.camel.component.etcd; +import java.net.URI; + +import mousio.etcd4j.EtcdClient; +import mousio.etcd4j.EtcdSecurityContext; +import org.apache.camel.CamelContext; import org.apache.camel.spi.UriParam; import org.apache.camel.spi.UriParams; import org.apache.camel.util.jsse.SSLContextParameters; @@ -41,6 +46,18 @@ public class EtcdConfiguration { private Long timeout; @UriParam(label = "consumer,advanced", defaultValue = "0") private Long fromIndex = 0L; + @UriParam(defaultValue = "/services/") + private String servicePath = "/services/"; + + private final CamelContext camelContext; + + public EtcdConfiguration(CamelContext camelContext) { + this.camelContext = camelContext; + } + + public CamelContext getCamelContext() { + return this.camelContext; + } public String getUris() { return uris; @@ -123,6 +140,10 @@ public class EtcdConfiguration { return timeout; } + public boolean hasTimeout() { + return timeout != null && timeout > 0; + } + /** * To set the maximum time an action could take to complete. */ @@ -140,4 +161,41 @@ public class EtcdConfiguration { public void setFromIndex(Long fromIndex) { this.fromIndex = fromIndex; } + + public String getServicePath() { + return servicePath; + } + + /** + * The path to look for for service discovery + */ + public void setServicePath(String servicePath) { + this.servicePath = servicePath; + } + + public EtcdClient createClient() throws Exception { + String[] uris; + if (getUris() != null) { + uris = getUris().split(","); + } else { + uris = EtcdConstants.ETCD_DEFAULT_URIS.split(","); + } + + URI[] etcdUriList = new URI[uris.length]; + + int i = 0; + for (String uri : uris) { + etcdUriList[i++] = URI.create(camelContext.resolvePropertyPlaceholders(uri)); + } + + return new EtcdClient( + new EtcdSecurityContext( + sslContextParameters != null + ? sslContextParameters.createSSLContext(camelContext) + : null, + userName, + password), + etcdUriList + ); + } } http://git-wip-us.apache.org/repos/asf/camel/blob/bafe28e4/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdHelper.java ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdHelper.java b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdHelper.java index c86e1a0..b222037 100644 --- a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdHelper.java +++ b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdHelper.java @@ -16,6 +16,9 @@ */ package org.apache.camel.component.etcd; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; import mousio.etcd4j.responses.EtcdErrorCode; import mousio.etcd4j.responses.EtcdException; @@ -32,4 +35,10 @@ public final class EtcdHelper { return false; } + + public static ObjectMapper createObjectMapper() { + return new ObjectMapper() + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + .setSerializationInclusion(JsonInclude.Include.NON_NULL); + } } http://git-wip-us.apache.org/repos/asf/camel/blob/bafe28e4/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/processor/remote/EtcdProcessorFactory.java ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/processor/remote/EtcdProcessorFactory.java b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/processor/remote/EtcdProcessorFactory.java deleted file mode 100644 index 0e60a77..0000000 --- a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/processor/remote/EtcdProcessorFactory.java +++ /dev/null @@ -1,24 +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.etcd.processor.remote; - -/** - * @author lburgazzoli - */ -public class EtcdProcessorFactory { -} http://git-wip-us.apache.org/repos/asf/camel/blob/bafe28e4/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/processor/remote/EtcdServiceCallProcessor.java ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/processor/remote/EtcdServiceCallProcessor.java b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/processor/remote/EtcdServiceCallProcessor.java new file mode 100644 index 0000000..3251ae5 --- /dev/null +++ b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/processor/remote/EtcdServiceCallProcessor.java @@ -0,0 +1,43 @@ +/** + * 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.etcd.processor.remote; + +import org.apache.camel.ExchangePattern; +import org.apache.camel.component.etcd.EtcdConfiguration; +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 Etcd implementation of the ServiceCall EIP. + */ +public class EtcdServiceCallProcessor extends DefaultServiceCallProcessor<ServiceCallServer> { + public EtcdServiceCallProcessor(String name, String scheme, String uri, ExchangePattern exchangePattern, EtcdConfiguration conf) { + super(name, scheme, uri, exchangePattern); + } + + @Override + public void setServerListStrategy(ServiceCallServerListStrategy<ServiceCallServer> serverListStrategy) { + if (!(serverListStrategy instanceof EtcdServiceCallServerListStrategy)) { + throw new IllegalArgumentException("ServerListStrategy is not an instance of EtcdServiceCallServerListStrategy"); + } + + super.setServerListStrategy(serverListStrategy); + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/bafe28e4/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/processor/remote/EtcdServiceCallProcessorFactory.java ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/processor/remote/EtcdServiceCallProcessorFactory.java b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/processor/remote/EtcdServiceCallProcessorFactory.java new file mode 100644 index 0000000..9f25738 --- /dev/null +++ b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/processor/remote/EtcdServiceCallProcessorFactory.java @@ -0,0 +1,68 @@ +/** + * 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.etcd.processor.remote; + +import java.util.Map; +import java.util.Optional; + +import org.apache.camel.ExchangePattern; +import org.apache.camel.component.etcd.EtcdConfiguration; +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 Etcd implementation of the ServiceCall EIP. + */ +public class EtcdServiceCallProcessorFactory extends DefaultServiceCallProcessorFactory<EtcdConfiguration, ServiceCallServer> { + @Override + protected EtcdConfiguration createConfiguration(RouteContext routeContext) throws Exception { + return new EtcdConfiguration(routeContext.getCamelContext()); + } + + @Override + protected DefaultServiceCallProcessor createProcessor( + String name, + String component, + String uri, + ExchangePattern mep, + EtcdConfiguration conf, + Map<String, String> properties) throws Exception { + + return new EtcdServiceCallProcessor(name, component, uri, mep, conf); + } + + @Override + protected Optional<ServiceCallServerListStrategy> builtInServerListStrategy(EtcdConfiguration conf, String name) throws Exception { + ServiceCallServerListStrategy strategy = null; + if (ObjectHelper.equal("ondemand", name, true)) { + strategy = new EtcdServiceCallServerListStrategies.OnDemand(conf); + } + + return Optional.ofNullable(strategy); + } + + @Override + protected ServiceCallServerListStrategy<ServiceCallServer> createDefaultServerListStrategy(EtcdConfiguration conf) throws Exception { + return new EtcdServiceCallServerListStrategies.OnDemand(conf); + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/bafe28e4/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/processor/remote/EtcdServiceCallServer.java ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/processor/remote/EtcdServiceCallServer.java b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/processor/remote/EtcdServiceCallServer.java new file mode 100644 index 0000000..d5c25d9 --- /dev/null +++ b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/processor/remote/EtcdServiceCallServer.java @@ -0,0 +1,59 @@ +/** + * 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.etcd.processor.remote; + +import java.util.Collections; +import java.util.Comparator; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import org.apache.camel.impl.remote.DefaultServiceCallServer; + +public class EtcdServiceCallServer extends DefaultServiceCallServer { + public static final Comparator<EtcdServiceCallServer> COMPARATOR = comparator(); + + private final String name; + private final Map<String, String> tags; + + @JsonCreator + public EtcdServiceCallServer( + @JsonProperty("name") final String name, + @JsonProperty("address") final String address, + @JsonProperty("port") final Integer port, + @JsonProperty("tags") final Map<String, String> tags) { + super(address, port); + + this.name = name; + this.tags = Collections.unmodifiableMap(tags != null ? tags : Collections.EMPTY_MAP); + } + + public String getName() { + return name; + } + + public Map<String, String> getTags() { + return tags; + } + + public static Comparator<EtcdServiceCallServer> comparator() { + Comparator<EtcdServiceCallServer> byAddress = (e1, e2) -> e2.getIp().compareTo(e1.getIp()); + Comparator<EtcdServiceCallServer> byPort = (e1, e2) -> Integer.compare(e2.getPort(), e1.getPort()); + + return byAddress.thenComparing(byPort); + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/bafe28e4/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/processor/remote/EtcdServiceCallServerListStrategies.java ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/processor/remote/EtcdServiceCallServerListStrategies.java b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/processor/remote/EtcdServiceCallServerListStrategies.java new file mode 100644 index 0000000..e4b4a8a --- /dev/null +++ b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/processor/remote/EtcdServiceCallServerListStrategies.java @@ -0,0 +1,83 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.etcd.processor.remote; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import mousio.etcd4j.requests.EtcdKeyGetRequest; +import mousio.etcd4j.responses.EtcdKeysResponse; +import org.apache.camel.RuntimeCamelException; +import org.apache.camel.component.etcd.EtcdConfiguration; +import org.apache.camel.spi.ServiceCallServer; +import org.apache.camel.util.ObjectHelper; + +public final class EtcdServiceCallServerListStrategies { + private EtcdServiceCallServerListStrategies() { + } + + public static final class OnDemand extends EtcdServiceCallServerListStrategy { + public OnDemand(EtcdConfiguration configuration) throws Exception { + super(configuration); + } + + @Override + public List<ServiceCallServer> getUpdatedListOfServers(String name) { + List<ServiceCallServer> servers = Collections.emptyList(); + try { + final EtcdConfiguration conf = getConfiguration(); + final EtcdKeyGetRequest request = getClient().get(conf.getServicePath()).recursive(); + if (conf.hasTimeout()) { + request.timeout(conf.getTimeout(), TimeUnit.SECONDS); + } + + final EtcdKeysResponse response = request.send().get(); + + if (Objects.nonNull(response.node) && !response.node.nodes.isEmpty()) { + servers = response.node.nodes.stream() + .map(node -> node.value) + .filter(ObjectHelper::isNotEmpty) + .map(this::nodeFromString) + .filter(Objects::nonNull) + .filter(s -> name.equalsIgnoreCase(s.getName())) + .sorted(EtcdServiceCallServer.COMPARATOR) + .collect(Collectors.toList()); + } + } catch (Exception e) { + throw new RuntimeCamelException(e); + } + + return servers; + } + + @Override + public String toString() { + return "OnDemand"; + } + } + + // ************************************************************************* + // Helpers + // ************************************************************************* + + public static EtcdServiceCallServerListStrategy onDemand(EtcdConfiguration configuration) throws Exception { + return new OnDemand(configuration); + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/bafe28e4/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/processor/remote/EtcdServiceCallServerListStrategy.java ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/processor/remote/EtcdServiceCallServerListStrategy.java b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/processor/remote/EtcdServiceCallServerListStrategy.java new file mode 100644 index 0000000..38f6139 --- /dev/null +++ b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/processor/remote/EtcdServiceCallServerListStrategy.java @@ -0,0 +1,74 @@ +/** + * 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.etcd.processor.remote; + +import com.fasterxml.jackson.databind.ObjectMapper; +import mousio.etcd4j.EtcdClient; +import org.apache.camel.component.etcd.EtcdConfiguration; +import org.apache.camel.component.etcd.EtcdHelper; +import org.apache.camel.impl.remote.DefaultServiceCallServerListStrategy; +import org.apache.camel.spi.ServiceCallServer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class EtcdServiceCallServerListStrategy extends DefaultServiceCallServerListStrategy<ServiceCallServer> { + private static final Logger LOGGER = LoggerFactory.getLogger(EtcdServiceCallServerListStrategy.class); + private static final ObjectMapper MAPPER = EtcdHelper.createObjectMapper(); + + private final EtcdConfiguration configuration; + private EtcdClient client; + + public EtcdServiceCallServerListStrategy(EtcdConfiguration configuration) { + this.configuration = configuration; + this.client = null; + } + + @Override + protected void doStart() throws Exception { + if (client == null) { + client = configuration.createClient(); + } + } + + @Override + protected void doStop() throws Exception { + if (client != null) { + client.close(); + client = null; + } + } + + protected EtcdConfiguration getConfiguration() { + return this.configuration; + } + + protected EtcdClient getClient() { + return this.client; + } + + protected EtcdServiceCallServer nodeFromString(String value) { + EtcdServiceCallServer server = null; + + try { + server = MAPPER.readValue(value, EtcdServiceCallServer.class); + } catch (Exception e) { + LOGGER.warn("", e); + } + + return server; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/bafe28e4/components/camel-etcd/src/main/resources/META-INF/services/org/apache/camel/model/ServiceCallDefinition ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/main/resources/META-INF/services/org/apache/camel/model/ServiceCallDefinition b/components/camel-etcd/src/main/resources/META-INF/services/org/apache/camel/model/ServiceCallDefinition new file mode 100644 index 0000000..0cd6c42 --- /dev/null +++ b/components/camel-etcd/src/main/resources/META-INF/services/org/apache/camel/model/ServiceCallDefinition @@ -0,0 +1,18 @@ +# +# 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.etcd.processor.remote.EtcdServiceCallProcessorFactory http://git-wip-us.apache.org/repos/asf/camel/blob/bafe28e4/components/camel-etcd/src/test/java/org/apache/camel/component/etcd/EtcdKeysTest.java ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/test/java/org/apache/camel/component/etcd/EtcdKeysTest.java b/components/camel-etcd/src/test/java/org/apache/camel/component/etcd/EtcdKeysTest.java index cf16017..c2bc507 100644 --- a/components/camel-etcd/src/test/java/org/apache/camel/component/etcd/EtcdKeysTest.java +++ b/components/camel-etcd/src/test/java/org/apache/camel/component/etcd/EtcdKeysTest.java @@ -30,7 +30,7 @@ import org.apache.camel.component.mock.MockEndpoint; import org.junit.Test; //@Ignore("Etcd must be started manually") -public class EtcdKeysTest extends EtcdTest { +public class EtcdKeysTest extends EtcdTestSupport { @Test(expected = EtcdException.class) public void testKeys() throws Exception { http://git-wip-us.apache.org/repos/asf/camel/blob/bafe28e4/components/camel-etcd/src/test/java/org/apache/camel/component/etcd/EtcdStatsTest.java ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/test/java/org/apache/camel/component/etcd/EtcdStatsTest.java b/components/camel-etcd/src/test/java/org/apache/camel/component/etcd/EtcdStatsTest.java index aba6045..b3eeb13 100644 --- a/components/camel-etcd/src/test/java/org/apache/camel/component/etcd/EtcdStatsTest.java +++ b/components/camel-etcd/src/test/java/org/apache/camel/component/etcd/EtcdStatsTest.java @@ -26,7 +26,7 @@ import org.apache.camel.component.mock.MockEndpoint; import org.junit.Test; //@Ignore("Etcd must be started manually") -public class EtcdStatsTest extends EtcdTest { +public class EtcdStatsTest extends EtcdTestSupport { @Test public void testStats() throws Exception { http://git-wip-us.apache.org/repos/asf/camel/blob/bafe28e4/components/camel-etcd/src/test/java/org/apache/camel/component/etcd/EtcdTest.java ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/test/java/org/apache/camel/component/etcd/EtcdTest.java b/components/camel-etcd/src/test/java/org/apache/camel/component/etcd/EtcdTest.java deleted file mode 100644 index a8100e6..0000000 --- a/components/camel-etcd/src/test/java/org/apache/camel/component/etcd/EtcdTest.java +++ /dev/null @@ -1,45 +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.etcd; - -import java.net.URI; - -import mousio.etcd4j.EtcdClient; -import mousio.etcd4j.responses.EtcdKeysResponse; -import org.apache.camel.Exchange; -import org.apache.camel.Processor; -import org.apache.camel.test.junit4.CamelTestSupport; - -public class EtcdTest extends CamelTestSupport { - protected static final Processor NODE_TO_VALUE_IN = new Processor() { - @Override - public void process(Exchange exchange) throws Exception { - EtcdKeysResponse response = exchange.getIn().getBody(EtcdKeysResponse.class); - if (response != null) { - exchange.getIn().setBody(response.node.key + "=" + response.node.value); - } - } - }; - - public boolean isCreateCamelContextPerClass() { - return false; - } - - protected EtcdClient getClient() { - return new EtcdClient(URI.create("http://localhost:4001")); - } -} http://git-wip-us.apache.org/repos/asf/camel/blob/bafe28e4/components/camel-etcd/src/test/java/org/apache/camel/component/etcd/EtcdTestSupport.java ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/test/java/org/apache/camel/component/etcd/EtcdTestSupport.java b/components/camel-etcd/src/test/java/org/apache/camel/component/etcd/EtcdTestSupport.java new file mode 100644 index 0000000..e66466d --- /dev/null +++ b/components/camel-etcd/src/test/java/org/apache/camel/component/etcd/EtcdTestSupport.java @@ -0,0 +1,45 @@ +/** + * 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.etcd; + +import java.net.URI; + +import mousio.etcd4j.EtcdClient; +import mousio.etcd4j.responses.EtcdKeysResponse; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.apache.camel.test.junit4.CamelTestSupport; + +public class EtcdTestSupport extends CamelTestSupport { + protected static final Processor NODE_TO_VALUE_IN = new Processor() { + @Override + public void process(Exchange exchange) throws Exception { + EtcdKeysResponse response = exchange.getIn().getBody(EtcdKeysResponse.class); + if (response != null) { + exchange.getIn().setBody(response.node.key + "=" + response.node.value); + } + } + }; + + public boolean isCreateCamelContextPerClass() { + return false; + } + + protected EtcdClient getClient() { + return new EtcdClient(URI.create("http://localhost:2379")); + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/bafe28e4/components/camel-etcd/src/test/java/org/apache/camel/component/etcd/EtcdWatchTest.java ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/test/java/org/apache/camel/component/etcd/EtcdWatchTest.java b/components/camel-etcd/src/test/java/org/apache/camel/component/etcd/EtcdWatchTest.java index c511325..39aca62 100644 --- a/components/camel-etcd/src/test/java/org/apache/camel/component/etcd/EtcdWatchTest.java +++ b/components/camel-etcd/src/test/java/org/apache/camel/component/etcd/EtcdWatchTest.java @@ -24,7 +24,7 @@ import org.apache.camel.component.mock.MockEndpoint; import org.junit.Test; //@Ignore("Etcd must be started manually") -public class EtcdWatchTest extends EtcdTest { +public class EtcdWatchTest extends EtcdTestSupport { @Test public void testWatchWithPath() throws Exception { http://git-wip-us.apache.org/repos/asf/camel/blob/bafe28e4/components/camel-etcd/src/test/java/org/apache/camel/component/etcd/processor/remote/EtcdServiceCallRouteTest.java ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/test/java/org/apache/camel/component/etcd/processor/remote/EtcdServiceCallRouteTest.java b/components/camel-etcd/src/test/java/org/apache/camel/component/etcd/processor/remote/EtcdServiceCallRouteTest.java new file mode 100644 index 0000000..a20bd02 --- /dev/null +++ b/components/camel-etcd/src/test/java/org/apache/camel/component/etcd/processor/remote/EtcdServiceCallRouteTest.java @@ -0,0 +1,117 @@ +/** + * 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.etcd.processor.remote; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.databind.ObjectMapper; +import mousio.etcd4j.EtcdClient; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.etcd.EtcdHelper; +import org.apache.camel.component.etcd.EtcdTestSupport; +import org.junit.Ignore; +import org.junit.Test; + +@Ignore +public class EtcdServiceCallRouteTest extends EtcdTestSupport { + private static final ObjectMapper MAPPER = EtcdHelper.createObjectMapper(); + private static final String SERVICE_NAME = "http-service"; + private static final int SERVICE_COUNT = 5; + private static final int SERVICE_PORT_BASE = 8080; + + private EtcdClient client; + private List<Map<String, Object>> servers; + private List<String> expectedBodies; + + // ************************************************************************* + // Setup / tear down + // ************************************************************************* + + @Override + protected void doPreSetup() throws Exception { + client = getClient(); + + servers = new ArrayList<>(SERVICE_COUNT); + expectedBodies = new ArrayList<>(SERVICE_COUNT); + + for (int i = 0; i < SERVICE_COUNT; i++) { + Map<String, Object> server = new HashMap<>(); + server.put("name", SERVICE_NAME); + server.put("address", "127.0.0.1"); + server.put("port", SERVICE_PORT_BASE + i); + + client.put("/services/" + "service-" + i, MAPPER.writeValueAsString(server)).send().get(); + + servers.add(Collections.unmodifiableMap(server)); + expectedBodies.add("ping on " + (SERVICE_PORT_BASE + i)); + } + } + + @Override + public void tearDown() throws Exception { + super.tearDown(); + client.deleteDir("/services/").recursive().send().get(); + } + + // ************************************************************************* + // Test + // ************************************************************************* + + @Test + public void testServiceCall() throws Exception { + getMockEndpoint("mock:result").expectedMessageCount(SERVICE_COUNT); + getMockEndpoint("mock:result").expectedBodiesReceivedInAnyOrder(expectedBodies); + + servers.forEach(s -> 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) + .etcdConfiguration() + .component("http") + .loadBalancer("roundrobin") + .serverListStrategy("ondemand") + .end() + .to("log:org.apache.camel.component.etcd.processor.service?level=INFO&showAll=true&multiline=true") + .to("mock:result"); + + servers.forEach(s -> + fromF("jetty:http://%s:%d", s.get("address"), s.get("port")) + .transform().simple("${in.body} on " + s.get("port")) + ); + } + }; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/bafe28e4/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java ---------------------------------------------------------------------- diff --git a/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java b/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java index 9f48921..7527881 100644 --- a/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java +++ b/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java @@ -19,7 +19,6 @@ package org.apache.camel.spring; import java.util.ArrayList; import java.util.List; import java.util.Map; - import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; @@ -58,6 +57,7 @@ import org.apache.camel.model.RouteDefinition; import org.apache.camel.model.ThreadPoolProfileDefinition; import org.apache.camel.model.dataformat.DataFormatsDefinition; import org.apache.camel.model.remote.ConsulConfigurationDefinition; +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; @@ -155,7 +155,8 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Spr private CamelJMXAgentDefinition camelJMXAgent; @XmlElements({ @XmlElement(name = "hystrixConfiguration", type = HystrixConfigurationDefinition.class, required = false), - @XmlElement(name = "consulConfiguration", type = KubernetesConfigurationDefinition.class, required = false), + @XmlElement(name = "consulConfiguration", type = ConsulConfigurationDefinition.class, required = false), + @XmlElement(name = "etcdConfiguration", type = EtcdConfigurationDefinition.class, required = false), @XmlElement(name = "kubernetesConfiguration", type = KubernetesConfigurationDefinition.class, required = false), @XmlElement(name = "ribbonConfiguration", type = RibbonConfigurationDefinition.class, required = false), @XmlElement(name = "template", type = CamelProducerTemplateFactoryBean.class, required = false), http://git-wip-us.apache.org/repos/asf/camel/blob/bafe28e4/components/camel-spring/src/main/java/org/apache/camel/spring/handler/CamelNamespaceHandler.java ---------------------------------------------------------------------- diff --git a/components/camel-spring/src/main/java/org/apache/camel/spring/handler/CamelNamespaceHandler.java b/components/camel-spring/src/main/java/org/apache/camel/spring/handler/CamelNamespaceHandler.java index 7470126..eae9f61 100644 --- a/components/camel-spring/src/main/java/org/apache/camel/spring/handler/CamelNamespaceHandler.java +++ b/components/camel-spring/src/main/java/org/apache/camel/spring/handler/CamelNamespaceHandler.java @@ -21,17 +21,10 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; - import javax.xml.bind.Binder; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - import org.apache.camel.builder.xml.Namespaces; import org.apache.camel.core.xml.CamelJMXAgentDefinition; import org.apache.camel.core.xml.CamelPropertyPlaceholderDefinition; @@ -41,6 +34,7 @@ import org.apache.camel.model.FromDefinition; import org.apache.camel.model.HystrixConfigurationDefinition; import org.apache.camel.model.SendDefinition; import org.apache.camel.model.remote.ConsulConfigurationDefinition; +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.spi.CamelContextNameStrategy; @@ -71,6 +65,11 @@ import org.springframework.beans.factory.parsing.BeanComponentDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; import org.springframework.beans.factory.xml.ParserContext; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; /** * Camel namespace for the spring XML configuration file. @@ -148,6 +147,7 @@ public class CamelNamespaceHandler extends NamespaceHandlerSupport { addBeanDefinitionParser("propertyPlaceholder", CamelPropertyPlaceholderDefinition.class, false, false); addBeanDefinitionParser("hystrixConfiguration", HystrixConfigurationDefinition.class, false, false); addBeanDefinitionParser("consulConfiguration", ConsulConfigurationDefinition.class, false, false); + addBeanDefinitionParser("etcdConfiguration", EtcdConfigurationDefinition.class, false, false); addBeanDefinitionParser("kubernetesConfiguration", KubernetesConfigurationDefinition.class, false, false); addBeanDefinitionParser("ribbonConfiguration", RibbonConfigurationDefinition.class, false, false);