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 index d17f0bf94e3..29a754035aa 100644 --- 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 @@ -23,6 +23,8 @@ import org.apache.http.Header; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.admin.indices.close.CloseIndexRequest; import org.elasticsearch.action.admin.indices.close.CloseIndexResponse; +import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; +import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; @@ -111,7 +113,32 @@ public final class IndicesClient { public void putMappingAsync(PutMappingRequest putMappingRequest, ActionListener listener, Header... headers) { restHighLevelClient.performRequestAsyncAndParseEntity(putMappingRequest, Request::putMapping, PutMappingResponse::fromXContent, - listener, Collections.emptySet(), headers); + listener, Collections.emptySet(), headers); + } + + /** + * Updates aliases using the Index Aliases API + *

+ * See + * Index Aliases API on elastic.co + */ + public IndicesAliasesResponse updateAliases(IndicesAliasesRequest indicesAliasesRequest, Header... headers) throws IOException { + return restHighLevelClient.performRequestAndParseEntity(indicesAliasesRequest, Request::updateAliases, + IndicesAliasesResponse::fromXContent, Collections.emptySet(), headers); + } + + /** + * Asynchronously updates aliases using the Index Aliases API + *

+ * See + * Index Aliases API on elastic.co + */ + public void updateAliasesAsync(IndicesAliasesRequest indicesAliasesRequestRequest, ActionListener listener, + Header... headers) { + restHighLevelClient.performRequestAsyncAndParseEntity(indicesAliasesRequestRequest, Request::updateAliases, + IndicesAliasesResponse::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 index 229e45498aa..ae69547b609 100755 --- 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 @@ -30,6 +30,7 @@ import org.apache.http.entity.ContentType; import org.apache.lucene.util.BytesRef; import org.elasticsearch.action.DocWriteRequest; import org.elasticsearch.action.admin.indices.close.CloseIndexRequest; +import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; @@ -178,6 +179,15 @@ public final class Request { HttpEntity entity = createEntity(createIndexRequest, REQUEST_BODY_CONTENT_TYPE); return new Request(HttpPut.METHOD_NAME, endpoint, parameters.getParams(), entity); } + + static Request updateAliases(IndicesAliasesRequest indicesAliasesRequest) throws IOException { + Params parameters = Params.builder(); + parameters.withTimeout(indicesAliasesRequest.timeout()); + parameters.withMasterTimeout(indicesAliasesRequest.masterNodeTimeout()); + + HttpEntity entity = createEntity(indicesAliasesRequest, REQUEST_BODY_CONTENT_TYPE); + return new Request(HttpPost.METHOD_NAME, "/_aliases", parameters.getParams(), entity); + } static Request putMapping(PutMappingRequest putMappingRequest) throws IOException { // The concreteIndex is an internal concept, not applicable to requests made over the REST API. 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 index 2f81479f93a..58569b687c7 100755 --- 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 @@ -20,9 +20,13 @@ package org.elasticsearch.client; import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.ElasticsearchStatusException; import org.elasticsearch.action.admin.indices.alias.Alias; import org.elasticsearch.action.admin.indices.close.CloseIndexRequest; import org.elasticsearch.action.admin.indices.close.CloseIndexResponse; +import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; +import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions; +import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; @@ -32,6 +36,7 @@ import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse; import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; import org.elasticsearch.action.admin.indices.open.OpenIndexResponse; import org.elasticsearch.action.support.IndicesOptions; +import org.elasticsearch.common.Strings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentHelper; @@ -43,7 +48,9 @@ import java.io.IOException; import java.util.Map; import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_REPLICAS; +import static org.hamcrest.CoreMatchers.hasItem; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.not; public class IndicesClientIT extends ESRestHighLevelClientTestCase { @@ -165,6 +172,97 @@ public class IndicesClientIT extends ESRestHighLevelClientTestCase { } } + @SuppressWarnings("unchecked") + public void testUpdateAliases() throws IOException { + String index = "index"; + String alias = "alias"; + + createIndex(index); + assertThat(aliasExists(index, alias), equalTo(false)); + assertThat(aliasExists(alias), equalTo(false)); + + IndicesAliasesRequest aliasesAddRequest = new IndicesAliasesRequest(); + AliasActions addAction = new AliasActions(AliasActions.Type.ADD).index(index).aliases(alias); + addAction.routing("routing").searchRouting("search_routing").filter("{\"term\":{\"year\":2016}}"); + aliasesAddRequest.addAliasAction(addAction); + IndicesAliasesResponse aliasesAddResponse = execute(aliasesAddRequest, highLevelClient().indices()::updateAliases, + highLevelClient().indices()::updateAliasesAsync); + assertTrue(aliasesAddResponse.isAcknowledged()); + assertThat(aliasExists(alias), equalTo(true)); + assertThat(aliasExists(index, alias), equalTo(true)); + Map getAlias = getAlias(index, alias); + assertThat(getAlias.get("index_routing"), equalTo("routing")); + assertThat(getAlias.get("search_routing"), equalTo("search_routing")); + Map filter = (Map) getAlias.get("filter"); + Map term = (Map) filter.get("term"); + assertEquals(2016, term.get("year")); + + String alias2 = "alias2"; + IndicesAliasesRequest aliasesAddRemoveRequest = new IndicesAliasesRequest(); + addAction = new AliasActions(AliasActions.Type.ADD).indices(index).alias(alias2); + aliasesAddRemoveRequest.addAliasAction(addAction); + AliasActions removeAction = new AliasActions(AliasActions.Type.REMOVE).index(index).alias(alias); + aliasesAddRemoveRequest.addAliasAction(removeAction); + IndicesAliasesResponse aliasesAddRemoveResponse = execute(aliasesAddRemoveRequest, highLevelClient().indices()::updateAliases, + highLevelClient().indices()::updateAliasesAsync); + assertTrue(aliasesAddRemoveResponse.isAcknowledged()); + assertThat(aliasExists(alias), equalTo(false)); + assertThat(aliasExists(alias2), equalTo(true)); + assertThat(aliasExists(index, alias), equalTo(false)); + assertThat(aliasExists(index, alias2), equalTo(true)); + + IndicesAliasesRequest aliasesRemoveIndexRequest = new IndicesAliasesRequest(); + AliasActions removeIndexAction = new AliasActions(AliasActions.Type.REMOVE_INDEX).index(index); + aliasesRemoveIndexRequest.addAliasAction(removeIndexAction); + IndicesAliasesResponse aliasesRemoveIndexResponse = execute(aliasesRemoveIndexRequest, highLevelClient().indices()::updateAliases, + highLevelClient().indices()::updateAliasesAsync); + assertTrue(aliasesRemoveIndexResponse.isAcknowledged()); + assertThat(aliasExists(alias), equalTo(false)); + assertThat(aliasExists(alias2), equalTo(false)); + assertThat(aliasExists(index, alias), equalTo(false)); + assertThat(aliasExists(index, alias2), equalTo(false)); + assertThat(indexExists(index), equalTo(false)); + } + + public void testAliasesNonExistentIndex() throws IOException { + String index = "index"; + String alias = "alias"; + String nonExistentIndex = "non_existent_index"; + + IndicesAliasesRequest nonExistentIndexRequest = new IndicesAliasesRequest(); + nonExistentIndexRequest.addAliasAction(new AliasActions(AliasActions.Type.ADD).index(nonExistentIndex).alias(alias)); + ElasticsearchException exception = expectThrows(ElasticsearchException.class, () -> execute(nonExistentIndexRequest, + highLevelClient().indices()::updateAliases, highLevelClient().indices()::updateAliasesAsync)); + assertThat(exception.status(), equalTo(RestStatus.NOT_FOUND)); + assertThat(exception.getMessage(), equalTo("Elasticsearch exception [type=index_not_found_exception, reason=no such index]")); + assertThat(exception.getMetadata("es.index"), hasItem(nonExistentIndex)); + + createIndex(index); + IndicesAliasesRequest mixedRequest = new IndicesAliasesRequest(); + mixedRequest.addAliasAction(new AliasActions(AliasActions.Type.ADD).indices(index).aliases(alias)); + mixedRequest.addAliasAction(new AliasActions(AliasActions.Type.REMOVE).indices(nonExistentIndex).alias(alias)); + exception = expectThrows(ElasticsearchStatusException.class, + () -> execute(mixedRequest, highLevelClient().indices()::updateAliases, highLevelClient().indices()::updateAliasesAsync)); + assertThat(exception.status(), equalTo(RestStatus.NOT_FOUND)); + assertThat(exception.getMessage(), equalTo("Elasticsearch exception [type=index_not_found_exception, reason=no such index]")); + assertThat(exception.getMetadata("es.index"), hasItem(nonExistentIndex)); + assertThat(exception.getMetadata("es.index"), not(hasItem(index))); + assertThat(aliasExists(index, alias), equalTo(false)); + assertThat(aliasExists(alias), equalTo(false)); + + IndicesAliasesRequest removeIndexRequest = new IndicesAliasesRequest(); + removeIndexRequest.addAliasAction(new AliasActions(AliasActions.Type.ADD).index(nonExistentIndex).alias(alias)); + removeIndexRequest.addAliasAction(new AliasActions(AliasActions.Type.REMOVE_INDEX).indices(nonExistentIndex)); + exception = expectThrows(ElasticsearchException.class, () -> execute(removeIndexRequest, highLevelClient().indices()::updateAliases, + highLevelClient().indices()::updateAliasesAsync)); + assertThat(exception.status(), equalTo(RestStatus.NOT_FOUND)); + assertThat(exception.getMessage(), equalTo("Elasticsearch exception [type=index_not_found_exception, reason=no such index]")); + assertThat(exception.getMetadata("es.index"), hasItem(nonExistentIndex)); + assertThat(exception.getMetadata("es.index"), not(hasItem(index))); + assertThat(aliasExists(index, alias), equalTo(false)); + assertThat(aliasExists(alias), equalTo(false)); + } + public void testOpenExistingIndex() throws IOException { String index = "index"; createIndex(index); @@ -245,6 +343,16 @@ public class IndicesClientIT extends ESRestHighLevelClientTestCase { assertThat(response.getStatusLine().getStatusCode(), equalTo(RestStatus.OK.getStatus())); } + private static boolean aliasExists(String alias) throws IOException { + Response response = client().performRequest("HEAD", "/_alias/" + alias); + return RestStatus.OK.getStatus() == response.getStatusLine().getStatusCode(); + } + + private static boolean aliasExists(String index, String alias) throws IOException { + Response response = client().performRequest("HEAD", "/" + index + "/_alias/" + alias); + return RestStatus.OK.getStatus() == response.getStatusLine().getStatusCode(); + } + @SuppressWarnings("unchecked") private Map getIndexMetadata(String index) throws IOException { Response response = client().performRequest("GET", index); @@ -258,4 +366,26 @@ public class IndicesClientIT extends ESRestHighLevelClientTestCase { return indexMetaData; } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private static Map getAlias(final String index, final String alias) throws IOException { + String endpoint = "/_alias"; + if (false == Strings.isEmpty(index)) { + endpoint = index + endpoint; + } + if (false == Strings.isEmpty(alias)) { + endpoint = endpoint + "/" + alias; + } + Map performGet = performGet(endpoint); + return (Map) ((Map) ((Map) performGet.get(index)).get("aliases")).get(alias); + } + + private static Map performGet(final String endpoint) throws IOException { + Response response = client().performRequest("GET", endpoint); + XContentType entityContentType = XContentType.fromMediaTypeOrFormat(response.getEntity().getContentType().getValue()); + Map responseEntity = XContentHelper.convertToMap(entityContentType.xContent(), response.getEntity().getContent(), + false); + assertNotNull(responseEntity); + return responseEntity; + } } 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 index 0ddaf1de1ca..4b8cade5567 100755 --- 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 @@ -26,6 +26,8 @@ import org.apache.http.entity.StringEntity; import org.apache.http.util.EntityUtils; import org.elasticsearch.action.DocWriteRequest; import org.elasticsearch.action.admin.indices.close.CloseIndexRequest; +import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; +import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; @@ -93,6 +95,7 @@ import java.util.function.Supplier; import static java.util.Collections.singletonMap; import static org.elasticsearch.client.Request.REQUEST_BODY_CONTENT_TYPE; import static org.elasticsearch.client.Request.enforceSameContentType; +import static org.elasticsearch.index.alias.RandomAliasActionsGenerator.randomAliasAction; import static org.elasticsearch.search.RandomSearchRequestGenerator.randomSearchRequest; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertToXContentEquivalent; import static org.hamcrest.CoreMatchers.equalTo; @@ -318,6 +321,21 @@ public class RequestTests extends ESTestCase { assertToXContentBody(createIndexRequest, request.getEntity()); } + public void testUpdateAliases() throws IOException { + IndicesAliasesRequest indicesAliasesRequest = new IndicesAliasesRequest(); + AliasActions aliasAction = randomAliasAction(); + indicesAliasesRequest.addAliasAction(aliasAction); + + Map expectedParams = new HashMap<>(); + setRandomTimeout(indicesAliasesRequest::timeout, AcknowledgedRequest.DEFAULT_ACK_TIMEOUT, expectedParams); + setRandomMasterTimeout(indicesAliasesRequest, expectedParams); + + Request request = Request.updateAliases(indicesAliasesRequest); + assertEquals("/_aliases", request.getEndpoint()); + assertEquals(expectedParams, request.getParameters()); + assertToXContentBody(indicesAliasesRequest, request.getEntity()); + } + public void testPutMapping() throws IOException { PutMappingRequest putMappingRequest = new PutMappingRequest(); 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 index 23029c7c6b0..710c3fe1d7c 100644 --- 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 @@ -24,6 +24,9 @@ import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.admin.indices.alias.Alias; import org.elasticsearch.action.admin.indices.close.CloseIndexRequest; import org.elasticsearch.action.admin.indices.close.CloseIndexResponse; +import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; +import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions; +import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; @@ -444,4 +447,68 @@ public class IndicesClientDocumentationIT extends ESRestHighLevelClientTestCase // end::close-index-notfound } } + + public void testIndicesAliases() throws IOException { + RestHighLevelClient client = highLevelClient(); + + { + CreateIndexResponse createIndexResponse = client.indices().create(new CreateIndexRequest("index1")); + assertTrue(createIndexResponse.isAcknowledged()); + createIndexResponse = client.indices().create(new CreateIndexRequest("index2")); + assertTrue(createIndexResponse.isAcknowledged()); + createIndexResponse = client.indices().create(new CreateIndexRequest("index3")); + assertTrue(createIndexResponse.isAcknowledged()); + createIndexResponse = client.indices().create(new CreateIndexRequest("index4")); + assertTrue(createIndexResponse.isAcknowledged()); + } + + { + // tag::update-aliases-request + IndicesAliasesRequest request = new IndicesAliasesRequest(); // <1> + AliasActions aliasAction = new AliasActions(AliasActions.Type.ADD).index("index1").alias("alias1"); // <2> + request.addAliasAction(aliasAction); // <3> + // end::update-aliases-request + + // tag::update-aliases-request2 + AliasActions addIndexAction = new AliasActions(AliasActions.Type.ADD).index("index1").alias("alias1") + .filter("{\"term\":{\"year\":2016}}"); // <1> + AliasActions addIndicesAction = new AliasActions(AliasActions.Type.ADD).indices("index1", "index2").alias("alias2") + .routing("1"); // <2> + AliasActions removeAction = new AliasActions(AliasActions.Type.REMOVE).index("index3").alias("alias3"); // <3> + AliasActions removeIndexAction = new AliasActions(AliasActions.Type.REMOVE_INDEX).index("index4"); // <4> + // end::update-aliases-request2 + + // tag::update-aliases-request-timeout + request.timeout(TimeValue.timeValueMinutes(2)); // <1> + request.timeout("2m"); // <2> + // end::update-aliases-request-timeout + // tag::update-aliases-request-masterTimeout + request.masterNodeTimeout(TimeValue.timeValueMinutes(1)); // <1> + request.masterNodeTimeout("1m"); // <2> + // end::update-aliases-request-masterTimeout + + // tag::update-aliases-execute + IndicesAliasesResponse indicesAliasesResponse = client.indices().updateAliases(request); + // end::update-aliases-execute + + // tag::update-aliases-response + boolean acknowledged = indicesAliasesResponse.isAcknowledged(); // <1> + // end::update-aliases-response + assertTrue(acknowledged); + + // tag::update-aliases-execute-async + client.indices().updateAliasesAsync(request, new ActionListener() { + @Override + public void onResponse(IndicesAliasesResponse indciesAliasesResponse) { + // <1> + } + + @Override + public void onFailure(Exception e) { + // <2> + } + }); + // end::update-aliases-execute-async + } + } } diff --git a/core/src/test/java/org/elasticsearch/action/admin/indices/alias/IndicesAliasesRequestTests.java b/core/src/test/java/org/elasticsearch/action/admin/indices/alias/IndicesAliasesRequestTests.java new file mode 100644 index 00000000000..80e3c34818c --- /dev/null +++ b/core/src/test/java/org/elasticsearch/action/admin/indices/alias/IndicesAliasesRequestTests.java @@ -0,0 +1,70 @@ +/* + * 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.alias; + +import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions; +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.index.alias.RandomAliasActionsGenerator.randomAliasAction; +import static org.hamcrest.CoreMatchers.equalTo; + +public class IndicesAliasesRequestTests extends ESTestCase { + + public void testToAndFromXContent() throws IOException { + IndicesAliasesRequest indicesAliasesRequest = createTestInstance(); + XContentType xContentType = randomFrom(XContentType.values()); + + BytesReference shuffled = toShuffledXContent(indicesAliasesRequest, xContentType, ToXContent.EMPTY_PARAMS, true, "filter"); + + IndicesAliasesRequest parsedIndicesAliasesRequest; + try (XContentParser parser = createParser(xContentType.xContent(), shuffled)) { + parsedIndicesAliasesRequest = IndicesAliasesRequest.fromXContent(parser); + assertNull(parser.nextToken()); + } + + for (int i = 0; i < parsedIndicesAliasesRequest.getAliasActions().size(); i++) { + AliasActions expectedAction = indicesAliasesRequest.getAliasActions().get(i); + AliasActions actualAction = parsedIndicesAliasesRequest.getAliasActions().get(i); + assertThat(actualAction, equalTo(expectedAction)); + } + } + + private IndicesAliasesRequest createTestInstance() { + int numItems = randomIntBetween(0, 32); + IndicesAliasesRequest request = new IndicesAliasesRequest(); + if (randomBoolean()) { + request.timeout(randomTimeValue()); + } + + if (randomBoolean()) { + request.masterNodeTimeout(randomTimeValue()); + } + for (int i = 0; i < numItems; i++) { + request.addAliasAction(randomAliasAction()); + } + return request; + } +} diff --git a/docs/java-rest/high-level/apis/index.asciidoc b/docs/java-rest/high-level/apis/index.asciidoc index f7367b6e8c2..b24d2266711 100644 --- a/docs/java-rest/high-level/apis/index.asciidoc +++ b/docs/java-rest/high-level/apis/index.asciidoc @@ -8,6 +8,8 @@ include::close_index.asciidoc[] include::putmapping.asciidoc[] +include::update_aliases.asciidoc[] + include::_index.asciidoc[] include::get.asciidoc[] diff --git a/docs/java-rest/high-level/apis/update_aliases.asciidoc b/docs/java-rest/high-level/apis/update_aliases.asciidoc new file mode 100644 index 00000000000..14f3fd2eb83 --- /dev/null +++ b/docs/java-rest/high-level/apis/update_aliases.asciidoc @@ -0,0 +1,79 @@ +[[java-rest-high-update-aliases]] +=== Update Aliases API + +[[java-rest-high-update-aliases-request]] +==== Indices Aliases Request + +The Update Aliases API allows aliasing an index with a name, with all APIs +automatically converting the alias name to the actual index name. + +An `IndicesAliasesRequest` must have at least one `AliasActions`: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[update-aliases-request] +-------------------------------------------------- +<1> Creates an `IndicesAliasesRequest` +<2> Creates an `AliasActions` that aliases index `test1` with `alias1` +<3> Adds the alias action to the request + +The following action types are supported: `add` - alias an index, `remove` - +removes the alias associated with the index, and `remove_index` - deletes the +index. + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[update-aliases-request2] +-------------------------------------------------- +<1> Creates an alias `alias1` with an optional filter on field `year` +<2> Creates an alias `alias2` associated with two indices and with an optional routing +<3> Removes the associated alias `alias3` +<4> `remove_index` is just like <> + +==== Optional arguments +The following arguments can optionally be provided: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[update-aliases-request-timeout] +-------------------------------------------------- +<1> Timeout to wait for the all the nodes to acknowledge the operation as a `TimeValue` +<2> Timeout to wait for the all the nodes to acknowledge the operation as a `String` + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[update-aliases-request-masterTimeout] +-------------------------------------------------- +<1> Timeout to connect to the master node as a `TimeValue` +<2> Timeout to connect to the master node as a `String` + +[[java-rest-high-update-aliases-sync]] +==== Synchronous Execution + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[update-aliases-execute] +-------------------------------------------------- + +[[java-rest-high-update-aliases-async]] +==== Asynchronous Execution + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[update-aliases-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-update-aliases-response]] +==== Indices Aliases Response + +The returned `IndicesAliasesResponse` allows to retrieve information about the +executed operation as follows: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[update-aliases-response] +-------------------------------------------------- +<1> Indicates whether all of the nodes have acknowledged the request \ No newline at end of file diff --git a/docs/java-rest/high-level/supported-apis.asciidoc b/docs/java-rest/high-level/supported-apis.asciidoc index aede4789f4d..4fe32401cac 100644 --- a/docs/java-rest/high-level/supported-apis.asciidoc +++ b/docs/java-rest/high-level/supported-apis.asciidoc @@ -9,6 +9,7 @@ Indices APIs:: * <> * <> * <> +* <> Single document APIs:: * <> diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/alias/IndicesAliasesRequest.java b/server/src/main/java/org/elasticsearch/action/admin/indices/alias/IndicesAliasesRequest.java index 2798359d4a8..61be2778845 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/indices/alias/IndicesAliasesRequest.java +++ b/server/src/main/java/org/elasticsearch/action/admin/indices/alias/IndicesAliasesRequest.java @@ -28,6 +28,7 @@ import org.elasticsearch.cluster.metadata.AliasAction; import org.elasticsearch.common.ParseField; import org.elasticsearch.common.ParsingException; import org.elasticsearch.common.Strings; +import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.Writeable; @@ -35,6 +36,7 @@ import org.elasticsearch.common.xcontent.ConstructingObjectParser; import org.elasticsearch.common.xcontent.ObjectParser; import org.elasticsearch.common.xcontent.ObjectParser.ValueType; import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.ToXContentObject; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentParser; @@ -56,7 +58,8 @@ import static org.elasticsearch.common.xcontent.ObjectParser.fromList; /** * A request to add/remove aliases for one or more indices. */ -public class IndicesAliasesRequest extends AcknowledgedRequest { +public class IndicesAliasesRequest extends AcknowledgedRequest implements ToXContentObject { + private List allAliasActions = new ArrayList<>(); // indices options that require every specified index to exist, expand wildcards only to open @@ -65,22 +68,37 @@ public class IndicesAliasesRequest extends AcknowledgedRequest { if (action.indices() != null) { throw new IllegalArgumentException("Only one of [index] and [indices] is supported"); } action.indices(indices); - }), new ParseField("indices")); + }), INDICES); parser.declareString((action, alias) -> { if (action.aliases() != null && action.aliases().length != 0) { throw new IllegalArgumentException("Only one of [alias] and [aliases] is supported"); } action.alias(alias); - }, new ParseField("alias")); + }, ALIAS); parser.declareStringArray(fromList(String.class, (action, aliases) -> { if (action.aliases() != null && action.aliases().length != 0) { throw new IllegalArgumentException("Only one of [alias] and [aliases] is supported"); } action.aliases(aliases); - }), new ParseField("aliases")); + }), ALIASES); return parser; } - private static final ObjectParser ADD_PARSER = parser("add", AliasActions::add); + private static final ObjectParser ADD_PARSER = parser(ADD.getPreferredName(), AliasActions::add); static { ADD_PARSER.declareObject(AliasActions::filter, (parser, m) -> { try { @@ -155,14 +173,15 @@ public class IndicesAliasesRequest extends AcknowledgedRequest REMOVE_PARSER = parser("remove", AliasActions::remove); - private static final ObjectParser REMOVE_INDEX_PARSER = parser("remove_index", AliasActions::removeIndex); + private static final ObjectParser REMOVE_PARSER = parser(REMOVE.getPreferredName(), AliasActions::remove); + private static final ObjectParser REMOVE_INDEX_PARSER = parser(REMOVE_INDEX.getPreferredName(), + AliasActions::removeIndex); /** * Parser for any one {@link AliasAction}. @@ -183,9 +202,9 @@ public class IndicesAliasesRequest extends AcknowledgedRequest PARSER = new ObjectParser<>("aliases", IndicesAliasesRequest::new); + static { + PARSER.declareObjectArray((request, actions) -> { + for (AliasActions action : actions) { + request.addAliasAction(action); + } + }, AliasActions.PARSER, new ParseField("actions")); + } + + public static IndicesAliasesRequest fromXContent(XContentParser parser) throws IOException { + return PARSER.apply(parser, null); + } } diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/alias/IndicesAliasesResponse.java b/server/src/main/java/org/elasticsearch/action/admin/indices/alias/IndicesAliasesResponse.java index 81fb1c1a64f..c3cc0b5ebd4 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/indices/alias/IndicesAliasesResponse.java +++ b/server/src/main/java/org/elasticsearch/action/admin/indices/alias/IndicesAliasesResponse.java @@ -22,16 +22,25 @@ package org.elasticsearch.action.admin.indices.alias; 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 add/remove alias action. */ -public class IndicesAliasesResponse extends AcknowledgedResponse { +public class IndicesAliasesResponse extends AcknowledgedResponse implements ToXContentObject { + + private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>("indices_aliases", + true, args -> new IndicesAliasesResponse((boolean) args[0])); + static { + declareAcknowledgedField(PARSER); + } IndicesAliasesResponse() { - } IndicesAliasesResponse(boolean acknowledged) { @@ -49,4 +58,16 @@ public class IndicesAliasesResponse 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 IndicesAliasesResponse fromXContent(XContentParser parser) throws IOException { + return PARSER.apply(parser, null); + } } \ No newline at end of file diff --git a/server/src/main/java/org/elasticsearch/action/support/master/AcknowledgedRequest.java b/server/src/main/java/org/elasticsearch/action/support/master/AcknowledgedRequest.java index 1180d3b1210..615aaec4875 100644 --- a/server/src/main/java/org/elasticsearch/action/support/master/AcknowledgedRequest.java +++ b/server/src/main/java/org/elasticsearch/action/support/master/AcknowledgedRequest.java @@ -18,7 +18,6 @@ */ package org.elasticsearch.action.support.master; -import org.elasticsearch.Version; import org.elasticsearch.cluster.ack.AckedRequest; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; diff --git a/server/src/main/java/org/elasticsearch/action/support/master/AcknowledgedResponse.java b/server/src/main/java/org/elasticsearch/action/support/master/AcknowledgedResponse.java index 3cce3d554f0..aac8f6af42c 100755 --- a/server/src/main/java/org/elasticsearch/action/support/master/AcknowledgedResponse.java +++ b/server/src/main/java/org/elasticsearch/action/support/master/AcknowledgedResponse.java @@ -24,7 +24,6 @@ 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; diff --git a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetAliasesAction.java b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetAliasesAction.java index 8cf4707262e..e5442c9a2f4 100644 --- a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetAliasesAction.java +++ b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetAliasesAction.java @@ -20,6 +20,7 @@ package org.elasticsearch.rest.action.admin.indices; import com.carrotsearch.hppc.cursors.ObjectObjectCursor; + import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest; import org.elasticsearch.action.admin.indices.alias.get.GetAliasesResponse; import org.elasticsearch.action.support.IndicesOptions; diff --git a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestIndicesAliasesAction.java b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestIndicesAliasesAction.java index b0c8122d4df..faae93803c8 100644 --- a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestIndicesAliasesAction.java +++ b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestIndicesAliasesAction.java @@ -36,14 +36,6 @@ import java.io.IOException; import static org.elasticsearch.rest.RestRequest.Method.POST; public class RestIndicesAliasesAction extends BaseRestHandler { - static final ObjectParser PARSER = new ObjectParser<>("aliases"); - static { - PARSER.declareObjectArray((request, actions) -> { - for (AliasActions action: actions) { - request.addAliasAction(action); - } - }, AliasActions.PARSER, new ParseField("actions")); - } @Override public String getName() { @@ -61,7 +53,7 @@ public class RestIndicesAliasesAction extends BaseRestHandler { indicesAliasesRequest.masterNodeTimeout(request.paramAsTime("master_timeout", indicesAliasesRequest.masterNodeTimeout())); indicesAliasesRequest.timeout(request.paramAsTime("timeout", indicesAliasesRequest.timeout())); try (XContentParser parser = request.contentParser()) { - PARSER.parse(parser, indicesAliasesRequest, null); + IndicesAliasesRequest.PARSER.parse(parser, indicesAliasesRequest, null); } if (indicesAliasesRequest.getAliasActions().isEmpty()) { throw new IllegalArgumentException("No action specified"); diff --git a/server/src/test/java/org/elasticsearch/action/admin/indices/alias/AliasActionsTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/alias/AliasActionsTests.java index 4a4aa736332..01c2457f967 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/indices/alias/AliasActionsTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/indices/alias/AliasActionsTests.java @@ -21,8 +21,10 @@ package org.elasticsearch.action.admin.indices.alias; import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions; import org.elasticsearch.common.ParsingException; +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.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentParser; @@ -30,13 +32,15 @@ import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.test.ESTestCase; import java.io.IOException; -import java.util.HashMap; import java.util.Map; import java.util.Objects; +import static org.elasticsearch.index.alias.RandomAliasActionsGenerator.randomAliasAction; +import static org.elasticsearch.index.alias.RandomAliasActionsGenerator.randomMap; +import static org.elasticsearch.index.alias.RandomAliasActionsGenerator.randomRouting; +import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.Matchers.arrayContaining; import static org.hamcrest.Matchers.arrayWithSize; -import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.instanceOf; public class AliasActionsTests extends ESTestCase { @@ -58,8 +62,7 @@ public class AliasActionsTests extends ESTestCase { Exception e = expectThrows(IllegalArgumentException.class, () -> new AliasActions(randomFrom(AliasActions.Type.values())).index(null)); assertEquals("[index] can't be empty string", e.getMessage()); - e = expectThrows(IllegalArgumentException.class, - () -> new AliasActions(randomFrom(AliasActions.Type.values())).index("")); + e = expectThrows(IllegalArgumentException.class, () -> new AliasActions(randomFrom(AliasActions.Type.values())).index("")); assertEquals("[index] can't be empty string", e.getMessage()); e = expectThrows(IllegalArgumentException.class, () -> new AliasActions(randomFrom(AliasActions.Type.values())).indices((String[]) null)); @@ -110,8 +113,10 @@ public class AliasActionsTests extends ESTestCase { Object searchRouting = randomBoolean() ? randomRouting() : null; Object indexRouting = randomBoolean() ? randomBoolean() ? searchRouting : randomRouting() : null; XContentBuilder b = XContentBuilder.builder(randomFrom(XContentType.values()).xContent()); - b.startObject(); { - b.startObject("add"); { + b.startObject(); + { + b.startObject("add"); + { if (indices.length > 1 || randomBoolean()) { b.array("indices", indices); } else { @@ -161,8 +166,10 @@ public class AliasActionsTests extends ESTestCase { Object searchRouting = randomRouting(); Object indexRouting = randomRouting(); XContentBuilder b = XContentBuilder.builder(randomFrom(XContentType.values()).xContent()); - b.startObject(); { - b.startObject("add"); { + b.startObject(); + { + b.startObject("add"); + { b.field("index", index); b.field("alias", alias); if (randomBoolean()) { @@ -191,8 +198,10 @@ public class AliasActionsTests extends ESTestCase { String[] indices = generateRandomStringArray(10, 5, false, false); String[] aliases = generateRandomStringArray(10, 5, false, false); XContentBuilder b = XContentBuilder.builder(randomFrom(XContentType.values()).xContent()); - b.startObject(); { - b.startObject("remove"); { + b.startObject(); + { + b.startObject("remove"); + { if (indices.length > 1 || randomBoolean()) { b.array("indices", indices); } else { @@ -217,10 +226,12 @@ public class AliasActionsTests extends ESTestCase { } public void testParseRemoveIndex() throws IOException { - String[] indices = randomBoolean() ? new String[] {randomAlphaOfLength(5)} : generateRandomStringArray(10, 5, false, false); + String[] indices = randomBoolean() ? new String[] { randomAlphaOfLength(5) } : generateRandomStringArray(10, 5, false, false); XContentBuilder b = XContentBuilder.builder(randomFrom(XContentType.values()).xContent()); - b.startObject(); { - b.startObject("remove_index"); { + b.startObject(); + { + b.startObject("remove_index"); + { if (indices.length > 1 || randomBoolean()) { b.array("indices", indices); } else { @@ -241,8 +252,10 @@ public class AliasActionsTests extends ESTestCase { public void testParseIndexAndIndicesThrowsError() throws IOException { XContentBuilder b = XContentBuilder.builder(randomFrom(XContentType.values()).xContent()); - b.startObject(); { - b.startObject(randomFrom("add", "remove")); { + b.startObject(); + { + b.startObject(randomFrom("add", "remove")); + { b.field("index", randomAlphaOfLength(5)); b.array("indices", generateRandomStringArray(10, 5, false, false)); b.field("alias", randomAlphaOfLength(5)); @@ -259,8 +272,10 @@ public class AliasActionsTests extends ESTestCase { public void testParseAliasAndAliasesThrowsError() throws IOException { XContentBuilder b = XContentBuilder.builder(randomFrom(XContentType.values()).xContent()); - b.startObject(); { - b.startObject(randomFrom("add", "remove")); { + b.startObject(); + { + b.startObject(randomFrom("add", "remove")); + { b.field("index", randomAlphaOfLength(5)); b.field("alias", randomAlphaOfLength(5)); b.array("aliases", generateRandomStringArray(10, 5, false, false)); @@ -311,38 +326,17 @@ public class AliasActionsTests extends ESTestCase { } } - - private Map randomMap(int maxDepth) { - int members = between(0, 5); - Map result = new HashMap<>(members); - for (int i = 0; i < members; i++) { - Object value; - switch (between(0, 3)) { - case 0: - if (maxDepth > 0) { - value = randomMap(maxDepth - 1); - } else { - value = randomAlphaOfLength(5); - } - break; - case 1: - value = randomAlphaOfLength(5); - break; - case 2: - value = randomBoolean(); - break; - case 3: - value = randomLong(); - break; - default: - throw new UnsupportedOperationException(); + public void testFromToXContent() throws IOException { + for (int runs = 0; runs < 20; runs++) { + AliasActions action = randomAliasAction(); + XContentType xContentType = randomFrom(XContentType.values()); + BytesReference shuffled = toShuffledXContent(action, xContentType, ToXContent.EMPTY_PARAMS, false, "filter"); + AliasActions parsedAction; + try (XContentParser parser = createParser(xContentType.xContent(), shuffled)) { + parsedAction = AliasActions.fromXContent(parser); + assertNull(parser.nextToken()); } - result.put(randomAlphaOfLength(5), value); + assertThat(parsedAction, equalTo(action)); } - return result; - } - - private Object randomRouting() { - return randomBoolean() ? randomAlphaOfLength(5) : randomInt(); } } diff --git a/test/framework/src/main/java/org/elasticsearch/index/alias/RandomAliasActionsGenerator.java b/test/framework/src/main/java/org/elasticsearch/index/alias/RandomAliasActionsGenerator.java new file mode 100644 index 00000000000..7a8355c05f9 --- /dev/null +++ b/test/framework/src/main/java/org/elasticsearch/index/alias/RandomAliasActionsGenerator.java @@ -0,0 +1,119 @@ +/* + * 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.index.alias; + +import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +import static org.elasticsearch.test.ESTestCase.between; +import static org.elasticsearch.test.ESTestCase.randomAlphaOfLength; +import static org.elasticsearch.test.ESTestCase.randomAlphaOfLengthBetween; +import static org.elasticsearch.test.ESTestCase.randomBoolean; +import static org.elasticsearch.test.ESTestCase.randomFrom; +import static org.elasticsearch.test.ESTestCase.randomInt; +import static org.elasticsearch.test.ESTestCase.randomIntBetween; +import static org.elasticsearch.test.ESTestCase.randomLong; + +public class RandomAliasActionsGenerator { + public static AliasActions randomAliasAction() { + return randomAliasAction(false); + } + + public static AliasActions randomAliasAction(boolean useStringAsFilter) { + AliasActions action = new AliasActions(randomFrom(AliasActions.Type.values())); + if (randomBoolean()) { + action.index(randomAlphaOfLength(5)); + } else { + int numIndices = randomIntBetween(1, 5); + String[] indices = new String[numIndices]; + for (int i = 0; i < numIndices; i++) { + indices[i] = "index-" + randomAlphaOfLengthBetween(2, 5).toLowerCase(Locale.ROOT); + } + action.indices(indices); + } + if (action.actionType() != AliasActions.Type.REMOVE_INDEX) { + if (randomBoolean()) { + action.alias(randomAlphaOfLength(5)); + } else { + int numAliases = randomIntBetween(1, 5); + String[] aliases = new String[numAliases]; + for (int i = 0; i < numAliases; i++) { + aliases[i] = "alias-" + randomAlphaOfLengthBetween(2, 5).toLowerCase(Locale.ROOT); + } + action.aliases(aliases); + } + } + if (action.actionType() == AliasActions.Type.ADD) { + if (randomBoolean()) { + if (useStringAsFilter) { + action.filter(randomAlphaOfLength(5)); + } else { + action.filter(randomMap(randomInt(5))); + } + } + if (randomBoolean()) { + if (randomBoolean()) { + action.routing(randomRouting().toString()); + } else { + action.searchRouting(randomRouting().toString()); + action.indexRouting(randomRouting().toString()); + } + } + } + return action; + } + + public static Map randomMap(int maxDepth) { + int members = between(0, 5); + Map result = new HashMap<>(members); + for (int i = 0; i < members; i++) { + Object value; + switch (between(0, 3)) { + case 0: + if (maxDepth > 0) { + value = randomMap(maxDepth - 1); + } else { + value = randomAlphaOfLength(5); + } + break; + case 1: + value = randomAlphaOfLength(5); + break; + case 2: + value = randomBoolean(); + break; + case 3: + value = randomLong(); + break; + default: + throw new UnsupportedOperationException(); + } + result.put(randomAlphaOfLength(5), value); + } + return result; + } + + public static Object randomRouting() { + return randomBoolean() ? randomAlphaOfLength(5) : randomInt(); + } +}