From 8c4487db6c9ef96b360c20e3912eddd87c5b8f6e Mon Sep 17 00:00:00 2001 From: iverase Date: Mon, 24 Sep 2018 12:17:33 +0200 Subject: [PATCH 1/9] HLRC: Add activate watcher action Relates #29827 --- .../elasticsearch/client/WatcherClient.java | 29 +++++ .../client/WatcherRequestConverters.java | 14 +++ .../client/watcher/ActivateWatchRequest.java | 100 ++++++++++++++++++ .../client/watcher/ActivateWatchResponse.java | 72 +++++++++++++ .../org/elasticsearch/client/WatcherIT.java | 32 ++++++ .../client/WatcherRequestConvertersTests.java | 11 ++ .../documentation/WatcherDocumentationIT.java | 58 ++++++++++ .../high-level/supported-apis.asciidoc | 2 + .../watcher/activate-watch.asciidoc | 50 +++++++++ 9 files changed, 368 insertions(+) create mode 100644 client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActivateWatchRequest.java create mode 100644 client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActivateWatchResponse.java create mode 100644 docs/java-rest/high-level/watcher/activate-watch.asciidoc diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/WatcherClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/WatcherClient.java index b1a3eb3f87bf9..038c40f603d35 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/WatcherClient.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/WatcherClient.java @@ -19,6 +19,8 @@ package org.elasticsearch.client; import org.elasticsearch.action.ActionListener; +import org.elasticsearch.client.watcher.ActivateWatchRequest; +import org.elasticsearch.client.watcher.ActivateWatchResponse; import org.elasticsearch.protocol.xpack.watcher.DeleteWatchRequest; import org.elasticsearch.protocol.xpack.watcher.DeleteWatchResponse; import org.elasticsearch.protocol.xpack.watcher.PutWatchRequest; @@ -91,4 +93,31 @@ public void deleteWatchAsync(DeleteWatchRequest request, RequestOptions options, restHighLevelClient.performRequestAsyncAndParseEntity(request, WatcherRequestConverters::deleteWatch, options, DeleteWatchResponse::fromXContent, listener, singleton(404)); } + + /** + * Activate a watch from the cluster + * See + * the docs for more. + * @param request the request + * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @return the response + * @throws IOException in case there is a problem sending the request or parsing back the response + */ + public ActivateWatchResponse activateWatch(ActivateWatchRequest request, RequestOptions options) throws IOException { + return restHighLevelClient.performRequestAndParseEntity(request, WatcherRequestConverters::activateWatch, options, + ActivateWatchResponse::fromXContent, singleton(404)); + } + + /** + * Asynchronously activates a watch from the cluster + * See + * the docs for more. + * @param request the request + * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @param listener the listener to be notified upon request completion + */ + public void activateWatchAsync(ActivateWatchRequest request, RequestOptions options, ActionListener listener) { + restHighLevelClient.performRequestAsyncAndParseEntity(request, WatcherRequestConverters::activateWatch, options, + ActivateWatchResponse::fromXContent, listener, singleton(404)); + } } diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/WatcherRequestConverters.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/WatcherRequestConverters.java index 3b52d1c7b9943..17b7537beceac 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/WatcherRequestConverters.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/WatcherRequestConverters.java @@ -23,6 +23,7 @@ import org.apache.http.client.methods.HttpPut; import org.apache.http.entity.ByteArrayEntity; import org.apache.http.entity.ContentType; +import org.elasticsearch.client.watcher.ActivateWatchRequest; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.protocol.xpack.watcher.DeleteWatchRequest; import org.elasticsearch.protocol.xpack.watcher.PutWatchRequest; @@ -59,4 +60,17 @@ static Request deleteWatch(DeleteWatchRequest deleteWatchRequest) { Request request = new Request(HttpDelete.METHOD_NAME, endpoint); return request; } + + static Request activateWatch(ActivateWatchRequest activateWatchRequest) { + String endpoint = new RequestConverters.EndpointBuilder() + .addPathPartAsIs("_xpack") + .addPathPartAsIs("watcher") + .addPathPartAsIs("watch") + .addPathPartAsIs(activateWatchRequest.getWatchId()) + .addPathPart("_activate") + .build(); + + Request request = new Request(HttpPut.METHOD_NAME, endpoint); + return request; + } } diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActivateWatchRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActivateWatchRequest.java new file mode 100644 index 0000000000000..7fd5d4d114217 --- /dev/null +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActivateWatchRequest.java @@ -0,0 +1,100 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.client.watcher; + +import org.elasticsearch.client.Validatable; +import org.elasticsearch.client.ValidationException; +import org.elasticsearch.client.security.RefreshPolicy; +import org.elasticsearch.common.CharArrays; +import org.elasticsearch.common.xcontent.ToXContentObject; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.protocol.xpack.watcher.PutWatchRequest; + +import java.io.Closeable; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +/** + * A request to explicitly activate a watch. + */ +public final class ActivateWatchRequest implements Validatable, Closeable, ToXContentObject { + + private final String watchId; + + public ActivateWatchRequest(String watchId) { + this.watchId = Objects.requireNonNull(watchId, "Watch identifier is required"); + } + + /** + * @return The ID of the watch to be activated. + */ + public String getWatchId() { + return watchId; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ActivateWatchRequest that = (ActivateWatchRequest) o; + return Objects.equals(watchId, that.watchId); + } + + @Override + public int hashCode() { + int result = Objects.hash(watchId); + return result; + } + + @Override + public void close() { + } + + @Override + public Optional validate() { + + ValidationException exception = new ValidationException(); + + if (watchId == null) { + exception.addValidationError("watch id is missing"); + } else if (PutWatchRequest.isValidId(watchId) == false) { + exception.addValidationError("watch id contains whitespace"); + } + return !exception.validationErrors().isEmpty() + ? Optional.of(exception) + : Optional.empty(); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + return builder; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("activate [").append(watchId).append("]"); + return sb.toString(); + } +} diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActivateWatchResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActivateWatchResponse.java new file mode 100644 index 0000000000000..66c4b73887f1c --- /dev/null +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActivateWatchResponse.java @@ -0,0 +1,72 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.client.watcher; + +import org.elasticsearch.common.ParseField; +import org.elasticsearch.common.xcontent.ConstructingObjectParser; +import org.elasticsearch.common.xcontent.XContentParser; + +import java.io.IOException; +import java.util.Objects; + +/** + * Response from an 'activate watch' request. + */ +public final class ActivateWatchResponse { + + private final WatchStatus status; + + public ActivateWatchResponse(WatchStatus status) { + this.status = status; + } + + public WatchStatus getStatus() { + return status; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ActivateWatchResponse that = (ActivateWatchResponse) o; + return Objects.equals(status, that.status); + } + + @Override + public int hashCode() { + return Objects.hash(status); + } + + + private static final ParseField STATUS_FIELD = new ParseField("status"); + private static ConstructingObjectParser PARSER = + new ConstructingObjectParser<>("activate_watch_response", true, + a -> new ActivateWatchResponse((WatchStatus) a[0])); + + static { + PARSER.declareObject(ConstructingObjectParser.constructorArg(), + (parser, context) -> WatchStatus.parse(parser), + STATUS_FIELD); + } + + public static ActivateWatchResponse fromXContent(XContentParser parser) throws IOException { + return PARSER.parse(parser, null); + } +} diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/WatcherIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/WatcherIT.java index 491992735afbf..152e20644508b 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/WatcherIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/WatcherIT.java @@ -18,6 +18,9 @@ */ package org.elasticsearch.client; +import org.elasticsearch.ElasticsearchStatusException; +import org.elasticsearch.client.watcher.ActivateWatchRequest; +import org.elasticsearch.client.watcher.ActivateWatchResponse; import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.xcontent.XContentType; @@ -25,8 +28,10 @@ import org.elasticsearch.protocol.xpack.watcher.DeleteWatchResponse; import org.elasticsearch.protocol.xpack.watcher.PutWatchRequest; import org.elasticsearch.protocol.xpack.watcher.PutWatchResponse; +import org.elasticsearch.rest.RestStatus; import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.lessThan; public class WatcherIT extends ESRestHighLevelClientTestCase { @@ -72,4 +77,31 @@ public void testDeleteWatch() throws Exception { } } + public void testActivateWatch() throws Exception { + // Activate watch that exists + { + String watchId = randomAlphaOfLength(10); + createWatch(watchId); + ActivateWatchResponse activateWatchResponse1 = highLevelClient().watcher().activateWatch(new ActivateWatchRequest(watchId), + RequestOptions.DEFAULT); + assertThat(activateWatchResponse1.getStatus().state().isActive(), is(true)); + + ActivateWatchResponse activateWatchResponse2 = highLevelClient().watcher().activateWatch(new ActivateWatchRequest(watchId), + RequestOptions.DEFAULT); + assertThat(activateWatchResponse2.getStatus().state().isActive(), is(true)); + assertThat(activateWatchResponse1.getStatus().state().getTimestamp(), + lessThan(activateWatchResponse2.getStatus().state().getTimestamp())); + + } + + // Activate watch that does not exist + { + String watchId = randomAlphaOfLength(10); + // exception when activating a not existing watcher + ElasticsearchStatusException exception = expectThrows(ElasticsearchStatusException.class, () -> + highLevelClient().watcher().activateWatch(new ActivateWatchRequest(watchId), RequestOptions.DEFAULT)); + assertEquals(RestStatus.NOT_FOUND, exception.status()); + } + } + } diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/WatcherRequestConvertersTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/WatcherRequestConvertersTests.java index cf5af1dd5949f..6c8100561059d 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/WatcherRequestConvertersTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/WatcherRequestConvertersTests.java @@ -21,6 +21,7 @@ import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpPut; +import org.elasticsearch.client.watcher.ActivateWatchRequest; import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.protocol.xpack.watcher.DeleteWatchRequest; @@ -75,4 +76,14 @@ public void testDeleteWatch() { assertEquals("/_xpack/watcher/watch/" + watchId, request.getEndpoint()); assertThat(request.getEntity(), nullValue()); } + + public void testActivateWatch() { + String watchId = randomAlphaOfLength(10); + ActivateWatchRequest activateWatchRequest = new ActivateWatchRequest(watchId); + + Request request = WatcherRequestConverters.activateWatch(activateWatchRequest); + assertEquals(HttpPut.METHOD_NAME, request.getMethod()); + assertEquals("/_xpack/watcher/watch/" + watchId + "/_activate", request.getEndpoint()); + assertThat(request.getEntity(), nullValue()); + } } diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/WatcherDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/WatcherDocumentationIT.java index 707997d1f3103..ffeba9cb726da 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/WatcherDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/WatcherDocumentationIT.java @@ -23,6 +23,9 @@ import org.elasticsearch.client.ESRestHighLevelClientTestCase; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestHighLevelClient; +import org.elasticsearch.client.watcher.ActivateWatchRequest; +import org.elasticsearch.client.watcher.ActivateWatchResponse; +import org.elasticsearch.client.watcher.WatchStatus; import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.xcontent.XContentType; @@ -132,4 +135,59 @@ public void onFailure(Exception e) { } } + public void testActivateWatch() throws Exception { + RestHighLevelClient client = highLevelClient(); + + { + BytesReference watch = new BytesArray("{ \n" + + " \"trigger\": { \"schedule\": { \"interval\": \"10h\" } },\n" + + " \"input\": { \"simple\": { \"foo\" : \"bar\" } },\n" + + " \"actions\": { \"logme\": { \"logging\": { \"text\": \"{{ctx.payload}}\" } } }\n" + + "}"); + PutWatchRequest request = new PutWatchRequest("my_watch_id", watch, XContentType.JSON); + request.setActive(false); // <1> + PutWatchResponse response = client.watcher().putWatch(request, RequestOptions.DEFAULT); + } + + { + //tag::activate-watch-execute + ActivateWatchRequest request = new ActivateWatchRequest("my_watch_id"); + ActivateWatchResponse response = client.watcher().activateWatch(request, RequestOptions.DEFAULT); + //end::activate-watch-execute + + //tag::activate-watch-response + WatchStatus watchStatus = response.getStatus(); // <1> + //end::activate-watch-response + + assertTrue(watchStatus.state().isActive()); + } + + { + ActivateWatchRequest request = new ActivateWatchRequest("my_watch_id"); + //tag::activate-watch-execute-listener + ActionListener listener = new ActionListener() { + @Override + public void onResponse(ActivateWatchResponse response) { + // <1> + } + + @Override + public void onFailure(Exception e) { + // <2> + } + }; + //end::activate-watch-execute-listener + + //Replace the empty listener by a blocking listener in test + final CountDownLatch latch = new CountDownLatch(1); + listener = new LatchedActionListener<>(listener, latch); + + //tag::activate-watch-execute-async + client.watcher().activateWatchAsync(request, RequestOptions.DEFAULT, listener); // <1> + //end::activate-watch-execute-async + + assertTrue(latch.await(30L, TimeUnit.SECONDS)); + + } + } } diff --git a/docs/java-rest/high-level/supported-apis.asciidoc b/docs/java-rest/high-level/supported-apis.asciidoc index f91a2ed8e7507..b19a2ad3215eb 100644 --- a/docs/java-rest/high-level/supported-apis.asciidoc +++ b/docs/java-rest/high-level/supported-apis.asciidoc @@ -294,9 +294,11 @@ The Java High Level REST Client supports the following Watcher APIs: * <> * <> +* <> include::watcher/put-watch.asciidoc[] include::watcher/delete-watch.asciidoc[] +include::watcher/activate-watch.asciidoc[] == Graph APIs diff --git a/docs/java-rest/high-level/watcher/activate-watch.asciidoc b/docs/java-rest/high-level/watcher/activate-watch.asciidoc new file mode 100644 index 0000000000000..153eb3a090298 --- /dev/null +++ b/docs/java-rest/high-level/watcher/activate-watch.asciidoc @@ -0,0 +1,50 @@ +[[java-rest-high-watcher-activate-watch]] +=== Activate Watch API + +[[java-rest-high-watcher-activate-watch-execution]] +==== Execution + +A watch can be activated as follows: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/WatcherDocumentationIT.java[activate-watch-execute] +-------------------------------------------------- + +[[java-rest-high-watcher-activate-watch-response]] +==== Response + +The returned `ActivateWatchResponse` contains the new status of the activated watch. + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/WatcherDocumentationIT.java[activate-watch-response] +-------------------------------------------------- +<1> `watchStatus` contains status of the watch + +[[java-rest-high-watcher-activate-watch-async]] +==== Asynchronous Execution + +This request can be executed asynchronously: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/WatcherDocumentationIT.java[activate-watch-execute-async] +-------------------------------------------------- +<1> The `ActivateWatchRequest` to execute and the `ActionListener` to use when +the execution completes + +The asynchronous method does not block and returns immediately. Once it is +completed the `ActionListener` is called back using the `onResponse` method +if the execution successfully completed or using the `onFailure` method if +it failed. + +A typical listener for `ActivateWatchResponse` looks like: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/WatcherDocumentationIT.java[activate-watch-execute-listener] +-------------------------------------------------- +<1> Called when the execution is successfully completed. The response is +provided as an argument +<2> Called in case of failure. The raised exception is provided as an argument From 8533941814b3ee845cba5bf65afd59942fe034db Mon Sep 17 00:00:00 2001 From: iverase Date: Mon, 24 Sep 2018 12:32:56 +0200 Subject: [PATCH 2/9] remove unused imports --- .../elasticsearch/client/watcher/ActivateWatchRequest.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActivateWatchRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActivateWatchRequest.java index 7fd5d4d114217..97faa7e8d1c32 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActivateWatchRequest.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActivateWatchRequest.java @@ -21,18 +21,12 @@ import org.elasticsearch.client.Validatable; import org.elasticsearch.client.ValidationException; -import org.elasticsearch.client.security.RefreshPolicy; -import org.elasticsearch.common.CharArrays; import org.elasticsearch.common.xcontent.ToXContentObject; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.protocol.xpack.watcher.PutWatchRequest; import java.io.Closeable; import java.io.IOException; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.Optional; From 95c874ab4c1aea882603cbaf9b58408da28b715e Mon Sep 17 00:00:00 2001 From: iverase Date: Tue, 2 Oct 2018 16:43:14 +0200 Subject: [PATCH 3/9] Implemented first round of PR comments --- .../client/WatcherRequestConverters.java | 4 +- .../client/watcher/ActivateWatchRequest.java | 41 ++++--------------- .../client/watcher/ActivateWatchResponse.java | 1 - .../org/elasticsearch/client/WatcherIT.java | 41 ++++++++----------- 4 files changed, 28 insertions(+), 59 deletions(-) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/WatcherRequestConverters.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/WatcherRequestConverters.java index 17b7537beceac..9525eede115df 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/WatcherRequestConverters.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/WatcherRequestConverters.java @@ -66,8 +66,8 @@ static Request activateWatch(ActivateWatchRequest activateWatchRequest) { .addPathPartAsIs("_xpack") .addPathPartAsIs("watcher") .addPathPartAsIs("watch") - .addPathPartAsIs(activateWatchRequest.getWatchId()) - .addPathPart("_activate") + .addPathPart(activateWatchRequest.getWatchId()) + .addPathPartAsIs("_activate") .build(); Request request = new Request(HttpPut.METHOD_NAME, endpoint); diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActivateWatchRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActivateWatchRequest.java index 97faa7e8d1c32..3f415d95e0e91 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActivateWatchRequest.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActivateWatchRequest.java @@ -20,25 +20,26 @@ package org.elasticsearch.client.watcher; import org.elasticsearch.client.Validatable; -import org.elasticsearch.client.ValidationException; -import org.elasticsearch.common.xcontent.ToXContentObject; -import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.protocol.xpack.watcher.PutWatchRequest; import java.io.Closeable; -import java.io.IOException; import java.util.Objects; -import java.util.Optional; /** * A request to explicitly activate a watch. */ -public final class ActivateWatchRequest implements Validatable, Closeable, ToXContentObject { +public final class ActivateWatchRequest implements Validatable, Closeable { private final String watchId; public ActivateWatchRequest(String watchId) { - this.watchId = Objects.requireNonNull(watchId, "Watch identifier is required"); + if (watchId == null) { + throw new IllegalArgumentException("Watch identifier is required"); + } + if (PutWatchRequest.isValidId(watchId) == false) { + throw new IllegalArgumentException("Watch identifier contains whitespace"); + } + this.watchId = watchId; } /** @@ -65,30 +66,4 @@ public int hashCode() { @Override public void close() { } - - @Override - public Optional validate() { - - ValidationException exception = new ValidationException(); - - if (watchId == null) { - exception.addValidationError("watch id is missing"); - } else if (PutWatchRequest.isValidId(watchId) == false) { - exception.addValidationError("watch id contains whitespace"); - } - return !exception.validationErrors().isEmpty() - ? Optional.of(exception) - : Optional.empty(); - } - - @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - return builder; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder("activate [").append(watchId).append("]"); - return sb.toString(); - } } diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActivateWatchResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActivateWatchResponse.java index 66c4b73887f1c..be577cfe977cb 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActivateWatchResponse.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActivateWatchResponse.java @@ -54,7 +54,6 @@ public int hashCode() { return Objects.hash(status); } - private static final ParseField STATUS_FIELD = new ParseField("status"); private static ConstructingObjectParser PARSER = new ConstructingObjectParser<>("activate_watch_response", true, diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/WatcherIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/WatcherIT.java index 152e20644508b..ca4cdec0f1960 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/WatcherIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/WatcherIT.java @@ -77,31 +77,26 @@ public void testDeleteWatch() throws Exception { } } - public void testActivateWatch() throws Exception { - // Activate watch that exists - { - String watchId = randomAlphaOfLength(10); - createWatch(watchId); - ActivateWatchResponse activateWatchResponse1 = highLevelClient().watcher().activateWatch(new ActivateWatchRequest(watchId), - RequestOptions.DEFAULT); - assertThat(activateWatchResponse1.getStatus().state().isActive(), is(true)); - - ActivateWatchResponse activateWatchResponse2 = highLevelClient().watcher().activateWatch(new ActivateWatchRequest(watchId), - RequestOptions.DEFAULT); - assertThat(activateWatchResponse2.getStatus().state().isActive(), is(true)); - assertThat(activateWatchResponse1.getStatus().state().getTimestamp(), - lessThan(activateWatchResponse2.getStatus().state().getTimestamp())); + public void testActivateWatchThatExists() throws Exception { + String watchId = randomAlphaOfLength(10); + createWatch(watchId); + ActivateWatchResponse activateWatchResponse1 = highLevelClient().watcher().activateWatch(new ActivateWatchRequest(watchId), + RequestOptions.DEFAULT); + assertThat(activateWatchResponse1.getStatus().state().isActive(), is(true)); - } + ActivateWatchResponse activateWatchResponse2 = highLevelClient().watcher().activateWatch(new ActivateWatchRequest(watchId), + RequestOptions.DEFAULT); + assertThat(activateWatchResponse2.getStatus().state().isActive(), is(true)); + assertThat(activateWatchResponse1.getStatus().state().getTimestamp(), + lessThan(activateWatchResponse2.getStatus().state().getTimestamp())); + } - // Activate watch that does not exist - { - String watchId = randomAlphaOfLength(10); - // exception when activating a not existing watcher - ElasticsearchStatusException exception = expectThrows(ElasticsearchStatusException.class, () -> - highLevelClient().watcher().activateWatch(new ActivateWatchRequest(watchId), RequestOptions.DEFAULT)); - assertEquals(RestStatus.NOT_FOUND, exception.status()); - } + public void testActivateWatchThatDoesNotExist() throws Exception { + String watchId = randomAlphaOfLength(10); + // exception when activating a not existing watcher + ElasticsearchStatusException exception = expectThrows(ElasticsearchStatusException.class, () -> + highLevelClient().watcher().activateWatch(new ActivateWatchRequest(watchId), RequestOptions.DEFAULT)); + assertEquals(RestStatus.NOT_FOUND, exception.status()); } } From cdd2579a73fae66acc56ab7efd085551b1a30b97 Mon Sep 17 00:00:00 2001 From: iverase Date: Tue, 2 Oct 2018 16:46:08 +0200 Subject: [PATCH 4/9] rename test --- .../org/elasticsearch/client/WatcherRequestConvertersTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/WatcherRequestConvertersTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/WatcherRequestConvertersTests.java index 6c8100561059d..2ad74d6a082e9 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/WatcherRequestConvertersTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/WatcherRequestConvertersTests.java @@ -77,7 +77,7 @@ public void testDeleteWatch() { assertThat(request.getEntity(), nullValue()); } - public void testActivateWatch() { + public void testActivateWatchRequestConversion() { String watchId = randomAlphaOfLength(10); ActivateWatchRequest activateWatchRequest = new ActivateWatchRequest(watchId); From 4a3db3013a446fae847f897976cb80d939612450 Mon Sep 17 00:00:00 2001 From: iverase Date: Wed, 3 Oct 2018 11:00:25 +0200 Subject: [PATCH 5/9] Update docs and cos test using new approach --- .../documentation/WatcherDocumentationIT.java | 16 +++++------ .../high-level/supported-apis.asciidoc | 5 +++- .../watcher/activate-watch.asciidoc | 28 +++++++++++-------- 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/WatcherDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/WatcherDocumentationIT.java index ffeba9cb726da..486c7cbbbf9d3 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/WatcherDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/WatcherDocumentationIT.java @@ -150,21 +150,21 @@ public void testActivateWatch() throws Exception { } { - //tag::activate-watch-execute + //tag::activate-watch-request ActivateWatchRequest request = new ActivateWatchRequest("my_watch_id"); ActivateWatchResponse response = client.watcher().activateWatch(request, RequestOptions.DEFAULT); - //end::activate-watch-execute + //end::activate-watch-request - //tag::activate-watch-response + //tag::activate-watch-request WatchStatus watchStatus = response.getStatus(); // <1> - //end::activate-watch-response + //end::activate-watch-request assertTrue(watchStatus.state().isActive()); } { ActivateWatchRequest request = new ActivateWatchRequest("my_watch_id"); - //tag::activate-watch-execute-listener + //tag::activate-watch-request-listener ActionListener listener = new ActionListener() { @Override public void onResponse(ActivateWatchResponse response) { @@ -176,15 +176,15 @@ public void onFailure(Exception e) { // <2> } }; - //end::activate-watch-execute-listener + //end::activate-watch-request-listener //Replace the empty listener by a blocking listener in test final CountDownLatch latch = new CountDownLatch(1); listener = new LatchedActionListener<>(listener, latch); - //tag::activate-watch-execute-async + //tag::activate-watch-request-async client.watcher().activateWatchAsync(request, RequestOptions.DEFAULT, listener); // <1> - //end::activate-watch-execute-async + //end::activate-watch-request-async assertTrue(latch.await(30L, TimeUnit.SECONDS)); diff --git a/docs/java-rest/high-level/supported-apis.asciidoc b/docs/java-rest/high-level/supported-apis.asciidoc index 9cefe6617daf6..3bb221f27387e 100644 --- a/docs/java-rest/high-level/supported-apis.asciidoc +++ b/docs/java-rest/high-level/supported-apis.asciidoc @@ -306,11 +306,14 @@ include::security/change-password.asciidoc[] == Watcher APIs +:upid: {mainid}-document +:doc-tests-file: {doc-tests}/WatcherDocumentationIT.java + The Java High Level REST Client supports the following Watcher APIs: * <> * <> -* <> +* <<{upid}-activate-watch>> include::watcher/put-watch.asciidoc[] include::watcher/delete-watch.asciidoc[] diff --git a/docs/java-rest/high-level/watcher/activate-watch.asciidoc b/docs/java-rest/high-level/watcher/activate-watch.asciidoc index 153eb3a090298..52124ccb6eddb 100644 --- a/docs/java-rest/high-level/watcher/activate-watch.asciidoc +++ b/docs/java-rest/high-level/watcher/activate-watch.asciidoc @@ -1,37 +1,43 @@ -[[java-rest-high-watcher-activate-watch]] +-- +:api: activate-watch +:request: ActivateWatchRequest +:response: ActivateWatchResponse +-- + +[id="{upid}-{api}"] === Activate Watch API -[[java-rest-high-watcher-activate-watch-execution]] +[id="{upid}-{api}-request"] ==== Execution A watch can be activated as follows: ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- -include-tagged::{doc-tests}/WatcherDocumentationIT.java[activate-watch-execute] +include-tagged::{doc-tests-file}[{api}-request] -------------------------------------------------- -[[java-rest-high-watcher-activate-watch-response]] +[id="{upid}-{api}-response"] ==== Response -The returned `ActivateWatchResponse` contains the new status of the activated watch. +The returned +{response}+ contains the new status of the activated watch. ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- -include-tagged::{doc-tests}/WatcherDocumentationIT.java[activate-watch-response] +include-tagged::{doc-tests-file}[{api}-response] -------------------------------------------------- <1> `watchStatus` contains status of the watch -[[java-rest-high-watcher-activate-watch-async]] +[id="{upid}-{api}-request-async"] ==== Asynchronous Execution This request can be executed asynchronously: ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- -include-tagged::{doc-tests}/WatcherDocumentationIT.java[activate-watch-execute-async] +include-tagged::{doc-tests-file}[{api}-request-async] -------------------------------------------------- -<1> The `ActivateWatchRequest` to execute and the `ActionListener` to use when +<1> The +{request}+ to execute and the `ActionListener` to use when the execution completes The asynchronous method does not block and returns immediately. Once it is @@ -39,11 +45,11 @@ completed the `ActionListener` is called back using the `onResponse` method if the execution successfully completed or using the `onFailure` method if it failed. -A typical listener for `ActivateWatchResponse` looks like: +A typical listener for +{response}+ looks like: ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- -include-tagged::{doc-tests}/WatcherDocumentationIT.java[activate-watch-execute-listener] +include-tagged::{doc-tests-file}[{api}-request-listener] -------------------------------------------------- <1> Called when the execution is successfully completed. The response is provided as an argument From 04ed79a54df9ee8439416a707d607df5abbd8773 Mon Sep 17 00:00:00 2001 From: iverase Date: Wed, 3 Oct 2018 12:02:11 +0200 Subject: [PATCH 6/9] remove extra space --- .../org/elasticsearch/client/WatcherRequestConverters.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/WatcherRequestConverters.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/WatcherRequestConverters.java index 42acc04bba380..0baa42428cd2d 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/WatcherRequestConverters.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/WatcherRequestConverters.java @@ -61,8 +61,7 @@ static Request deleteWatch(DeleteWatchRequest deleteWatchRequest) { Request request = new Request(HttpDelete.METHOD_NAME, endpoint); return request; } - - + public static Request ackWatch(AckWatchRequest ackWatchRequest) { String endpoint = new RequestConverters.EndpointBuilder() .addPathPartAsIs("_xpack") From 78f88d0cc12ee38388073980e64d2fedcccb3160 Mon Sep 17 00:00:00 2001 From: iverase Date: Wed, 3 Oct 2018 12:13:34 +0200 Subject: [PATCH 7/9] add response test --- .../client/WatcherRequestConverters.java | 2 +- .../watcher/ActivateWatchResponseTests.java | 113 ++++++++++++++++++ 2 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 client/rest-high-level/src/test/java/org/elasticsearch/client/watcher/ActivateWatchResponseTests.java diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/WatcherRequestConverters.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/WatcherRequestConverters.java index 0baa42428cd2d..3a17056f9bf4c 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/WatcherRequestConverters.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/WatcherRequestConverters.java @@ -61,7 +61,7 @@ static Request deleteWatch(DeleteWatchRequest deleteWatchRequest) { Request request = new Request(HttpDelete.METHOD_NAME, endpoint); return request; } - + public static Request ackWatch(AckWatchRequest ackWatchRequest) { String endpoint = new RequestConverters.EndpointBuilder() .addPathPartAsIs("_xpack") diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/watcher/ActivateWatchResponseTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/watcher/ActivateWatchResponseTests.java new file mode 100644 index 0000000000000..136ecbc58c150 --- /dev/null +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/watcher/ActivateWatchResponseTests.java @@ -0,0 +1,113 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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.elasticsearch.client.watcher; + +import org.elasticsearch.common.bytes.BytesReference; +import org.elasticsearch.common.xcontent.NamedXContentRegistry; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.common.xcontent.XContentParseException; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.test.XContentTestUtils; + +import java.io.IOException; +import java.util.function.Predicate; + +/** + * Basic unit tests for {@link ActivateWatchResponse}. + * + * Note that we only sanity check watch status parsing here, as there + * are dedicated tests for it in {@link WatchStatusTests}. + */ +public class ActivateWatchResponseTests extends ESTestCase { + + public void testBasicParsing() throws IOException { + XContentType contentType = randomFrom(XContentType.values()); + XContentBuilder builder = XContentFactory.contentBuilder(contentType).startObject() + .startObject("status") + .field("version", 42) + .field("execution_state", ExecutionState.ACKNOWLEDGED) + .startObject("state") + .field("active", false) + .endObject() + .endObject() + .endObject(); + BytesReference bytes = BytesReference.bytes(builder); + + ActivateWatchResponse response = parse(builder.contentType(), bytes); + WatchStatus status = response.getStatus(); + assertNotNull(status); + assertEquals(42, status.version()); + assertEquals(ExecutionState.ACKNOWLEDGED, status.getExecutionState()); + assertFalse(status.state().isActive()); + } + + public void testParsingWithMissingStatus() throws IOException { + XContentType contentType = randomFrom(XContentType.values()); + XContentBuilder builder = XContentFactory.contentBuilder(contentType).startObject().endObject(); + BytesReference bytes = BytesReference.bytes(builder); + + expectThrows(IllegalArgumentException.class, () -> parse(builder.contentType(), bytes)); + } + + public void testParsingWithNullStatus() throws IOException { + XContentType contentType = randomFrom(XContentType.values()); + XContentBuilder builder = XContentFactory.contentBuilder(contentType).startObject() + .nullField("status") + .endObject(); + BytesReference bytes = BytesReference.bytes(builder); + + expectThrows(XContentParseException.class, () -> parse(builder.contentType(), bytes)); + } + + public void testParsingWithUnknownKeys() throws IOException { + XContentType contentType = randomFrom(XContentType.values()); + XContentBuilder builder = XContentFactory.contentBuilder(contentType).startObject() + .startObject("status") + .field("version", 42) + .field("execution_state", ExecutionState.ACKNOWLEDGED) + .startObject("state") + .field("active", true) + .endObject() + .endObject() + .endObject(); + BytesReference bytes = BytesReference.bytes(builder); + + Predicate excludeFilter = field -> field.equals("status.actions"); + BytesReference bytesWithRandomFields = XContentTestUtils.insertRandomFields( + builder.contentType(), bytes, excludeFilter, random()); + + ActivateWatchResponse response = parse(builder.contentType(), bytesWithRandomFields); + WatchStatus status = response.getStatus(); + assertNotNull(status); + assertEquals(42, status.version()); + assertEquals(ExecutionState.ACKNOWLEDGED, status.getExecutionState()); + assertTrue(status.state().isActive()); + } + + private ActivateWatchResponse parse(XContentType contentType, BytesReference bytes) throws IOException { + XContentParser parser = XContentFactory.xContent(contentType) + .createParser(NamedXContentRegistry.EMPTY, null, bytes.streamInput()); + parser.nextToken(); + return ActivateWatchResponse.fromXContent(parser); + } +} From 779965582d23809f81a6bd1e4d216811c632acf8 Mon Sep 17 00:00:00 2001 From: iverase Date: Wed, 3 Oct 2018 21:39:16 +0200 Subject: [PATCH 8/9] clean up request and response classes --- .../client/watcher/ActivateWatchRequest.java | 13 +++-------- .../client/watcher/ActivateWatchResponse.java | 22 +++++++++---------- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActivateWatchRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActivateWatchRequest.java index 3f415d95e0e91..5810ec9a5a9e5 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActivateWatchRequest.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActivateWatchRequest.java @@ -28,18 +28,15 @@ /** * A request to explicitly activate a watch. */ -public final class ActivateWatchRequest implements Validatable, Closeable { +public final class ActivateWatchRequest implements Validatable { private final String watchId; public ActivateWatchRequest(String watchId) { - if (watchId == null) { - throw new IllegalArgumentException("Watch identifier is required"); - } - if (PutWatchRequest.isValidId(watchId) == false) { + this.watchId = Objects.requireNonNull(watchId, "Watch identifier is required"); + if (PutWatchRequest.isValidId(this.watchId) == false) { throw new IllegalArgumentException("Watch identifier contains whitespace"); } - this.watchId = watchId; } /** @@ -62,8 +59,4 @@ public int hashCode() { int result = Objects.hash(watchId); return result; } - - @Override - public void close() { - } } diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActivateWatchResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActivateWatchResponse.java index be577cfe977cb..b1e63e767f3be 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActivateWatchResponse.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActivateWatchResponse.java @@ -31,6 +31,17 @@ */ public final class ActivateWatchResponse { + private static final ParseField STATUS_FIELD = new ParseField("status"); + private static ConstructingObjectParser PARSER = + new ConstructingObjectParser<>("activate_watch_response", true, + a -> new ActivateWatchResponse((WatchStatus) a[0])); + + static { + PARSER.declareObject(ConstructingObjectParser.constructorArg(), + (parser, context) -> WatchStatus.parse(parser), + STATUS_FIELD); + } + private final WatchStatus status; public ActivateWatchResponse(WatchStatus status) { @@ -54,17 +65,6 @@ public int hashCode() { return Objects.hash(status); } - private static final ParseField STATUS_FIELD = new ParseField("status"); - private static ConstructingObjectParser PARSER = - new ConstructingObjectParser<>("activate_watch_response", true, - a -> new ActivateWatchResponse((WatchStatus) a[0])); - - static { - PARSER.declareObject(ConstructingObjectParser.constructorArg(), - (parser, context) -> WatchStatus.parse(parser), - STATUS_FIELD); - } - public static ActivateWatchResponse fromXContent(XContentParser parser) throws IOException { return PARSER.parse(parser, null); } From d60242437641847b8d1a9818c059b28cb1078da1 Mon Sep 17 00:00:00 2001 From: iverase Date: Wed, 3 Oct 2018 21:54:29 +0200 Subject: [PATCH 9/9] remove unused import --- .../org/elasticsearch/client/watcher/ActivateWatchRequest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActivateWatchRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActivateWatchRequest.java index 5810ec9a5a9e5..7f2849ff39c0c 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActivateWatchRequest.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/watcher/ActivateWatchRequest.java @@ -22,7 +22,6 @@ import org.elasticsearch.client.Validatable; import org.elasticsearch.protocol.xpack.watcher.PutWatchRequest; -import java.io.Closeable; import java.util.Objects; /**