Browse Source

Add Delete Index API support to high-level REST client (#27019)

Relates to #25847
Catalin Ursachi 8 years ago
parent
commit
8bf33241ed

+ 63 - 0
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 <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices.html">Indices API on elastic.co</a>
+ */
+public final class IndicesClient {
+    private final RestHighLevelClient restHighLevelClient;
+
+    public IndicesClient(RestHighLevelClient restHighLevelClient) {
+        this.restHighLevelClient = restHighLevelClient;
+    }
+
+    /**
+     * Deletes an index using the Delete Index API
+     * <p>
+     * See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-delete-index.html">
+     * Delete Index API on elastic.co</a>
+     */
+    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
+     * <p>
+     * See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-delete-index.html">
+     * Delete Index API on elastic.co</a>
+     */
+    public void deleteIndexAsync(DeleteIndexRequest deleteIndexRequest, ActionListener<DeleteIndexResponse> listener, Header... headers) {
+        restHighLevelClient.performRequestAsyncAndParseEntity(deleteIndexRequest, Request::deleteIndex, DeleteIndexResponse::fromXContent,
+            listener, Collections.emptySet(), headers);
+    }
+}

+ 16 - 0
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);
         }

+ 19 - 8
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<RestClient, IOException> 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 <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices.html">Indices API on elastic.co</a>
+     */
+    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 <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-delete.html">Delete API on elastic.co</a>
      */
@@ -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 <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-delete.html">Delete API on elastic.co</a>
      */
@@ -347,7 +358,7 @@ public class RestHighLevelClient implements Closeable {
     }
 
     /**
-     * Executes a search using the Search api
+     * Executes a search using the Search API
      *
      * See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html">Search API on elastic.co</a>
      */
@@ -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 <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html">Search API on elastic.co</a>
      */
@@ -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 <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-scroll.html">Search Scroll
      * API on elastic.co</a>
@@ -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 <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-scroll.html">Search Scroll
      * API on elastic.co</a>
@@ -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 <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-scroll.html#_clear_scroll_api">
      * Clear Scroll API on elastic.co</a>
@@ -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 <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-scroll.html#_clear_scroll_api">
      * Clear Scroll API on elastic.co</a>

+ 68 - 0
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;
+    }
+}

+ 65 - 19
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<String, String> 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<String, String> 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<String, String> expectedParams) {
+    private static void setRandomIndicesOptions(Consumer<IndicesOptions> setter, Supplier<IndicesOptions> getter,
+                                                Map<String, String> 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<String> setter, TimeValue defaultTimeout, Map<String, String> 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<String, String> 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());
         }
     }
 

+ 116 - 0
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<DeleteIndexResponse>() {
+                @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
+        }
+    }
+}

+ 39 - 3
core/src/main/java/org/elasticsearch/action/admin/cluster/repositories/delete/DeleteRepositoryResponse.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<CreateIndexResponse, Void> 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);
     }
 }

+ 24 - 1
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<DeleteIndexResponse, Void> 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);
+    }
 }

+ 19 - 0
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 <T extends AcknowledgedResponse> void declareAcknowledgedField(ConstructingObjectParser<T, Void> 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());
+    }
 }

+ 1 - 1
core/src/main/java/org/elasticsearch/index/get/GetResult.java

@@ -82,7 +82,7 @@ public class GetResult implements Streamable, Iterable<DocumentField>, ToXConten
     }
 
     /**
-     * Does the document exists.
+     * Does the document exist.
      */
     public boolean isExists() {
         return exists;

+ 1 - 0
core/src/main/java/org/elasticsearch/rest/action/AcknowledgedRestListener.java

@@ -36,6 +36,7 @@ public class AcknowledgedRestListener<T extends AcknowledgedResponse> 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);

+ 62 - 0
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);
+    }
 }

+ 85 - 0
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);
+    }
+}

+ 76 - 0
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

+ 1 - 0
docs/java-rest/high-level/apis/index.asciidoc

@@ -1,3 +1,4 @@
+include::deleteindex.asciidoc[]
 include::_index.asciidoc[]
 include::get.asciidoc[]
 include::delete.asciidoc[]

+ 3 - 0
docs/java-rest/high-level/supported-apis.asciidoc

@@ -3,6 +3,9 @@
 
 The Java High Level REST Client supports the following APIs:
 
+Indices APIs::
+* <<java-rest-high-delete-index>>
+
 Single document APIs::
 * <<java-rest-high-document-index>>
 * <<java-rest-high-document-get>>