Add Indices Aliases API to the high level REST client (#27876)

Relates to #27205
This commit is contained in:
olcbean 2018-01-25 14:34:06 +01:00 committed by Luca Cavanna
parent 0c83240b5f
commit 9db23e48cd
17 changed files with 688 additions and 84 deletions

View File

@ -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<PutMappingResponse> 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
* <p>
* See <a href=
* "https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-aliases.html">
* Index Aliases API on elastic.co</a>
*/
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
* <p>
* See <a href=
* "https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-aliases.html">
* Index Aliases API on elastic.co</a>
*/
public void updateAliasesAsync(IndicesAliasesRequest indicesAliasesRequestRequest, ActionListener<IndicesAliasesResponse> listener,
Header... headers) {
restHighLevelClient.performRequestAsyncAndParseEntity(indicesAliasesRequestRequest, Request::updateAliases,
IndicesAliasesResponse::fromXContent, listener, Collections.emptySet(), headers);
}
/**

View File

@ -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.

View File

@ -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<String, Object> getAlias = getAlias(index, alias);
assertThat(getAlias.get("index_routing"), equalTo("routing"));
assertThat(getAlias.get("search_routing"), equalTo("search_routing"));
Map<String, Object> filter = (Map<String, Object>) getAlias.get("filter");
Map<String, Object> term = (Map<String, Object>) 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<String, Object> 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<String, Object> 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<String, Object> performGet = performGet(endpoint);
return (Map) ((Map) ((Map) performGet.get(index)).get("aliases")).get(alias);
}
private static Map<String, Object> performGet(final String endpoint) throws IOException {
Response response = client().performRequest("GET", endpoint);
XContentType entityContentType = XContentType.fromMediaTypeOrFormat(response.getEntity().getContentType().getValue());
Map<String, Object> responseEntity = XContentHelper.convertToMap(entityContentType.xContent(), response.getEntity().getContent(),
false);
assertNotNull(responseEntity);
return responseEntity;
}
}

View File

@ -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<String, String> 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();

View File

@ -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<IndicesAliasesResponse>() {
@Override
public void onResponse(IndicesAliasesResponse indciesAliasesResponse) {
// <1>
}
@Override
public void onFailure(Exception e) {
// <2>
}
});
// end::update-aliases-execute-async
}
}
}

View File

@ -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;
}
}

View File

@ -8,6 +8,8 @@ include::close_index.asciidoc[]
include::putmapping.asciidoc[]
include::update_aliases.asciidoc[]
include::_index.asciidoc[]
include::get.asciidoc[]

View File

@ -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 <<java-rest-high-delete-index>>
==== 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

View File

@ -9,6 +9,7 @@ Indices APIs::
* <<java-rest-high-open-index>>
* <<java-rest-high-close-index>>
* <<java-rest-high-put-mapping>>
* <<java-rest-high-update-aliases>>
Single document APIs::
* <<java-rest-high-document-index>>

View File

@ -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<IndicesAliasesRequest> {
public class IndicesAliasesRequest extends AcknowledgedRequest<IndicesAliasesRequest> implements ToXContentObject {
private List<AliasActions> 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<IndicesAliasesReq
private static final IndicesOptions INDICES_OPTIONS = IndicesOptions.fromOptions(false, false, true, false, true, false, true);
public IndicesAliasesRequest() {
}
/**
* Request to take one or more actions on one or more indexes and alias combinations.
*/
public static class AliasActions implements AliasesRequest, Writeable {
public static class AliasActions implements AliasesRequest, Writeable, ToXContentObject {
private static final ParseField INDEX = new ParseField("index");
private static final ParseField INDICES = new ParseField("indices");
private static final ParseField ALIAS = new ParseField("alias");
private static final ParseField ALIASES = new ParseField("aliases");
private static final ParseField FILTER = new ParseField("filter");
private static final ParseField ROUTING = new ParseField("routing");
private static final ParseField INDEX_ROUTING = new ParseField("index_routing", "indexRouting", "index-routing");
private static final ParseField SEARCH_ROUTING = new ParseField("search_routing", "searchRouting", "search-routing");
private static final ParseField ADD = new ParseField("add");
private static final ParseField REMOVE = new ParseField("remove");
private static final ParseField REMOVE_INDEX = new ParseField("remove_index");
public enum Type {
ADD((byte) 0),
REMOVE((byte) 1),
REMOVE_INDEX((byte) 2);
ADD((byte) 0, AliasActions.ADD),
REMOVE((byte) 1, AliasActions.REMOVE),
REMOVE_INDEX((byte) 2, AliasActions.REMOVE_INDEX);
private final byte value;
private final String fieldName;
Type(byte value) {
Type(byte value, ParseField field) {
this.value = value;
this.fieldName = field.getPreferredName();
}
public byte value() {
@ -125,29 +143,29 @@ public class IndicesAliasesRequest extends AcknowledgedRequest<IndicesAliasesReq
throw new IllegalArgumentException("Only one of [index] and [indices] is supported");
}
action.index(index);
}, new ParseField("index"));
}, INDEX);
parser.declareStringArray(fromList(String.class, (action, indices) -> {
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<AliasActions, Void> ADD_PARSER = parser("add", AliasActions::add);
private static final ObjectParser<AliasActions, Void> 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<IndicesAliasesReq
} catch (IOException e) {
throw new ParsingException(parser.getTokenLocation(), "Problems parsing [filter]", e);
}
}, new ParseField("filter"));
}, FILTER);
// Since we need to support numbers AND strings here we have to use ValueType.INT.
ADD_PARSER.declareField(AliasActions::routing, XContentParser::text, new ParseField("routing"), ValueType.INT);
ADD_PARSER.declareField(AliasActions::indexRouting, XContentParser::text, new ParseField("index_routing"), ValueType.INT);
ADD_PARSER.declareField(AliasActions::searchRouting, XContentParser::text, new ParseField("search_routing"), ValueType.INT);
ADD_PARSER.declareField(AliasActions::routing, XContentParser::text, ROUTING, ValueType.INT);
ADD_PARSER.declareField(AliasActions::indexRouting, XContentParser::text, INDEX_ROUTING, ValueType.INT);
ADD_PARSER.declareField(AliasActions::searchRouting, XContentParser::text, SEARCH_ROUTING, ValueType.INT);
}
private static final ObjectParser<AliasActions, Void> REMOVE_PARSER = parser("remove", AliasActions::remove);
private static final ObjectParser<AliasActions, Void> REMOVE_INDEX_PARSER = parser("remove_index", AliasActions::removeIndex);
private static final ObjectParser<AliasActions, Void> REMOVE_PARSER = parser(REMOVE.getPreferredName(), AliasActions::remove);
private static final ObjectParser<AliasActions, Void> REMOVE_INDEX_PARSER = parser(REMOVE_INDEX.getPreferredName(),
AliasActions::removeIndex);
/**
* Parser for any one {@link AliasAction}.
@ -183,9 +202,9 @@ public class IndicesAliasesRequest extends AcknowledgedRequest<IndicesAliasesReq
return action;
});
static {
PARSER.declareObject(optionalConstructorArg(), ADD_PARSER, new ParseField("add"));
PARSER.declareObject(optionalConstructorArg(), REMOVE_PARSER, new ParseField("remove"));
PARSER.declareObject(optionalConstructorArg(), REMOVE_INDEX_PARSER, new ParseField("remove_index"));
PARSER.declareObject(optionalConstructorArg(), ADD_PARSER, ADD);
PARSER.declareObject(optionalConstructorArg(), REMOVE_PARSER, REMOVE);
PARSER.declareObject(optionalConstructorArg(), REMOVE_INDEX_PARSER, REMOVE_INDEX);
}
private final AliasActions.Type type;
@ -196,7 +215,7 @@ public class IndicesAliasesRequest extends AcknowledgedRequest<IndicesAliasesReq
private String indexRouting;
private String searchRouting;
AliasActions(AliasActions.Type type) {
public AliasActions(AliasActions.Type type) {
this.type = type;
}
@ -402,6 +421,37 @@ public class IndicesAliasesRequest extends AcknowledgedRequest<IndicesAliasesReq
return INDICES_OPTIONS;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.startObject(type.fieldName);
if (null != indices && 0 != indices.length) {
builder.array(INDICES.getPreferredName(), indices);
}
if (0 != aliases.length) {
builder.array(ALIASES.getPreferredName(), aliases);
}
if (false == Strings.isEmpty(filter)) {
builder.rawField(FILTER.getPreferredName(), new BytesArray(filter), XContentType.JSON);
}
if (false == Strings.isEmpty(routing)) {
builder.field(ROUTING.getPreferredName(), routing);
}
if (false == Strings.isEmpty(indexRouting)) {
builder.field(INDEX_ROUTING.getPreferredName(), indexRouting);
}
if (false == Strings.isEmpty(searchRouting)) {
builder.field(SEARCH_ROUTING.getPreferredName(), searchRouting);
}
builder.endObject();
builder.endObject();
return builder;
}
public static AliasActions fromXContent(XContentParser parser) throws IOException {
return PARSER.apply(parser, null);
}
@Override
public String toString() {
return "AliasActions["
@ -478,4 +528,29 @@ public class IndicesAliasesRequest extends AcknowledgedRequest<IndicesAliasesReq
public IndicesOptions indicesOptions() {
return INDICES_OPTIONS;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.startArray("actions");
for (AliasActions action : allAliasActions) {
action.toXContent(builder, params);
}
builder.endArray();
builder.endObject();
return builder;
}
public static final ObjectParser<IndicesAliasesRequest, Void> 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);
}
}

View File

@ -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<IndicesAliasesResponse, Void> 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);
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -36,14 +36,6 @@ import java.io.IOException;
import static org.elasticsearch.rest.RestRequest.Method.POST;
public class RestIndicesAliasesAction extends BaseRestHandler {
static final ObjectParser<IndicesAliasesRequest, Void> 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");

View File

@ -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<String, Object> randomMap(int maxDepth) {
int members = between(0, 5);
Map<String, Object> 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();
}
}

View File

@ -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<String, Object> randomMap(int maxDepth) {
int members = between(0, 5);
Map<String, Object> 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();
}
}