Repository: camel Updated Branches: refs/heads/master 11ce32132 -> e85782704
CAMEL-9586 - Create new Etcd component Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/e8578270 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/e8578270 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/e8578270 Branch: refs/heads/master Commit: e857827040b67f49fb1c939f42e21e8c2688e310 Parents: 11ce321 Author: lburgazzoli <[email protected]> Authored: Wed Feb 10 16:54:39 2016 +0100 Committer: Claus Ibsen <[email protected]> Committed: Tue Feb 23 07:47:36 2016 +0100 ---------------------------------------------------------------------- components/camel-etcd/pom.xml | 88 +++++++++++++ components/camel-etcd/src/main/docs/etcd.adoc | 32 +++++ .../component/etcd/AbstractEtcdConsumer.java | 70 +++++++++++ .../component/etcd/AbstractEtcdEndpoint.java | 97 ++++++++++++++ .../etcd/AbstractEtcdPollingConsumer.java | 70 +++++++++++ .../component/etcd/AbstractEtcdProducer.java | 69 ++++++++++ .../camel/component/etcd/EtcdComponent.java | 82 ++++++++++++ .../camel/component/etcd/EtcdConfiguration.java | 80 ++++++++++++ .../camel/component/etcd/EtcdConstants.java | 42 +++++++ .../component/etcd/EtcdKeysConfiguration.java | 82 ++++++++++++ .../camel/component/etcd/EtcdKeysEndpoint.java | 38 ++++++ .../camel/component/etcd/EtcdKeysProducer.java | 125 +++++++++++++++++++ .../camel/component/etcd/EtcdNamespace.java | 50 ++++++++ .../component/etcd/EtcdStatsConfiguration.java | 23 ++++ .../camel/component/etcd/EtcdStatsConsumer.java | 50 ++++++++ .../camel/component/etcd/EtcdStatsEndpoint.java | 53 ++++++++ .../camel/component/etcd/EtcdStatsProducer.java | 42 +++++++ .../component/etcd/EtcdWatchConfiguration.java | 36 ++++++ .../camel/component/etcd/EtcdWatchConsumer.java | 113 +++++++++++++++++ .../camel/component/etcd/EtcdWatchEndpoint.java | 39 ++++++ .../services/org/apache/camel/component/etcd | 1 + .../camel/component/etcd/EtcdKeysTest.java | 125 +++++++++++++++++++ .../camel/component/etcd/EtcdStatsTest.java | 88 +++++++++++++ .../apache/camel/component/etcd/EtcdTest.java | 45 +++++++ .../camel/component/etcd/EtcdWatchTest.java | 101 +++++++++++++++ .../src/test/resources/log4j.properties | 14 +++ components/pom.xml | 1 + parent/pom.xml | 1 + .../features/src/main/resources/features.xml | 6 + .../apache/camel/itest/karaf/CamelEtcdTest.java | 40 ++++++ 30 files changed, 1703 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/e8578270/components/camel-etcd/pom.xml ---------------------------------------------------------------------- diff --git a/components/camel-etcd/pom.xml b/components/camel-etcd/pom.xml new file mode 100644 index 0000000..786a1ab --- /dev/null +++ b/components/camel-etcd/pom.xml @@ -0,0 +1,88 @@ +<?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. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.camel</groupId> + <artifactId>components</artifactId> + <version>2.17-SNAPSHOT</version> + </parent> + + <artifactId>camel-etcd</artifactId> + <packaging>bundle</packaging> + <name>Camel :: Etcd</name> + <description>Camel Etcd support</description> + + <properties> + <version.etcd4j>2.10.0</version.etcd4j> + + <schemeName>etcd</schemeName> + <componentName>Etcd</componentName> + <componentPackage>org.apache.camel.component.etcd</componentPackage> + + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> + + <camel.osgi.export.pkg>${componentPackage}</camel.osgi.export.pkg> + + </properties> + +<dependencies> + <dependency> + <groupId>org.mousio</groupId> + <artifactId>etcd4j</artifactId> + <version>${etcd4j-version}</version> + </dependency> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-core</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + <version>${commons-lang3-version}</version> + </dependency> + + <!-- logging --> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-log4j12</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>log4j</groupId> + <artifactId>log4j</artifactId> + <scope>test</scope> + </dependency> + + <!-- testing --> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-test</artifactId> + <scope>test</scope> + </dependency> + + </dependencies> +</project> http://git-wip-us.apache.org/repos/asf/camel/blob/e8578270/components/camel-etcd/src/main/docs/etcd.adoc ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/main/docs/etcd.adoc b/components/camel-etcd/src/main/docs/etcd.adoc new file mode 100644 index 0000000..499b706 --- /dev/null +++ b/components/camel-etcd/src/main/docs/etcd.adoc @@ -0,0 +1,32 @@ ++[[Etcd-Etcd]] ++Etcd + + + +// endpoint options: START +The etcd component supports 5 endpoint options which are listed below: + +[width="100%",cols="2s,1,1m,1m,5",options="header"] +|======================================================================= +| Name | Group | Default | Java Type | Description +| namespace | common | | EtcdNamespace | *Required* The namespace +| bridgeErrorHandler | consumer | false | boolean | Allows for bridging the consumer to the Camel routing Error Handler which mean any exceptions occurred while the consumer is trying to pickup incoming messages or the likes will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions that will be logged at WARN/ERROR level and ignored. +| exceptionHandler | consumer (advanced) | | ExceptionHandler | To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this options is not in use. By default the consumer will deal with exceptions that will be logged at WARN/ERROR level and ignored. +| exchangePattern | advanced | InOnly | ExchangePattern | Sets the default exchange pattern when creating an exchange +| synchronous | advanced | false | boolean | Sets whether synchronous processing should be strictly used or Camel is allowed to use asynchronous processing (if supported). +|======================================================================= +// endpoint options: END + + + + +// component options: START +The etcd component has no options. + + +[width="100%",cols="2s,1m,8",options="header"] +|======================================================================= +| Name | Java Type | Description +|======================================================================= +// component options: END + http://git-wip-us.apache.org/repos/asf/camel/blob/e8578270/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/AbstractEtcdConsumer.java ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/AbstractEtcdConsumer.java b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/AbstractEtcdConsumer.java new file mode 100644 index 0000000..e75909a --- /dev/null +++ b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/AbstractEtcdConsumer.java @@ -0,0 +1,70 @@ +/** + * 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 mousio.etcd4j.EtcdClient; +import org.apache.camel.Processor; +import org.apache.camel.impl.DefaultConsumer; + +/** + * The etcd consumer. + */ +abstract class AbstractEtcdConsumer extends DefaultConsumer { + private final EtcdConfiguration configuration; + private final EtcdNamespace namespace; + private final String path; + + private EtcdClient client; + + protected AbstractEtcdConsumer(AbstractEtcdEndpoint endpoint, Processor processor, EtcdConfiguration configuration, EtcdNamespace namespace, String path) { + super(endpoint, processor); + + this.configuration = configuration; + this.namespace = namespace; + this.path = path; + this.client = null; + } + + @Override + protected void doStop() throws Exception { + if (client != null) { + client.close(); + } + + super.doStop(); + } + + protected EtcdClient getClient() throws Exception { + if (client == null) { + client = ((AbstractEtcdEndpoint)getEndpoint()).createClient(); + } + + return client; + } + + protected EtcdConfiguration getConfiguration() { + return configuration; + } + + protected EtcdNamespace getActionNamespace() { + return namespace; + } + + protected String getPath() { + return this.path; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/e8578270/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 new file mode 100644 index 0000000..8cf18ca --- /dev/null +++ b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/AbstractEtcdEndpoint.java @@ -0,0 +1,97 @@ +/** + * 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.EtcdSecurityContext; +import org.apache.camel.impl.DefaultEndpoint; +import org.apache.camel.spi.Metadata; +import org.apache.camel.spi.UriEndpoint; +import org.apache.camel.spi.UriPath; +import org.apache.camel.util.ObjectHelper; + +/** + * Represents a etcd endpoint. + */ +@UriEndpoint(scheme = "etcd", title = "etcd", syntax = "etcd:namespace", consumerClass = AbstractEtcdConsumer.class, label = "etcd") +abstract class AbstractEtcdEndpoint<C extends EtcdConfiguration> extends DefaultEndpoint { + + @UriPath(description = "The namespace") + @Metadata(required = "true") + private final EtcdNamespace namespace; + private final C configuration; + private final String path; + + protected AbstractEtcdEndpoint(String uri, EtcdComponent component, C configuration, EtcdNamespace namespace, String path) { + super(uri, component); + + this.configuration = configuration; + this.namespace = namespace; + this.path = path; + } + + @Override + public boolean isSingleton() { + return true; + } + + public C getConfiguration() { + return this.configuration; + } + + public EtcdNamespace getActionNamespace() { + return this.namespace; + } + + public EtcdClient createClient() throws Exception { + + String[] uris = EtcdConstants.ETCD_DEFAULT_URIS; + if (configuration.hasUris()) { + uris = configuration.getUris().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( + configuration.createSslContext(), + configuration.getUserName(), + configuration.getPassword()), + etcdUriList + ); + } + + public String getPath() { + return this.path; + } + + public String getRemainingPath(String defaultPath) { + String path = getPath().substring(namespace.path().length()); + if (ObjectHelper.isEmpty(path)) { + path = defaultPath; + } + + return path; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/e8578270/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/AbstractEtcdPollingConsumer.java ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/AbstractEtcdPollingConsumer.java b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/AbstractEtcdPollingConsumer.java new file mode 100644 index 0000000..d9d65df --- /dev/null +++ b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/AbstractEtcdPollingConsumer.java @@ -0,0 +1,70 @@ +/** + * 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 mousio.etcd4j.EtcdClient; +import org.apache.camel.Processor; +import org.apache.camel.impl.ScheduledPollConsumer; + +/** + * The etcd consumer. + */ +abstract class AbstractEtcdPollingConsumer extends ScheduledPollConsumer { + private final EtcdConfiguration configuration; + private final EtcdNamespace namespace; + private final String path; + + private EtcdClient client; + + protected AbstractEtcdPollingConsumer(AbstractEtcdEndpoint endpoint, Processor processor, EtcdConfiguration configuration, EtcdNamespace namespace, String path) { + super(endpoint, processor); + + this.configuration = configuration; + this.namespace = namespace; + this.path = path; + this.client = null; + } + + @Override + protected void doStop() throws Exception { + if (client != null) { + client.close(); + } + + super.doStop(); + } + + protected EtcdClient getClient() throws Exception { + if (client == null) { + client = ((AbstractEtcdEndpoint)getEndpoint()).createClient(); + } + + return client; + } + + protected EtcdConfiguration getConfiguration() { + return configuration; + } + + protected EtcdNamespace getActionNamespace() { + return namespace; + } + + protected String getPath() { + return this.path; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/e8578270/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/AbstractEtcdProducer.java ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/AbstractEtcdProducer.java b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/AbstractEtcdProducer.java new file mode 100644 index 0000000..214c9a0 --- /dev/null +++ b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/AbstractEtcdProducer.java @@ -0,0 +1,69 @@ +/** + * 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 mousio.etcd4j.EtcdClient; +import org.apache.camel.impl.DefaultProducer; + +/** + * The etcd producer. + */ +abstract class AbstractEtcdProducer extends DefaultProducer { + private final EtcdConfiguration configuration; + private final EtcdNamespace namespace; + private final String path; + + private EtcdClient client; + + protected AbstractEtcdProducer(AbstractEtcdEndpoint endpoint, EtcdConfiguration configuration, EtcdNamespace namespace, String path) { + super(endpoint); + + this.configuration = configuration; + this.namespace = namespace; + this.path = path; + this.client = null; + } + + @Override + protected void doStop() throws Exception { + if (client != null) { + client.close(); + } + + super.doStop(); + } + + protected EtcdClient getClient() throws Exception { + if (client == null) { + client = ((AbstractEtcdEndpoint)getEndpoint()).createClient(); + } + + return client; + } + + protected EtcdConfiguration getConfiguration() { + return configuration; + } + + protected EtcdNamespace getActionNamespace() { + return namespace; + } + + protected String getPath() { + return this.path; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/e8578270/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 new file mode 100644 index 0000000..8aa20c8f --- /dev/null +++ b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdComponent.java @@ -0,0 +1,82 @@ +/** + * 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.util.Map; + +import org.apache.camel.CamelContext; +import org.apache.camel.Endpoint; +import org.apache.camel.impl.UriEndpointComponent; + +/** + * Represents the component that manages {@link AbstractEtcdEndpoint}. + */ +public class EtcdComponent extends UriEndpointComponent { + public EtcdComponent() { + super(AbstractEtcdEndpoint.class); + } + + public EtcdComponent(CamelContext context) { + super(context, AbstractEtcdEndpoint.class); + } + + @Override + protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception { + EtcdNamespace namespace = EtcdNamespace.fromPath(remaining); + if (namespace != null) { + if (!remaining.startsWith("/")) { + remaining = "/" + remaining; + } + + switch (namespace) { + case STATS: + return new EtcdStatsEndpoint( + uri, + this, + loadConfiguration(new EtcdStatsConfiguration(), parameters), + namespace, + remaining + ); + case WATCH: + return new EtcdWatchEndpoint( + uri, + this, + loadConfiguration(new EtcdWatchConfiguration(), parameters), + namespace, + remaining + ); + case KEYS: + return new EtcdKeysEndpoint( + uri, + this, + loadConfiguration(new EtcdKeysConfiguration(), parameters), + namespace, + remaining + ); + default: + throw new IllegalStateException("No endpoint for " + remaining); + } + } + + throw new IllegalStateException("No endpoint for " + remaining); + } + + protected <T> T loadConfiguration(T configuration, Map<String, Object> parameters) throws Exception { + setProperties(configuration, parameters); + return configuration; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/e8578270/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 new file mode 100644 index 0000000..38c85a1 --- /dev/null +++ b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdConfiguration.java @@ -0,0 +1,80 @@ +/** + * 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 javax.net.ssl.SSLContext; + +import org.apache.camel.spi.UriParam; +import org.apache.camel.spi.UriParams; +import org.apache.camel.util.jsse.SSLContextParameters; + +@UriParams +class EtcdConfiguration { + + @UriParam(multiValue = true) + private String uris; + + @UriParam(label = "security") + private SSLContextParameters sslContextParameters; + + @UriParam(label = "security") + private String userName; + + @UriParam(label = "security") + private String password; + + + public String getUris() { + return uris; + } + + public boolean hasUris() { + return uris != null; + } + + public void setUris(String uris) { + this.uris = uris; + } + + public SSLContextParameters getSslContextParameters() { + return sslContextParameters; + } + + public void setSslContextParameters(SSLContextParameters sslContextParameters) { + this.sslContextParameters = sslContextParameters; + } + + 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; + } + + SSLContext createSslContext() throws Exception { + return sslContextParameters != null ? sslContextParameters.createSSLContext() : null; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/e8578270/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdConstants.java ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdConstants.java b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdConstants.java new file mode 100644 index 0000000..88bc6ea --- /dev/null +++ b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdConstants.java @@ -0,0 +1,42 @@ +/** + * 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; + +public interface EtcdConstants { + String[] ETCD_DEFAULT_URIS = new String [] { + "http://localhost:2379", + "http://localhost:4001" + }; + + String ETCD_PATH_STATS = "/stats"; + String ETCD_PATH_WATCH = "/watch"; + String ETCD_PATH_KEYS = "/keys"; + + String ETCD_ACTION = "CamelEtcdAction"; + String ETCD_PATH = "CamelEtcdPath"; + String ETCD_TIMEOUT = "CamelEtcdTimeout"; + + String ETCD_KEYS_ACTION_SET = "set"; + String ETCD_KEYS_ACTION_DELETE = "delete"; + String ETCD_KEYS_ACTION_DELETE_DIR = "deleteDir"; + String ETCD_KEYS_ACTION_GET = "get"; + + + String ETCD_LEADER_STATS_PATH = "/stats/leader"; + String ETCD_SELF_STATS_PATH = "/stats/self"; + String ETCD_STORE_STATS_PATH = "/stats/store"; +} http://git-wip-us.apache.org/repos/asf/camel/blob/e8578270/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdKeysConfiguration.java ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdKeysConfiguration.java b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdKeysConfiguration.java new file mode 100644 index 0000000..ac46330 --- /dev/null +++ b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdKeysConfiguration.java @@ -0,0 +1,82 @@ +/** + * 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 org.apache.camel.spi.UriParam; +import org.apache.camel.spi.UriParams; +import org.apache.camel.util.ObjectHelper; + +@UriParams +class EtcdKeysConfiguration extends EtcdConfiguration { + @UriParam + private String path; + + @UriParam + private boolean recursive; + + @UriParam(label = "producer") + private Integer timeToLive; + + @UriParam(label = "producer,consumer") + private Long timeout; + + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public boolean hasPath() { + return ObjectHelper.isNotEmpty(path); + } + + public boolean isRecursive() { + return recursive; + } + + public void setRecursive(boolean recursive) { + this.recursive = recursive; + } + + + public Integer getTimeToLive() { + return timeToLive; + } + + public void setTimeToLive(Integer timeToLive) { + this.timeToLive = timeToLive; + } + + public boolean hasTimeToLive() { + return timeToLive != null && timeToLive > 0; + } + + public Long getTimeout() { + return timeout; + } + + public void setTimeout(Long timeout) { + this.timeout = timeout; + } + + public boolean hasTimeout() { + return timeout != null && timeout > 0; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/e8578270/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdKeysEndpoint.java ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdKeysEndpoint.java b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdKeysEndpoint.java new file mode 100644 index 0000000..e16f71d --- /dev/null +++ b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdKeysEndpoint.java @@ -0,0 +1,38 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.etcd; + +import org.apache.camel.Consumer; +import org.apache.camel.Processor; +import org.apache.camel.Producer; + +class EtcdKeysEndpoint extends AbstractEtcdEndpoint<EtcdKeysConfiguration> { + public EtcdKeysEndpoint( + String uri, EtcdComponent component, EtcdKeysConfiguration configuration, EtcdNamespace namespace, String path) { + super(uri, component, configuration, namespace, path); + } + + @Override + public Producer createProducer() throws Exception { + return new EtcdKeysProducer(this, getConfiguration(), getActionNamespace(), getPath()); + } + + @Override + public Consumer createConsumer(Processor processor) throws Exception { + throw new IllegalArgumentException("Consumer not enabled for " + getPath()); + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/e8578270/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdKeysProducer.java ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdKeysProducer.java b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdKeysProducer.java new file mode 100644 index 0000000..fc6395e --- /dev/null +++ b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdKeysProducer.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.component.etcd; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import mousio.etcd4j.EtcdClient; +import mousio.etcd4j.requests.EtcdKeyDeleteRequest; +import mousio.etcd4j.requests.EtcdKeyGetRequest; +import mousio.etcd4j.requests.EtcdKeyPutRequest; +import org.apache.camel.Exchange; +import org.apache.camel.ExchangeTimedOutException; +import org.apache.camel.util.ObjectHelper; + + +class EtcdKeysProducer extends AbstractEtcdProducer { + private final EtcdKeysConfiguration configuration; + private final String defaultPath; + + EtcdKeysProducer(EtcdKeysEndpoint endpoint, EtcdKeysConfiguration configuration, EtcdNamespace namespace, String path) { + super(endpoint, configuration, namespace, path); + + this.configuration = configuration; + this.defaultPath = endpoint.getRemainingPath(configuration.getPath()); + } + + @Override + public void process(Exchange exchange) throws Exception { + String action = exchange.getIn().getHeader(EtcdConstants.ETCD_ACTION, String.class); + String path = exchange.getIn().getHeader(EtcdConstants.ETCD_PATH, String.class); + if (path == null) { + path = defaultPath; + } + + ObjectHelper.notEmpty(path, EtcdConstants.ETCD_PATH); + ObjectHelper.notEmpty(action, EtcdConstants.ETCD_ACTION); + + switch(action) { + case EtcdConstants.ETCD_KEYS_ACTION_SET: + processSet(getClient(), path, exchange); + break; + case EtcdConstants.ETCD_KEYS_ACTION_GET: + processGet(getClient(), path, exchange); + break; + case EtcdConstants.ETCD_KEYS_ACTION_DELETE: + processDel(getClient(), path, false, exchange); + break; + case EtcdConstants.ETCD_KEYS_ACTION_DELETE_DIR: + processDel(getClient(), path, true, exchange); + break; + default: + throw new IllegalArgumentException("Unknown action " + action); + } + } + + // ************************************************************************* + // Processors + // ************************************************************************* + + private void processSet(EtcdClient client, String path, Exchange exchange) throws Exception { + EtcdKeyPutRequest request = client.put(path, exchange.getIn().getBody(String.class)); + if (configuration.hasTimeToLive()) { + request.ttl(configuration.getTimeToLive()); + } + if (configuration.hasTimeout()) { + request.timeout(configuration.getTimeout(), TimeUnit.MILLISECONDS); + } + + try { + exchange.getIn().setBody(request.send().get()); + } catch (TimeoutException e) { + throw new ExchangeTimedOutException(exchange, configuration.getTimeout()); + } + } + + private void processGet(EtcdClient client, String path, Exchange exchange) throws Exception { + EtcdKeyGetRequest request = client.get(path); + if (configuration.hasTimeout()) { + request.timeout(configuration.getTimeout(), TimeUnit.MILLISECONDS); + } + if (configuration.isRecursive()) { + request.recursive(); + } + + try { + exchange.getIn().setBody(request.send().get()); + } catch (TimeoutException e) { + throw new ExchangeTimedOutException(exchange, configuration.getTimeout()); + } + } + + private void processDel(EtcdClient client, String path, boolean dir, Exchange exchange) throws Exception { + EtcdKeyDeleteRequest request = client.delete(path); + if (configuration.hasTimeout()) { + request.timeout(configuration.getTimeout(), TimeUnit.MILLISECONDS); + } + if (configuration.isRecursive()) { + request.recursive(); + } + if (dir) { + request.dir(); + } + + try { + exchange.getIn().setBody(request.send().get()); + } catch (TimeoutException e) { + throw new ExchangeTimedOutException(exchange, configuration.getTimeout()); + } + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/e8578270/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdNamespace.java ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdNamespace.java b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdNamespace.java new file mode 100644 index 0000000..9d370d8 --- /dev/null +++ b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdNamespace.java @@ -0,0 +1,50 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.etcd; + +import org.apache.camel.util.ObjectHelper; + +enum EtcdNamespace { + STATS(EtcdConstants.ETCD_PATH_STATS), + WATCH(EtcdConstants.ETCD_PATH_WATCH), + KEYS(EtcdConstants.ETCD_PATH_KEYS); + + static final EtcdNamespace[] VALUES = values(); + + final String path; + + EtcdNamespace(String path) { + this.path = path; + } + + public String path() { + return path; + } + + + static EtcdNamespace fromPath(String name) { + if (ObjectHelper.isNotEmpty(name)) { + for (int i = VALUES.length - 1; i >= 0; --i) { + if (name.startsWith(VALUES[i].path)) { + return VALUES[i]; + } + } + } + + return null; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/e8578270/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdStatsConfiguration.java ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdStatsConfiguration.java b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdStatsConfiguration.java new file mode 100644 index 0000000..024b212 --- /dev/null +++ b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdStatsConfiguration.java @@ -0,0 +1,23 @@ +/** + * 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 org.apache.camel.spi.UriParams; + +@UriParams +class EtcdStatsConfiguration extends EtcdConfiguration { +} http://git-wip-us.apache.org/repos/asf/camel/blob/e8578270/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdStatsConsumer.java ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdStatsConsumer.java b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdStatsConsumer.java new file mode 100644 index 0000000..f9a8648 --- /dev/null +++ b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdStatsConsumer.java @@ -0,0 +1,50 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.etcd; + +import org.apache.camel.Exchange; +import org.apache.camel.Processor; + +class EtcdStatsConsumer extends AbstractEtcdPollingConsumer { + + EtcdStatsConsumer(EtcdStatsEndpoint endpoint, Processor processor, EtcdStatsConfiguration configuration, EtcdNamespace namespace, String path) { + super(endpoint, processor, configuration, namespace, path); + } + + @Override + public EtcdStatsEndpoint getEndpoint() { + return (EtcdStatsEndpoint)super.getEndpoint(); + } + + @Override + protected int poll() throws Exception { + EtcdStatsEndpoint endpoint = getEndpoint(); + Object answer = endpoint.getStats(getClient()); + + if (answer != null) { + Exchange exchange = endpoint.createExchange(); + exchange.getIn().setHeader(EtcdConstants.ETCD_PATH, getPath()); + exchange.getIn().setBody(answer); + + getProcessor().process(exchange); + + return 1; + } + + return 0; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/e8578270/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdStatsEndpoint.java ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdStatsEndpoint.java b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdStatsEndpoint.java new file mode 100644 index 0000000..e29e45d --- /dev/null +++ b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdStatsEndpoint.java @@ -0,0 +1,53 @@ +/** + * 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 mousio.etcd4j.EtcdClient; +import org.apache.camel.Consumer; +import org.apache.camel.Processor; +import org.apache.camel.Producer; + + +class EtcdStatsEndpoint extends AbstractEtcdEndpoint<EtcdStatsConfiguration> { + public EtcdStatsEndpoint( + String uri, EtcdComponent component, EtcdStatsConfiguration configuration, EtcdNamespace namespace, String path) { + super(uri, component, configuration, namespace, path); + } + + @Override + public Producer createProducer() throws Exception { + return new EtcdStatsProducer(this, getConfiguration(), getActionNamespace(), getPath()); + } + + @Override + public Consumer createConsumer(Processor processor) throws Exception { + return new EtcdStatsConsumer(this, processor, getConfiguration(), getActionNamespace(), getPath()); + } + + Object getStats(EtcdClient client) { + switch (getPath()) { + case EtcdConstants.ETCD_LEADER_STATS_PATH: + return client.getLeaderStats(); + case EtcdConstants.ETCD_SELF_STATS_PATH: + return client.getSelfStats(); + case EtcdConstants.ETCD_STORE_STATS_PATH: + return client.getStoreStats(); + default: + throw new IllegalStateException("No stats for " + getPath()); + } + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/e8578270/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdStatsProducer.java ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdStatsProducer.java b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdStatsProducer.java new file mode 100644 index 0000000..fbefe68 --- /dev/null +++ b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdStatsProducer.java @@ -0,0 +1,42 @@ +/** + * 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 org.apache.camel.Exchange; + + +class EtcdStatsProducer extends AbstractEtcdProducer { + EtcdStatsProducer(EtcdStatsEndpoint endpoint, EtcdStatsConfiguration configuration, EtcdNamespace namespace, String path) { + super(endpoint, configuration, namespace, path); + } + + @Override + public EtcdStatsEndpoint getEndpoint() { + return (EtcdStatsEndpoint)super.getEndpoint(); + } + + @Override + public void process(Exchange exchange) throws Exception { + EtcdStatsEndpoint endpoint = getEndpoint(); + Object answer = endpoint.getStats(getClient()); + + if (answer != null) { + exchange.getIn().setHeader(EtcdConstants.ETCD_PATH, getPath()); + exchange.getIn().setBody(answer); + } + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/e8578270/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdWatchConfiguration.java ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdWatchConfiguration.java b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdWatchConfiguration.java new file mode 100644 index 0000000..d5d1f9e --- /dev/null +++ b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdWatchConfiguration.java @@ -0,0 +1,36 @@ +/** + * 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 org.apache.camel.spi.UriParam; +import org.apache.camel.spi.UriParams; + +@UriParams +class EtcdWatchConfiguration extends EtcdKeysConfiguration { + + + @UriParam(defaultValue = "false") + boolean sendEmptyExchangeOnTimeout; + + public boolean isSendEmptyExchangeOnTimeout() { + return sendEmptyExchangeOnTimeout; + } + + public void setSendEmptyExchangeOnTimeout(boolean sendEmptyExchangeOnTimeout) { + this.sendEmptyExchangeOnTimeout = sendEmptyExchangeOnTimeout; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/e8578270/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdWatchConsumer.java ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdWatchConsumer.java b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdWatchConsumer.java new file mode 100644 index 0000000..23bb560 --- /dev/null +++ b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdWatchConsumer.java @@ -0,0 +1,113 @@ +/** + * 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.io.IOException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import mousio.client.promises.ResponsePromise; +import mousio.etcd4j.requests.EtcdKeyGetRequest; +import mousio.etcd4j.responses.EtcdKeysResponse; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +class EtcdWatchConsumer extends AbstractEtcdConsumer implements ResponsePromise.IsSimplePromiseResponseHandler<EtcdKeysResponse> { + private static final Logger LOGGER = LoggerFactory.getLogger(EtcdWatchConsumer.class); + + private final EtcdWatchEndpoint endpoint; + private final EtcdWatchConfiguration configuration; + private final String defaultPath; + + EtcdWatchConsumer(EtcdWatchEndpoint endpoint, Processor processor, EtcdWatchConfiguration configuration, EtcdNamespace namespace, String path) { + super(endpoint, processor, configuration, namespace, path); + + this.endpoint = endpoint; + this.configuration = configuration; + this.defaultPath = endpoint.getRemainingPath(configuration.getPath()); + } + + @Override + protected void doStart() throws Exception { + super.doStart(); + + watch(); + } + + @Override + protected void doStop() throws Exception { + super.doStop(); + } + + @Override + public void onResponse(ResponsePromise<EtcdKeysResponse> promise) { + if (!isRunAllowed()) { + return; + } + + try { + EtcdKeysResponse response = promise.get(); + + Exchange exchange = endpoint.createExchange(); + exchange.getIn().setHeader(EtcdConstants.ETCD_PATH, response.node.key); + exchange.getIn().setBody(response); + + getProcessor().process(exchange); + + watch(); + } catch (TimeoutException e) { + LOGGER.debug("Timeout watching for " + defaultPath); + + if (configuration.isSendEmptyExchangeOnTimeout()) { + try { + Exchange exchange = endpoint.createExchange(); + exchange.getIn().setHeader(EtcdConstants.ETCD_TIMEOUT, true); + exchange.getIn().setHeader(EtcdConstants.ETCD_PATH, defaultPath); + exchange.getIn().setBody(null); + + getProcessor().process(exchange); + } catch (Exception e1) { + throw new IllegalArgumentException(e); + } + } + } catch (Exception e) { + throw new IllegalArgumentException(e); + } + } + + private void watch() throws Exception { + if (!isRunAllowed()) { + return; + } + + EtcdKeyGetRequest request = getClient().get(defaultPath).waitForChange(); + if (configuration.isRecursive()) { + request.recursive(); + } + if (configuration.hasTimeout()) { + request.timeout(configuration.getTimeout(), TimeUnit.MILLISECONDS); + } + + try { + request.send().addListener(this); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/e8578270/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdWatchEndpoint.java ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdWatchEndpoint.java b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdWatchEndpoint.java new file mode 100644 index 0000000..3791dc0 --- /dev/null +++ b/components/camel-etcd/src/main/java/org/apache/camel/component/etcd/EtcdWatchEndpoint.java @@ -0,0 +1,39 @@ +/** + * 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 org.apache.camel.Consumer; +import org.apache.camel.Processor; +import org.apache.camel.Producer; + + +class EtcdWatchEndpoint extends AbstractEtcdEndpoint<EtcdWatchConfiguration> { + public EtcdWatchEndpoint( + String uri, EtcdComponent component, EtcdWatchConfiguration configuration, EtcdNamespace namespace, String path) { + super(uri, component, configuration, namespace, path); + } + + @Override + public Producer createProducer() throws Exception { + throw new IllegalArgumentException("Producer not enabled for " + getPath()); + } + + @Override + public Consumer createConsumer(Processor processor) throws Exception { + return new EtcdWatchConsumer(this, processor, getConfiguration(), getActionNamespace(), getPath()); + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/e8578270/components/camel-etcd/src/main/resources/META-INF/services/org/apache/camel/component/etcd ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/main/resources/META-INF/services/org/apache/camel/component/etcd b/components/camel-etcd/src/main/resources/META-INF/services/org/apache/camel/component/etcd new file mode 100644 index 0000000..5f6b3f0 --- /dev/null +++ b/components/camel-etcd/src/main/resources/META-INF/services/org/apache/camel/component/etcd @@ -0,0 +1 @@ +class=org.apache.camel.component.etcd.EtcdComponent http://git-wip-us.apache.org/repos/asf/camel/blob/e8578270/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 new file mode 100644 index 0000000..99590b5 --- /dev/null +++ b/components/camel-etcd/src/test/java/org/apache/camel/component/etcd/EtcdKeysTest.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.component.etcd; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import mousio.etcd4j.EtcdClient; +import mousio.etcd4j.responses.EtcdException; +import mousio.etcd4j.responses.EtcdKeysResponse; +import org.apache.camel.Exchange; +import org.apache.camel.Predicate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.junit.Ignore; +import org.junit.Test; + +@Ignore("Etcd must be started manually") +public class EtcdKeysTest extends EtcdTest { + + @Test(expected = EtcdException.class) + public void testKeys() throws Exception { + final String path = "/camel/" + UUID.randomUUID().toString(); + final String value = UUID.randomUUID().toString(); + final EtcdClient client = getClient(); + final Map<String, Object> headers = new HashMap<>(); + + // ******************************************* + // SET + // ******************************************* + + headers.clear(); + headers.put(EtcdConstants.ETCD_ACTION, EtcdConstants.ETCD_KEYS_ACTION_SET); + headers.put(EtcdConstants.ETCD_PATH, path); + + sendBody("direct:keys-set", value, headers); + + MockEndpoint mockSet = getMockEndpoint("mock:result-set"); + mockSet.expectedMinimumMessageCount(1); + mockSet.expectedHeaderReceived(EtcdConstants.ETCD_PATH, path); + mockSet.assertIsSatisfied(); + + // ******************************************* + // GET + // ******************************************* + + headers.clear(); + headers.put(EtcdConstants.ETCD_ACTION, EtcdConstants.ETCD_KEYS_ACTION_GET); + headers.put(EtcdConstants.ETCD_PATH, path); + + sendBody("direct:keys-get", value, headers); + + MockEndpoint mockGet = getMockEndpoint("mock:result-get"); + mockGet.expectedMinimumMessageCount(1); + mockGet.expectedHeaderReceived(EtcdConstants.ETCD_PATH, path); + mockGet.expectedMessagesMatches(new Predicate() { + @Override + public boolean matches(Exchange exchange) { + EtcdKeysResponse keysResponse = exchange.getIn().getBody(EtcdKeysResponse.class); + assertNotNull(keysResponse); + assertNotNull(keysResponse.node); + assertNotNull(keysResponse.node.value); + + return keysResponse.node.value.equals(value); + } + }); + + mockGet.assertIsSatisfied(); + + // ******************************************* + // DELETE + // ******************************************* + + headers.clear(); + headers.put(EtcdConstants.ETCD_ACTION, EtcdConstants.ETCD_KEYS_ACTION_DELETE); + headers.put(EtcdConstants.ETCD_PATH, path); + + sendBody("direct:keys-del", "value", headers); + + MockEndpoint mockDel = getMockEndpoint("mock:result-del"); + mockDel.expectedMinimumMessageCount(1); + mockDel.expectedHeaderReceived(EtcdConstants.ETCD_PATH, path); + mockDel.assertIsSatisfied(); + + // ******************************************* + // VALIDATION + // ******************************************* + + client.get(path).send().get(); + + fail("EtcdException should have been thrown"); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + public void configure() { + from("direct:keys-set") + .to("etcd:/keys") + .to("mock:result-set"); + from("direct:keys-get") + .to("etcd:/keys") + .to("mock:result-get"); + from("direct:keys-del") + .to("etcd:/keys") + .to("mock:result-del"); + } + }; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/e8578270/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 new file mode 100644 index 0000000..4bfcd07 --- /dev/null +++ b/components/camel-etcd/src/test/java/org/apache/camel/component/etcd/EtcdStatsTest.java @@ -0,0 +1,88 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.etcd; + +import mousio.etcd4j.responses.EtcdLeaderStatsResponse; +import mousio.etcd4j.responses.EtcdSelfStatsResponse; +import mousio.etcd4j.responses.EtcdStoreStatsResponse; +import org.apache.camel.Exchange; +import org.apache.camel.Predicate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.junit.Ignore; +import org.junit.Test; + +@Ignore("Etcd must be started manually") +public class EtcdStatsTest extends EtcdTest { + + @Test + public void testStats() throws Exception { + testStatsConsumer("mock:stats-leader-consumer", EtcdConstants.ETCD_LEADER_STATS_PATH, EtcdLeaderStatsResponse.class); + testStatsConsumer("mock:stats-self-consumer" , EtcdConstants.ETCD_SELF_STATS_PATH , EtcdSelfStatsResponse.class); + testStatsConsumer("mock:stats-store-consumer" , EtcdConstants.ETCD_STORE_STATS_PATH , EtcdStoreStatsResponse.class); + + testStatsProducer("direct:stats-leader", "mock:stats-leader-producer", EtcdConstants.ETCD_LEADER_STATS_PATH, EtcdLeaderStatsResponse.class); + testStatsProducer("direct:stats-self" , "mock:stats-self-producer" , EtcdConstants.ETCD_SELF_STATS_PATH , EtcdSelfStatsResponse.class); + testStatsProducer("direct:stats-store" , "mock:stats-store-producer" , EtcdConstants.ETCD_STORE_STATS_PATH , EtcdStoreStatsResponse.class); + } + + protected void testStatsConsumer(String mockEnpoint, String expectedPath, final Class<?> expectedType) throws Exception { + MockEndpoint mock = getMockEndpoint(mockEnpoint); + mock.expectedMinimumMessageCount(1); + mock.expectedHeaderReceived(EtcdConstants.ETCD_PATH, expectedPath); + mock.expectedMessagesMatches(new Predicate() { + @Override + public boolean matches(Exchange exchange) { + return exchange.getIn().getBody().getClass() == expectedType; + } + }); + + assertMockEndpointsSatisfied(); + } + + protected void testStatsProducer(String producerEnpoint, String mockEnpoint, String expectedPath, final Class<?> expectedType) throws Exception { + sendBody(producerEnpoint, ""); + + testStatsConsumer(mockEnpoint, expectedPath, expectedType); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + public void configure() { + // CONSUMER + from("etcd:/stats/leader?consumer.delay=50&consumer.initialDelay=0") + .to("mock:stats-leader-consumer"); + from("etcd:/stats/self?consumer.delay=50&consumer.initialDelay=0") + .to("mock:stats-self-consumer"); + from("etcd:/stats/store?consumer.delay=50&consumer.initialDelay=0") + .to("mock:stats-store-consumer"); + + // PRODUCER + from("direct:stats-leader") + .to("etcd:/stats/leader") + .to("mock:stats-leader-producer"); + from("direct:stats-self") + .to("etcd:/stats/self") + .to("mock:stats-self-producer"); + from("direct:stats-store") + .to("etcd:/stats/store") + .to("mock:stats-store-producer"); + } + }; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/e8578270/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 new file mode 100644 index 0000000..a8100e6 --- /dev/null +++ b/components/camel-etcd/src/test/java/org/apache/camel/component/etcd/EtcdTest.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 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/e8578270/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 new file mode 100644 index 0000000..2af853a --- /dev/null +++ b/components/camel-etcd/src/test/java/org/apache/camel/component/etcd/EtcdWatchTest.java @@ -0,0 +1,101 @@ +/** + * 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 mousio.etcd4j.EtcdClient; +import org.apache.camel.Exchange; +import org.apache.camel.Predicate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.junit.Ignore; +import org.junit.Test; + +@Ignore("Etcd must be started manually") +public class EtcdWatchTest extends EtcdTest { + + @Test + public void testWatchWithPath() throws Exception { + testWatch("mock:watch-with-path", "/myKey1", true); + } + + @Test + public void testWatchWithConfigPath() throws Exception { + testWatch("mock:watch-with-config-path", "/myKey2", true); + } + + @Test + public void testWatchRecursive() throws Exception { + testWatch("mock:watch-recursive", "/recursive/myKey1", true); + } + + @Test + public void testWatchWithTimeout() throws Exception { + MockEndpoint mock = getMockEndpoint("mock:watch-with-timeout"); + mock.expectedMessageCount(1); + mock.expectedHeaderReceived(EtcdConstants.ETCD_PATH, "/timeoutKey"); + mock.expectedHeaderReceived(EtcdConstants.ETCD_TIMEOUT, true); + mock.expectedMessagesMatches(new Predicate() { + @Override + public boolean matches(Exchange exchange) { + return exchange.getIn().getBody() == null; + } + }); + + mock.assertIsSatisfied(); + } + + private void testWatch(String mockEndpoint, final String key, boolean updateKey) throws Exception { + MockEndpoint mock = getMockEndpoint(mockEndpoint); + mock.expectedMessageCount(2); + mock.expectedHeaderReceived(EtcdConstants.ETCD_PATH, key); + mock.expectedMessagesMatches(new Predicate() { + @Override + public boolean matches(Exchange exchange) { + return exchange.getIn().getBody(String.class).startsWith(key + "=myValue-"); + } + }); + + if (updateKey) { + EtcdClient client = getClient(); + client.put(key, "myValue-1").send().get(); + Thread.sleep(250); + client.put(key, "myValue-2").send().get(); + } + + mock.assertIsSatisfied(); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + public void configure() { + from("etcd:/watch/myKey1") + .process(NODE_TO_VALUE_IN) + .to("mock:watch-with-path"); + from("etcd:/watch/recursive?recursive=true") + .process(NODE_TO_VALUE_IN) + .to("log:org.apache.camel.component.etcd?level=INFO") + .to("mock:watch-recursive"); + from("etcd:/watch?path=/myKey2") + .process(NODE_TO_VALUE_IN) + .to("mock:watch-with-config-path"); + from("etcd:/watch/timeoutKey?timeout=250&sendEmptyExchangeOnTimeout=true") + .to("mock:watch-with-timeout"); + } + }; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/e8578270/components/camel-etcd/src/test/resources/log4j.properties ---------------------------------------------------------------------- diff --git a/components/camel-etcd/src/test/resources/log4j.properties b/components/camel-etcd/src/test/resources/log4j.properties new file mode 100644 index 0000000..3b1bd38 --- /dev/null +++ b/components/camel-etcd/src/test/resources/log4j.properties @@ -0,0 +1,14 @@ +# +# The logging properties used +# +log4j.rootLogger=INFO, out + +# uncomment the following line to turn on Camel debugging +#log4j.logger.org.apache.camel=DEBUG + +# CONSOLE appender not used by default +log4j.appender.out=org.apache.log4j.ConsoleAppender +log4j.appender.out.layout=org.apache.log4j.PatternLayout +log4j.appender.out.layout.ConversionPattern=[%30.30t] %-30.30c{1} %-5p %m%n +#log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n + http://git-wip-us.apache.org/repos/asf/camel/blob/e8578270/components/pom.xml ---------------------------------------------------------------------- diff --git a/components/pom.xml b/components/pom.xml index 1e762a1..eafbc1a 100644 --- a/components/pom.xml +++ b/components/pom.xml @@ -96,6 +96,7 @@ <module>camel-ejb</module> <module>camel-elasticsearch</module> <module>camel-elsql</module> + <module>camel-etcd</module> <module>camel-eventadmin</module> <module>camel-exec</module> <module>camel-facebook</module> http://git-wip-us.apache.org/repos/asf/camel/blob/e8578270/parent/pom.xml ---------------------------------------------------------------------- diff --git a/parent/pom.xml b/parent/pom.xml index 4d51a25..758d331 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -157,6 +157,7 @@ <elsql-version>1.2</elsql-version> <el-api-1.0-version>1.0.1</el-api-1.0-version> <embedmongo-version>1.50.2</embedmongo-version> + <etcd4j-version>2.10.0</etcd4j-version> <exec-maven-plugin-version>1.4.0</exec-maven-plugin-version> <ezmorph-bundle-version>1.0.6_1</ezmorph-bundle-version> <facebook4j-core-version>2.4.2</facebook4j-core-version> http://git-wip-us.apache.org/repos/asf/camel/blob/e8578270/platforms/karaf/features/src/main/resources/features.xml ---------------------------------------------------------------------- diff --git a/platforms/karaf/features/src/main/resources/features.xml b/platforms/karaf/features/src/main/resources/features.xml index 160fc3c..12c429f 100644 --- a/platforms/karaf/features/src/main/resources/features.xml +++ b/platforms/karaf/features/src/main/resources/features.xml @@ -415,6 +415,12 @@ <bundle dependency='true'>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.elasticsearch/${elasticsearch-bundle-version}</bundle> <bundle>mvn:org.apache.camel/camel-elasticsearch/${project.version}</bundle> </feature> + <feature name='camel-etcd' version='${project.version}' resolver='(obr)' start-level='50'> + <feature version='${project.version}'>camel-core</feature> + <bundle dependency='true'>mvn:org.apache.commons/commons-lang3/${commons-lang3-version}</bundle> + <bundle dependency='true'>mvn:org.mousio/etcd4j/${etcd4j-version}</bundle> + <bundle>mvn:org.apache.camel/camel-etcd/${project.version}</bundle> + </feature> <feature name='camel-eventadmin' version='${project.version}' resolver='(obr)' start-level='50'> <feature>eventadmin</feature> <feature version='${project.version}'>camel-core</feature> http://git-wip-us.apache.org/repos/asf/camel/blob/e8578270/tests/camel-itest-karaf/src/test/java/org/apache/camel/itest/karaf/CamelEtcdTest.java ---------------------------------------------------------------------- diff --git a/tests/camel-itest-karaf/src/test/java/org/apache/camel/itest/karaf/CamelEtcdTest.java b/tests/camel-itest-karaf/src/test/java/org/apache/camel/itest/karaf/CamelEtcdTest.java new file mode 100644 index 0000000..50cdc81 --- /dev/null +++ b/tests/camel-itest-karaf/src/test/java/org/apache/camel/itest/karaf/CamelEtcdTest.java @@ -0,0 +1,40 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.itest.karaf; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.ops4j.pax.exam.Configuration; +import org.ops4j.pax.exam.Option; +import org.ops4j.pax.exam.junit.PaxExam; + +@RunWith(PaxExam.class) +public class CamelEtcdTest extends AbstractFeatureTest { + + public static final String COMPONENT = extractName(CamelEtcdTest.class); + + @Test + public void test() throws Exception { + testComponent(COMPONENT); + } + + @Configuration + public static Option[] configure() { + return configure(COMPONENT); + } + +} \ No newline at end of file
