diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java new file mode 100644 index 00000000000..2cc1d4849d5 --- /dev/null +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java @@ -0,0 +1,63 @@ +/* + * 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; + +import org.apache.http.Header; +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; +import org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse; + +import java.io.IOException; +import java.util.Collections; + +/** + * A wrapper for the {@link RestHighLevelClient} that provides methods for accessing the Indices API. + * + * See Indices API on elastic.co + */ +public final class IndicesClient { + private final RestHighLevelClient restHighLevelClient; + + public IndicesClient(RestHighLevelClient restHighLevelClient) { + this.restHighLevelClient = restHighLevelClient; + } + + /** + * Deletes an index using the Delete Index API + *

+ * See + * Delete Index API on elastic.co + */ + public DeleteIndexResponse deleteIndex(DeleteIndexRequest deleteIndexRequest, Header... headers) throws IOException { + return restHighLevelClient.performRequestAndParseEntity(deleteIndexRequest, Request::deleteIndex, DeleteIndexResponse::fromXContent, + Collections.emptySet(), headers); + } + + /** + * Asynchronously deletes an index using the Delete Index API + *

+ * See + * Delete Index API on elastic.co + */ + public void deleteIndexAsync(DeleteIndexRequest deleteIndexRequest, ActionListener listener, Header... headers) { + restHighLevelClient.performRequestAsyncAndParseEntity(deleteIndexRequest, Request::deleteIndex, DeleteIndexResponse::fromXContent, + listener, Collections.emptySet(), headers); + } +} diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/Request.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/Request.java old mode 100644 new mode 100755 index 7a95553c3c0..4da68e98e2d --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/Request.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/Request.java @@ -29,6 +29,7 @@ import org.apache.http.entity.ByteArrayEntity; import org.apache.http.entity.ContentType; import org.apache.lucene.util.BytesRef; import org.elasticsearch.action.DocWriteRequest; +import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.delete.DeleteRequest; import org.elasticsearch.action.get.GetRequest; @@ -123,6 +124,17 @@ public final class Request { return new Request(HttpDelete.METHOD_NAME, endpoint, parameters.getParams(), null); } + static Request deleteIndex(DeleteIndexRequest deleteIndexRequest) { + String endpoint = endpoint(deleteIndexRequest.indices(), Strings.EMPTY_ARRAY, ""); + + Params parameters = Params.builder(); + parameters.withTimeout(deleteIndexRequest.timeout()); + parameters.withMasterTimeout(deleteIndexRequest.masterNodeTimeout()); + parameters.withIndicesOptions(deleteIndexRequest.indicesOptions()); + + return new Request(HttpDelete.METHOD_NAME, endpoint, parameters.getParams(), null); + } + static Request info() { return new Request(HttpGet.METHOD_NAME, "/", Collections.emptyMap(), null); } @@ -449,6 +461,10 @@ public final class Request { return this; } + Params withMasterTimeout(TimeValue masterTimeout) { + return putParam("master_timeout", masterTimeout); + } + Params withParent(String parent) { return putParam("parent", parent); } diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java old mode 100644 new mode 100755 index 25697abb82e..bc3538930d3 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java @@ -176,6 +176,8 @@ public class RestHighLevelClient implements Closeable { private final NamedXContentRegistry registry; private final CheckedConsumer doClose; + private final IndicesClient indicesClient = new IndicesClient(this); + /** * Creates a {@link RestHighLevelClient} given the low level {@link RestClientBuilder} that allows to build the * {@link RestClient} to be used to perform requests. @@ -220,6 +222,15 @@ public class RestHighLevelClient implements Closeable { doClose.accept(client); } + /** + * Provides an {@link IndicesClient} which can be used to access the Indices API. + * + * See Indices API on elastic.co + */ + public IndicesClient indices() { + return indicesClient; + } + /** * Executes a bulk request using the Bulk API * @@ -327,7 +338,7 @@ public class RestHighLevelClient implements Closeable { } /** - * Deletes a document by id using the Delete api + * Deletes a document by id using the Delete API * * See Delete API on elastic.co */ @@ -337,7 +348,7 @@ public class RestHighLevelClient implements Closeable { } /** - * Asynchronously deletes a document by id using the Delete api + * Asynchronously deletes a document by id using the Delete API * * See Delete API on elastic.co */ @@ -347,7 +358,7 @@ public class RestHighLevelClient implements Closeable { } /** - * Executes a search using the Search api + * Executes a search using the Search API * * See Search API on elastic.co */ @@ -356,7 +367,7 @@ public class RestHighLevelClient implements Closeable { } /** - * Asynchronously executes a search using the Search api + * Asynchronously executes a search using the Search API * * See Search API on elastic.co */ @@ -365,7 +376,7 @@ public class RestHighLevelClient implements Closeable { } /** - * Executes a search using the Search Scroll api + * Executes a search using the Search Scroll API * * See Search Scroll * API on elastic.co @@ -375,7 +386,7 @@ public class RestHighLevelClient implements Closeable { } /** - * Asynchronously executes a search using the Search Scroll api + * Asynchronously executes a search using the Search Scroll API * * See Search Scroll * API on elastic.co @@ -386,7 +397,7 @@ public class RestHighLevelClient implements Closeable { } /** - * Clears one or more scroll ids using the Clear Scroll api + * Clears one or more scroll ids using the Clear Scroll API * * See * Clear Scroll API on elastic.co @@ -397,7 +408,7 @@ public class RestHighLevelClient implements Closeable { } /** - * Asynchronously clears one or more scroll ids using the Clear Scroll api + * Asynchronously clears one or more scroll ids using the Clear Scroll API * * See * Clear Scroll API on elastic.co diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java new file mode 100755 index 00000000000..4045e565288 --- /dev/null +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java @@ -0,0 +1,68 @@ +/* + * 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; + +import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; +import org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse; +import org.elasticsearch.rest.RestStatus; + +import java.io.IOException; + +public class IndicesClientIT extends ESRestHighLevelClientTestCase { + + public void testDeleteIndex() throws IOException { + { + // Delete index if exists + String indexName = "test_index"; + createIndex(indexName); + + DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(indexName); + DeleteIndexResponse deleteIndexResponse = + execute(deleteIndexRequest, highLevelClient().indices()::deleteIndex, highLevelClient().indices()::deleteIndexAsync); + assertTrue(deleteIndexResponse.isAcknowledged()); + + assertFalse(indexExists(indexName)); + } + { + // Return 404 if index doesn't exist + String nonExistentIndex = "non_existent_index"; + assertFalse(indexExists(nonExistentIndex)); + + DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(nonExistentIndex); + + ElasticsearchException exception = expectThrows(ElasticsearchException.class, + () -> execute(deleteIndexRequest, highLevelClient().indices()::deleteIndex, highLevelClient().indices()::deleteIndexAsync)); + assertEquals(RestStatus.NOT_FOUND, exception.status()); + } + } + + private static void createIndex(String index) throws IOException { + Response response = client().performRequest("PUT", index); + + assertEquals(200, response.getStatusLine().getStatusCode()); + } + + private static boolean indexExists(String index) throws IOException { + Response response = client().performRequest("HEAD", index); + + return response.getStatusLine().getStatusCode() == 200; + } +} diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestTests.java old mode 100644 new mode 100755 index 8f52eb37fe9..3be250d513d --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestTests.java @@ -25,6 +25,7 @@ import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.util.EntityUtils; import org.elasticsearch.action.DocWriteRequest; +import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkShardRequest; import org.elasticsearch.action.delete.DeleteRequest; @@ -36,6 +37,8 @@ import org.elasticsearch.action.search.SearchScrollRequest; import org.elasticsearch.action.search.SearchType; import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.action.support.WriteRequest; +import org.elasticsearch.action.support.master.AcknowledgedRequest; +import org.elasticsearch.action.support.master.MasterNodeRequest; import org.elasticsearch.action.support.replication.ReplicatedWriteRequest; import org.elasticsearch.action.support.replication.ReplicationRequest; import org.elasticsearch.action.update.UpdateRequest; @@ -44,6 +47,7 @@ import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.io.Streams; import org.elasticsearch.common.lucene.uid.Versions; +import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentHelper; @@ -74,6 +78,7 @@ import java.util.Map; import java.util.StringJoiner; import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.Supplier; import static java.util.Collections.singletonMap; import static org.elasticsearch.client.Request.enforceSameContentType; @@ -139,7 +144,7 @@ public class RequestTests extends ESTestCase { Map expectedParams = new HashMap<>(); - setRandomTimeout(deleteRequest, expectedParams); + setRandomTimeout(deleteRequest::timeout, ReplicationRequest.DEFAULT_TIMEOUT, expectedParams); setRandomRefreshPolicy(deleteRequest, expectedParams); setRandomVersion(deleteRequest, expectedParams); setRandomVersionType(deleteRequest, expectedParams); @@ -240,6 +245,30 @@ public class RequestTests extends ESTestCase { assertEquals(method, request.getMethod()); } + public void testDeleteIndex() throws IOException { + DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(); + + int numIndices = randomIntBetween(0, 5); + String[] indices = new String[numIndices]; + for (int i = 0; i < numIndices; i++) { + indices[i] = "index-" + randomAlphaOfLengthBetween(2, 5); + } + deleteIndexRequest.indices(indices); + + Map expectedParams = new HashMap<>(); + + setRandomTimeout(deleteIndexRequest::timeout, AcknowledgedRequest.DEFAULT_ACK_TIMEOUT, expectedParams); + setRandomMasterTimeout(deleteIndexRequest, expectedParams); + + setRandomIndicesOptions(deleteIndexRequest::indicesOptions, deleteIndexRequest::indicesOptions, expectedParams); + + Request request = Request.deleteIndex(deleteIndexRequest); + assertEquals("/" + String.join(",", indices), request.getEndpoint()); + assertEquals(expectedParams, request.getParameters()); + assertEquals("DELETE", request.getMethod()); + assertNull(request.getEntity()); + } + public void testIndex() throws IOException { String index = randomAlphaOfLengthBetween(3, 10); String type = randomAlphaOfLengthBetween(3, 10); @@ -258,7 +287,7 @@ public class RequestTests extends ESTestCase { } } - setRandomTimeout(indexRequest, expectedParams); + setRandomTimeout(indexRequest::timeout, ReplicationRequest.DEFAULT_TIMEOUT, expectedParams); setRandomRefreshPolicy(indexRequest, expectedParams); // There is some logic around _create endpoint and version/version type @@ -678,20 +707,7 @@ public class RequestTests extends ESTestCase { expectedParams.put("scroll", searchRequest.scroll().keepAlive().getStringRep()); } - if (randomBoolean()) { - searchRequest.indicesOptions(IndicesOptions.fromOptions(randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean())); - } - expectedParams.put("ignore_unavailable", Boolean.toString(searchRequest.indicesOptions().ignoreUnavailable())); - expectedParams.put("allow_no_indices", Boolean.toString(searchRequest.indicesOptions().allowNoIndices())); - if (searchRequest.indicesOptions().expandWildcardsOpen() && searchRequest.indicesOptions().expandWildcardsClosed()) { - expectedParams.put("expand_wildcards", "open,closed"); - } else if (searchRequest.indicesOptions().expandWildcardsOpen()) { - expectedParams.put("expand_wildcards", "open"); - } else if (searchRequest.indicesOptions().expandWildcardsClosed()) { - expectedParams.put("expand_wildcards", "closed"); - } else { - expectedParams.put("expand_wildcards", "none"); - } + setRandomIndicesOptions(searchRequest::indicesOptions, searchRequest::indicesOptions, expectedParams); SearchSourceBuilder searchSourceBuilder = null; if (frequently()) { @@ -903,13 +919,43 @@ public class RequestTests extends ESTestCase { } } - private static void setRandomTimeout(ReplicationRequest request, Map expectedParams) { + private static void setRandomIndicesOptions(Consumer setter, Supplier getter, + Map expectedParams) { + + if (randomBoolean()) { + setter.accept(IndicesOptions.fromOptions(randomBoolean(), randomBoolean(), randomBoolean(), + randomBoolean())); + } + expectedParams.put("ignore_unavailable", Boolean.toString(getter.get().ignoreUnavailable())); + expectedParams.put("allow_no_indices", Boolean.toString(getter.get().allowNoIndices())); + if (getter.get().expandWildcardsOpen() && getter.get().expandWildcardsClosed()) { + expectedParams.put("expand_wildcards", "open,closed"); + } else if (getter.get().expandWildcardsOpen()) { + expectedParams.put("expand_wildcards", "open"); + } else if (getter.get().expandWildcardsClosed()) { + expectedParams.put("expand_wildcards", "closed"); + } else { + expectedParams.put("expand_wildcards", "none"); + } + } + + private static void setRandomTimeout(Consumer setter, TimeValue defaultTimeout, Map expectedParams) { if (randomBoolean()) { String timeout = randomTimeValue(); - request.timeout(timeout); + setter.accept(timeout); expectedParams.put("timeout", timeout); } else { - expectedParams.put("timeout", ReplicationRequest.DEFAULT_TIMEOUT.getStringRep()); + expectedParams.put("timeout", defaultTimeout.getStringRep()); + } + } + + private static void setRandomMasterTimeout(MasterNodeRequest request, Map expectedParams) { + if (randomBoolean()) { + String masterTimeout = randomTimeValue(); + request.masterNodeTimeout(masterTimeout); + expectedParams.put("master_timeout", masterTimeout); + } else { + expectedParams.put("master_timeout", MasterNodeRequest.DEFAULT_MASTER_NODE_TIMEOUT.getStringRep()); } } diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java new file mode 100644 index 00000000000..e866fb92aae --- /dev/null +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java @@ -0,0 +1,116 @@ +/* + * 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.documentation; + +import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; +import org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse; +import org.elasticsearch.action.support.IndicesOptions; +import org.elasticsearch.client.ESRestHighLevelClientTestCase; +import org.elasticsearch.client.Response; +import org.elasticsearch.client.RestHighLevelClient; +import org.elasticsearch.common.unit.TimeValue; +import org.elasticsearch.rest.RestStatus; + +import java.io.IOException; + +/** + * This class is used to generate the Java Indices API documentation. + * You need to wrap your code between two tags like: + * // tag::example[] + * // end::example[] + * + * Where example is your tag name. + * + * Then in the documentation, you can extract what is between tag and end tags with + * ["source","java",subs="attributes,callouts,macros"] + * -------------------------------------------------- + * include-tagged::{doc-tests}/CRUDDocumentationIT.java[example] + * -------------------------------------------------- + */ +public class IndicesClientDocumentationIT extends ESRestHighLevelClientTestCase { + + public void testDeleteIndex() throws IOException { + RestHighLevelClient client = highLevelClient(); + + { + Response createIndexResponse = client().performRequest("PUT", "/posts"); + assertEquals(200, createIndexResponse.getStatusLine().getStatusCode()); + } + + { + // tag::delete-index-request + DeleteIndexRequest request = new DeleteIndexRequest("posts"); // <1> + // end::delete-index-request + + // tag::delete-index-execute + DeleteIndexResponse deleteIndexResponse = client.indices().deleteIndex(request); + // end::delete-index-execute + assertTrue(deleteIndexResponse.isAcknowledged()); + + // tag::delete-index-response + boolean acknowledged = deleteIndexResponse.isAcknowledged(); // <1> + // end::delete-index-response + + // tag::delete-index-execute-async + client.indices().deleteIndexAsync(request, new ActionListener() { + @Override + public void onResponse(DeleteIndexResponse deleteIndexResponse) { + // <1> + } + + @Override + public void onFailure(Exception e) { + // <2> + } + }); + // end::delete-index-execute-async + } + + { + DeleteIndexRequest request = new DeleteIndexRequest("posts"); + // tag::delete-index-request-timeout + request.timeout(TimeValue.timeValueMinutes(2)); // <1> + request.timeout("2m"); // <2> + // end::delete-index-request-timeout + // tag::delete-index-request-masterTimeout + request.masterNodeTimeout(TimeValue.timeValueMinutes(1)); // <1> + request.timeout("1m"); // <2> + // end::delete-index-request-masterTimeout + // tag::delete-index-request-indicesOptions + request.indicesOptions(IndicesOptions.lenientExpandOpen()); // <1> + // end::delete-index-request-indicesOptions + } + + { + // tag::delete-index-notfound + try { + DeleteIndexRequest request = new DeleteIndexRequest("does_not_exist"); + DeleteIndexResponse deleteIndexResponse = client.indices().deleteIndex(request); + } catch (ElasticsearchException exception) { + if (exception.status() == RestStatus.NOT_FOUND) { + // <1> + } + } + // end::delete-index-notfound + } + } +} diff --git a/core/src/main/java/org/elasticsearch/action/admin/cluster/repositories/delete/DeleteRepositoryResponse.java b/core/src/main/java/org/elasticsearch/action/admin/cluster/repositories/delete/DeleteRepositoryResponse.java old mode 100644 new mode 100755 diff --git a/core/src/main/java/org/elasticsearch/action/admin/indices/create/CreateIndexResponse.java b/core/src/main/java/org/elasticsearch/action/admin/indices/create/CreateIndexResponse.java index 7d948e7137e..b770c11c6ab 100644 --- a/core/src/main/java/org/elasticsearch/action/admin/indices/create/CreateIndexResponse.java +++ b/core/src/main/java/org/elasticsearch/action/admin/indices/create/CreateIndexResponse.java @@ -21,16 +21,39 @@ package org.elasticsearch.action.admin.indices.create; import org.elasticsearch.Version; import org.elasticsearch.action.support.master.AcknowledgedResponse; +import org.elasticsearch.common.ParseField; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.xcontent.ConstructingObjectParser; +import org.elasticsearch.common.xcontent.ObjectParser; +import org.elasticsearch.common.xcontent.ToXContentObject; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentParser; import java.io.IOException; +import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg; + /** * A response for a create index action. */ -public class CreateIndexResponse extends AcknowledgedResponse { +public class CreateIndexResponse extends AcknowledgedResponse implements ToXContentObject { + + private static final String SHARDS_ACKNOWLEDGED = "shards_acknowledged"; + private static final String INDEX = "index"; + + private static final ParseField SHARDS_ACKNOWLEDGED_PARSER = new ParseField(SHARDS_ACKNOWLEDGED); + private static final ParseField INDEX_PARSER = new ParseField(INDEX); + + private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>("create_index", + true, args -> new CreateIndexResponse((boolean) args[0], (boolean) args[1], (String) args[2])); + + static { + declareAcknowledgedField(PARSER); + PARSER.declareField(constructorArg(), (parser, context) -> parser.booleanValue(), SHARDS_ACKNOWLEDGED_PARSER, + ObjectParser.ValueType.BOOLEAN); + PARSER.declareField(constructorArg(), (parser, context) -> parser.text(), INDEX_PARSER, ObjectParser.ValueType.STRING); + } private boolean shardsAcked; private String index; @@ -79,7 +102,20 @@ public class CreateIndexResponse extends AcknowledgedResponse { } public void addCustomFields(XContentBuilder builder) throws IOException { - builder.field("shards_acknowledged", isShardsAcked()); - builder.field("index", index()); + builder.field(SHARDS_ACKNOWLEDGED, isShardsAcked()); + builder.field(INDEX, index()); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + addAcknowledgedField(builder); + addCustomFields(builder); + builder.endObject(); + return builder; + } + + public static CreateIndexResponse fromXContent(XContentParser parser) throws IOException { + return PARSER.apply(parser, null); } } diff --git a/core/src/main/java/org/elasticsearch/action/admin/indices/delete/DeleteIndexResponse.java b/core/src/main/java/org/elasticsearch/action/admin/indices/delete/DeleteIndexResponse.java old mode 100644 new mode 100755 index 509686d3649..8217668e217 --- a/core/src/main/java/org/elasticsearch/action/admin/indices/delete/DeleteIndexResponse.java +++ b/core/src/main/java/org/elasticsearch/action/admin/indices/delete/DeleteIndexResponse.java @@ -22,13 +22,24 @@ package org.elasticsearch.action.admin.indices.delete; import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.xcontent.ConstructingObjectParser; +import org.elasticsearch.common.xcontent.ToXContentObject; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentParser; import java.io.IOException; /** * A response for a delete index action. */ -public class DeleteIndexResponse extends AcknowledgedResponse { +public class DeleteIndexResponse extends AcknowledgedResponse implements ToXContentObject { + + private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>("delete_index", + true, args -> new DeleteIndexResponse((boolean) args[0])); + + static { + declareAcknowledgedField(PARSER); + } DeleteIndexResponse() { } @@ -48,4 +59,16 @@ public class DeleteIndexResponse extends AcknowledgedResponse { super.writeTo(out); writeAcknowledged(out); } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + addAcknowledgedField(builder); + builder.endObject(); + return builder; + } + + public static DeleteIndexResponse fromXContent(XContentParser parser) throws IOException { + return PARSER.apply(parser, null); + } } diff --git a/core/src/main/java/org/elasticsearch/action/support/master/AcknowledgedResponse.java b/core/src/main/java/org/elasticsearch/action/support/master/AcknowledgedResponse.java old mode 100644 new mode 100755 index cdac96a7a79..e4467964722 --- a/core/src/main/java/org/elasticsearch/action/support/master/AcknowledgedResponse.java +++ b/core/src/main/java/org/elasticsearch/action/support/master/AcknowledgedResponse.java @@ -19,17 +19,32 @@ package org.elasticsearch.action.support.master; import org.elasticsearch.action.ActionResponse; +import org.elasticsearch.common.ParseField; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.xcontent.ConstructingObjectParser; +import org.elasticsearch.common.xcontent.ObjectParser; +import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.XContentBuilder; import java.io.IOException; +import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg; + /** * Abstract class that allows to mark action responses that support acknowledgements. * Facilitates consistency across different api. */ public abstract class AcknowledgedResponse extends ActionResponse { + private static final String ACKNOWLEDGED = "acknowledged"; + private static final ParseField ACKNOWLEDGED_PARSER = new ParseField(ACKNOWLEDGED); + + protected static void declareAcknowledgedField(ConstructingObjectParser PARSER) { + PARSER.declareField(constructorArg(), (parser, context) -> parser.booleanValue(), ACKNOWLEDGED_PARSER, + ObjectParser.ValueType.BOOLEAN); + } + private boolean acknowledged; protected AcknowledgedResponse() { @@ -61,4 +76,8 @@ public abstract class AcknowledgedResponse extends ActionResponse { protected void writeAcknowledged(StreamOutput out) throws IOException { out.writeBoolean(acknowledged); } + + protected void addAcknowledgedField(XContentBuilder builder) throws IOException { + builder.field(ACKNOWLEDGED, isAcknowledged()); + } } diff --git a/core/src/main/java/org/elasticsearch/index/get/GetResult.java b/core/src/main/java/org/elasticsearch/index/get/GetResult.java index a47bb8be89e..75e283b4191 100644 --- a/core/src/main/java/org/elasticsearch/index/get/GetResult.java +++ b/core/src/main/java/org/elasticsearch/index/get/GetResult.java @@ -82,7 +82,7 @@ public class GetResult implements Streamable, Iterable, ToXConten } /** - * Does the document exists. + * Does the document exist. */ public boolean isExists() { return exists; diff --git a/core/src/main/java/org/elasticsearch/rest/action/AcknowledgedRestListener.java b/core/src/main/java/org/elasticsearch/rest/action/AcknowledgedRestListener.java index e12329f93a3..9f08c43fa0f 100644 --- a/core/src/main/java/org/elasticsearch/rest/action/AcknowledgedRestListener.java +++ b/core/src/main/java/org/elasticsearch/rest/action/AcknowledgedRestListener.java @@ -36,6 +36,7 @@ public class AcknowledgedRestListener extends Re @Override public RestResponse buildResponse(T response, XContentBuilder builder) throws Exception { + // TODO - Once AcknowledgedResponse implements ToXContent, this method should be updated to call response.toXContent. builder.startObject() .field(Fields.ACKNOWLEDGED, response.isAcknowledged()); addCustomFields(builder, response); diff --git a/core/src/test/java/org/elasticsearch/action/admin/indices/create/CreateIndexResponseTests.java b/core/src/test/java/org/elasticsearch/action/admin/indices/create/CreateIndexResponseTests.java index 588659335e4..b0fdae9ca62 100644 --- a/core/src/test/java/org/elasticsearch/action/admin/indices/create/CreateIndexResponseTests.java +++ b/core/src/test/java/org/elasticsearch/action/admin/indices/create/CreateIndexResponseTests.java @@ -20,12 +20,19 @@ package org.elasticsearch.action.admin.indices.create; import org.elasticsearch.Version; +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.test.ESTestCase; import java.io.IOException; +import static org.elasticsearch.test.XContentTestUtils.insertRandomFields; + public class CreateIndexResponseTests extends ESTestCase { public void testSerialization() throws IOException { @@ -62,4 +69,59 @@ public class CreateIndexResponseTests extends ESTestCase { } } } + + public void testToXContent() { + CreateIndexResponse response = new CreateIndexResponse(true, false, "index_name"); + String output = Strings.toString(response); + assertEquals("{\"acknowledged\":true,\"shards_acknowledged\":false,\"index\":\"index_name\"}", output); + } + + public void testToAndFromXContent() throws IOException { + doFromXContentTestWithRandomFields(false); + } + + /** + * This test adds random fields and objects to the xContent rendered out to + * ensure we can parse it back to be forward compatible with additions to + * the xContent + */ + public void testFromXContentWithRandomFields() throws IOException { + doFromXContentTestWithRandomFields(true); + } + + private void doFromXContentTestWithRandomFields(boolean addRandomFields) throws IOException { + + final CreateIndexResponse createIndexResponse = createTestItem(); + + boolean humanReadable = randomBoolean(); + final XContentType xContentType = randomFrom(XContentType.values()); + BytesReference originalBytes = toShuffledXContent(createIndexResponse, xContentType, ToXContent.EMPTY_PARAMS, humanReadable); + + BytesReference mutated; + if (addRandomFields) { + mutated = insertRandomFields(xContentType, originalBytes, null, random()); + } else { + mutated = originalBytes; + } + CreateIndexResponse parsedCreateIndexResponse; + try (XContentParser parser = createParser(xContentType.xContent(), mutated)) { + parsedCreateIndexResponse = CreateIndexResponse.fromXContent(parser); + assertNull(parser.nextToken()); + } + + assertEquals(createIndexResponse.index(), parsedCreateIndexResponse.index()); + assertEquals(createIndexResponse.isShardsAcked(), parsedCreateIndexResponse.isShardsAcked()); + assertEquals(createIndexResponse.isAcknowledged(), parsedCreateIndexResponse.isAcknowledged()); + } + + /** + * Returns a random {@link CreateIndexResponse}. + */ + private static CreateIndexResponse createTestItem() throws IOException { + boolean acknowledged = randomBoolean(); + boolean shardsAcked = acknowledged && randomBoolean(); + String index = randomAlphaOfLength(5); + + return new CreateIndexResponse(acknowledged, shardsAcked, index); + } } diff --git a/core/src/test/java/org/elasticsearch/action/admin/indices/delete/DeleteIndexResponseTests.java b/core/src/test/java/org/elasticsearch/action/admin/indices/delete/DeleteIndexResponseTests.java new file mode 100755 index 00000000000..4e036319ad9 --- /dev/null +++ b/core/src/test/java/org/elasticsearch/action/admin/indices/delete/DeleteIndexResponseTests.java @@ -0,0 +1,85 @@ +/* + * 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.action.admin.indices.delete; + +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.bytes.BytesReference; +import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.test.ESTestCase; + +import java.io.IOException; + +import static org.elasticsearch.test.XContentTestUtils.insertRandomFields; + +public class DeleteIndexResponseTests extends ESTestCase { + + public void testToXContent() { + DeleteIndexResponse response = new DeleteIndexResponse(true); + String output = Strings.toString(response); + assertEquals("{\"acknowledged\":true}", output); + } + + public void testToAndFromXContent() throws IOException { + doFromXContentTestWithRandomFields(false); + } + + /** + * This test adds random fields and objects to the xContent rendered out to + * ensure we can parse it back to be forward compatible with additions to + * the xContent + */ + public void testFromXContentWithRandomFields() throws IOException { + doFromXContentTestWithRandomFields(true); + } + + private void doFromXContentTestWithRandomFields(boolean addRandomFields) throws IOException { + + final DeleteIndexResponse deleteIndexResponse = createTestItem(); + + boolean humanReadable = randomBoolean(); + final XContentType xContentType = randomFrom(XContentType.values()); + BytesReference originalBytes = toShuffledXContent(deleteIndexResponse, xContentType, ToXContent.EMPTY_PARAMS, humanReadable); + + BytesReference mutated; + if (addRandomFields) { + mutated = insertRandomFields(xContentType, originalBytes, null, random()); + } else { + mutated = originalBytes; + } + DeleteIndexResponse parsedDeleteIndexResponse; + try (XContentParser parser = createParser(xContentType.xContent(), mutated)) { + parsedDeleteIndexResponse = DeleteIndexResponse.fromXContent(parser); + assertNull(parser.nextToken()); + } + + assertEquals(deleteIndexResponse.isAcknowledged(), parsedDeleteIndexResponse.isAcknowledged()); + } + + /** + * Returns a random {@link DeleteIndexResponse}. + */ + private static DeleteIndexResponse createTestItem() throws IOException { + boolean acknowledged = randomBoolean(); + + return new DeleteIndexResponse(acknowledged); + } +} diff --git a/docs/java-rest/high-level/apis/deleteindex.asciidoc b/docs/java-rest/high-level/apis/deleteindex.asciidoc new file mode 100644 index 00000000000..3c0627de49a --- /dev/null +++ b/docs/java-rest/high-level/apis/deleteindex.asciidoc @@ -0,0 +1,76 @@ +[[java-rest-high-delete-index]] +=== Delete Index API + +[[java-rest-high-delete-index-request]] +==== Delete Index Request + +A `DeleteIndexRequest` requires an `index` argument: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[delete-index-request] +-------------------------------------------------- +<1> Index + +==== Optional arguments +The following arguments can optionally be provided: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[delete-index-request-timeout] +-------------------------------------------------- +<1> Timeout to wait for the all the nodes to acknowledge the index deletion as a `TimeValue` +<2> Timeout to wait for the all the nodes to acknowledge the index deletion as a `String` + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[delete-index-request-masterTimeout] +-------------------------------------------------- +<1> Timeout to connect to the master node as a `TimeValue` +<2> Timeout to connect to the master node as a `String` + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[delete-index-request-indicesOptions] +-------------------------------------------------- +<1> Setting `IndicesOptions` controls how unavailable indices are resolved and +how wildcard expressions are expanded + +[[java-rest-high-delete-index-sync]] +==== Synchronous Execution + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[delete-index-execute] +-------------------------------------------------- + +[[java-rest-high-delete-index-async]] +==== Asynchronous Execution + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[delete-index-execute-async] +-------------------------------------------------- +<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 + +[[java-rest-high-delete-index-response]] +==== Delete Index Response + +The returned `DeleteIndexResponse` allows to retrieve information about the executed + operation as follows: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[delete-index-response] +-------------------------------------------------- +<1> Indicates whether all of the nodes have acknowledged the request or not + +If the index was not found, an `ElasticsearchException` will be thrown: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[delete-index-notfound] +-------------------------------------------------- +<1> Do something if the index to be deleted was not found diff --git a/docs/java-rest/high-level/apis/index.asciidoc b/docs/java-rest/high-level/apis/index.asciidoc index b4dcf7e9d80..993951b5ae7 100644 --- a/docs/java-rest/high-level/apis/index.asciidoc +++ b/docs/java-rest/high-level/apis/index.asciidoc @@ -1,3 +1,4 @@ +include::deleteindex.asciidoc[] include::_index.asciidoc[] include::get.asciidoc[] include::delete.asciidoc[] diff --git a/docs/java-rest/high-level/supported-apis.asciidoc b/docs/java-rest/high-level/supported-apis.asciidoc index 51411ea9fca..9e902e17157 100644 --- a/docs/java-rest/high-level/supported-apis.asciidoc +++ b/docs/java-rest/high-level/supported-apis.asciidoc @@ -3,6 +3,9 @@ The Java High Level REST Client supports the following APIs: +Indices APIs:: +* <> + Single document APIs:: * <> * <>