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 bed7d30242801..24c0175b7e884 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 @@ -27,8 +27,6 @@ import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequest; import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheResponse; import org.elasticsearch.action.admin.indices.close.CloseIndexRequest; -import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; -import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.admin.indices.flush.FlushRequest; import org.elasticsearch.action.admin.indices.flush.FlushResponse; @@ -59,6 +57,8 @@ import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryResponse; import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.client.core.ShardsAcknowledgedResponse; +import org.elasticsearch.client.indices.CreateIndexRequest; +import org.elasticsearch.client.indices.CreateIndexResponse; import org.elasticsearch.client.indices.FreezeIndexRequest; import org.elasticsearch.client.indices.GetIndexTemplatesRequest; import org.elasticsearch.client.indices.IndexTemplatesExistRequest; @@ -120,9 +120,10 @@ public void deleteAsync(DeleteIndexRequest deleteIndexRequest, RequestOptions op * @return the response * @throws IOException in case there is a problem sending the request or parsing back the response */ - public CreateIndexResponse create(CreateIndexRequest createIndexRequest, RequestOptions options) throws IOException { + public CreateIndexResponse create(CreateIndexRequest createIndexRequest, + RequestOptions options) throws IOException { return restHighLevelClient.performRequestAndParseEntity(createIndexRequest, IndicesRequestConverters::createIndex, options, - CreateIndexResponse::fromXContent, emptySet()); + CreateIndexResponse::fromXContent, emptySet()); } /** @@ -133,9 +134,54 @@ public CreateIndexResponse create(CreateIndexRequest createIndexRequest, Request * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized * @param listener the listener to be notified upon request completion */ - public void createAsync(CreateIndexRequest createIndexRequest, RequestOptions options, ActionListener listener) { + public void createAsync(CreateIndexRequest createIndexRequest, + RequestOptions options, + ActionListener listener) { restHighLevelClient.performRequestAsyncAndParseEntity(createIndexRequest, IndicesRequestConverters::createIndex, options, - CreateIndexResponse::fromXContent, listener, emptySet()); + CreateIndexResponse::fromXContent, listener, emptySet()); + } + + /** + * Creates an index using the Create Index API. + * See + * Create Index API on elastic.co + * @param createIndexRequest the request + * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @return the response + * @throws IOException in case there is a problem sending the request or parsing back the response + * + * @deprecated This method uses an old request object which still refers to types, a deprecated feature. The + * method {@link #create(CreateIndexRequest, RequestOptions)} should be used instead, which accepts a new + * request object. + */ + @Deprecated + public org.elasticsearch.action.admin.indices.create.CreateIndexResponse create( + org.elasticsearch.action.admin.indices.create.CreateIndexRequest createIndexRequest, + RequestOptions options) throws IOException { + return restHighLevelClient.performRequestAndParseEntity(createIndexRequest, + IndicesRequestConverters::createIndex, options, + org.elasticsearch.action.admin.indices.create.CreateIndexResponse::fromXContent, emptySet()); + } + + /** + * Asynchronously creates an index using the Create Index API. + * See + * Create Index API on elastic.co + * @param createIndexRequest the request + * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @param listener the listener to be notified upon request completion + * + * @deprecated This method uses an old request object which still refers to types, a deprecated feature. The + * method {@link #createAsync(CreateIndexRequest, RequestOptions, ActionListener)} should be used instead, + * which accepts a new request object. + */ + @Deprecated + public void createAsync(org.elasticsearch.action.admin.indices.create.CreateIndexRequest createIndexRequest, + RequestOptions options, + ActionListener listener) { + restHighLevelClient.performRequestAsyncAndParseEntity(createIndexRequest, + IndicesRequestConverters::createIndex, options, + org.elasticsearch.action.admin.indices.create.CreateIndexResponse::fromXContent, listener, emptySet()); } /** diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesRequestConverters.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesRequestConverters.java index ece8bdffa2566..2b44e3006b1be 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesRequestConverters.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesRequestConverters.java @@ -29,7 +29,6 @@ import org.elasticsearch.action.admin.indices.analyze.AnalyzeRequest; import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequest; import org.elasticsearch.action.admin.indices.close.CloseIndexRequest; -import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.admin.indices.flush.FlushRequest; import org.elasticsearch.action.admin.indices.flush.SyncedFlushRequest; @@ -47,6 +46,7 @@ import org.elasticsearch.action.admin.indices.template.delete.DeleteIndexTemplateRequest; import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest; import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryRequest; +import org.elasticsearch.client.indices.CreateIndexRequest; import org.elasticsearch.client.indices.FreezeIndexRequest; import org.elasticsearch.client.indices.GetIndexTemplatesRequest; import org.elasticsearch.client.indices.IndexTemplatesExistRequest; @@ -98,6 +98,21 @@ static Request closeIndex(CloseIndexRequest closeIndexRequest) { } static Request createIndex(CreateIndexRequest createIndexRequest) throws IOException { + String endpoint = new RequestConverters.EndpointBuilder() + .addPathPart(createIndexRequest.index()).build(); + Request request = new Request(HttpPut.METHOD_NAME, endpoint); + + RequestConverters.Params parameters = new RequestConverters.Params(request); + parameters.withTimeout(createIndexRequest.timeout()); + parameters.withMasterTimeout(createIndexRequest.masterNodeTimeout()); + parameters.withWaitForActiveShards(createIndexRequest.waitForActiveShards()); + + request.setEntity(RequestConverters.createEntity(createIndexRequest, RequestConverters.REQUEST_BODY_CONTENT_TYPE)); + return request; + } + + static Request createIndex(org.elasticsearch.action.admin.indices.create.CreateIndexRequest createIndexRequest) + throws IOException { String endpoint = RequestConverters.endpoint(createIndexRequest.indices()); Request request = new Request(HttpPut.METHOD_NAME, endpoint); diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/indices/CreateIndexRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/indices/CreateIndexRequest.java new file mode 100644 index 0000000000000..f0bff6e6f4307 --- /dev/null +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/indices/CreateIndexRequest.java @@ -0,0 +1,364 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.client.indices; + +import org.elasticsearch.ElasticsearchGenerationException; +import org.elasticsearch.ElasticsearchParseException; +import org.elasticsearch.action.admin.indices.alias.Alias; +import org.elasticsearch.action.support.ActiveShardCount; +import org.elasticsearch.client.TimedRequest; +import org.elasticsearch.client.Validatable; +import org.elasticsearch.common.ParseField; +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.bytes.BytesArray; +import org.elasticsearch.common.bytes.BytesReference; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.xcontent.DeprecationHandler; +import org.elasticsearch.common.xcontent.NamedXContentRegistry; +import org.elasticsearch.common.xcontent.ToXContentObject; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.common.xcontent.XContentHelper; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.common.xcontent.XContentType; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +import static org.elasticsearch.common.settings.Settings.Builder.EMPTY_SETTINGS; + +/** + * A request to create an index. + */ +public class CreateIndexRequest extends TimedRequest implements Validatable, ToXContentObject { + static final ParseField MAPPINGS = new ParseField("mappings"); + static final ParseField SETTINGS = new ParseField("settings"); + static final ParseField ALIASES = new ParseField("aliases"); + + private final String index; + private Settings settings = EMPTY_SETTINGS; + + private BytesReference mappings; + private XContentType mappingsXContentType; + + private final Set aliases = new HashSet<>(); + + private ActiveShardCount waitForActiveShards = ActiveShardCount.DEFAULT; + + /** + * Constructs a new request to create an index with the specified name. + */ + public CreateIndexRequest(String index) { + if (index == null) { + throw new IllegalArgumentException("The index name cannot be null."); + } + this.index = index; + } + + /** + * The name of the index to create. + */ + public String index() { + return index; + } + + /** + * The settings to create the index with. + */ + public Settings settings() { + return settings; + } + + /** + * The settings to create the index with. + */ + public CreateIndexRequest settings(Settings.Builder settings) { + this.settings = settings.build(); + return this; + } + + /** + * The settings to create the index with. + */ + public CreateIndexRequest settings(Settings settings) { + this.settings = settings; + return this; + } + + /** + * The settings to create the index with (either json or yaml format) + */ + public CreateIndexRequest settings(String source, XContentType xContentType) { + this.settings = Settings.builder().loadFromSource(source, xContentType).build(); + return this; + } + + /** + * Allows to set the settings using a json builder. + */ + public CreateIndexRequest settings(XContentBuilder builder) { + settings(Strings.toString(builder), builder.contentType()); + return this; + } + + /** + * The settings to create the index with (either json/yaml/properties format) + */ + public CreateIndexRequest settings(Map source) { + try { + XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON); + builder.map(source); + settings(Strings.toString(builder), XContentType.JSON); + } catch (IOException e) { + throw new ElasticsearchGenerationException("Failed to generate [" + source + "]", e); + } + return this; + } + + public BytesReference mappings() { + return mappings; + } + + public XContentType mappingsXContentType() { + return mappingsXContentType; + } + + /** + * Adds mapping that will be added when the index gets created. + * + * Note that the definition should *not* be nested under a type name. + * + * @param source The mapping source + * @param xContentType The content type of the source + */ + public CreateIndexRequest mapping(String source, XContentType xContentType) { + return mapping(new BytesArray(source), xContentType); + } + + /** + * Adds mapping that will be added when the index gets created. + * + * Note that the definition should *not* be nested under a type name. + * + * @param source The mapping source + */ + public CreateIndexRequest mapping(XContentBuilder source) { + return mapping(BytesReference.bytes(source), source.contentType()); + } + + /** + * Adds mapping that will be added when the index gets created. + * + * Note that the definition should *not* be nested under a type name. + * + * @param source The mapping source + */ + public CreateIndexRequest mapping(Map source) { + try { + XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON); + builder.map(source); + return mapping(BytesReference.bytes(builder), builder.contentType()); + } catch (IOException e) { + throw new ElasticsearchGenerationException("Failed to generate [" + source + "]", e); + } + } + + /** + * Adds mapping that will be added when the index gets created. + * + * Note that the definition should *not* be nested under a type name. + * + * @param source The mapping source + * @param xContentType the content type of the mapping source + */ + public CreateIndexRequest mapping(BytesReference source, XContentType xContentType) { + Objects.requireNonNull(xContentType); + mappings = source; + mappingsXContentType = xContentType; + return this; + } + + public Set aliases() { + return this.aliases; + } + + /** + * Sets the aliases that will be associated with the index when it gets created + */ + public CreateIndexRequest aliases(Map source) { + try { + XContentBuilder builder = XContentFactory.jsonBuilder(); + builder.map(source); + return aliases(BytesReference.bytes(builder), builder.contentType()); + } catch (IOException e) { + throw new ElasticsearchGenerationException("Failed to generate [" + source + "]", e); + } + } + + /** + * Sets the aliases that will be associated with the index when it gets created + */ + public CreateIndexRequest aliases(XContentBuilder source) { + return aliases(BytesReference.bytes(source), source.contentType()); + } + + /** + * Sets the aliases that will be associated with the index when it gets created + */ + public CreateIndexRequest aliases(String source, XContentType contentType) { + return aliases(new BytesArray(source), contentType); + } + + /** + * Sets the aliases that will be associated with the index when it gets created + */ + public CreateIndexRequest aliases(BytesReference source, XContentType contentType) { + // EMPTY is safe here because we never call namedObject + try (XContentParser parser = XContentHelper.createParser(NamedXContentRegistry.EMPTY, + DeprecationHandler.THROW_UNSUPPORTED_OPERATION, source, contentType)) { + //move to the first alias + parser.nextToken(); + while ((parser.nextToken()) != XContentParser.Token.END_OBJECT) { + alias(Alias.fromXContent(parser)); + } + return this; + } catch(IOException e) { + throw new ElasticsearchParseException("Failed to parse aliases", e); + } + } + + /** + * Adds an alias that will be associated with the index when it gets created + */ + public CreateIndexRequest alias(Alias alias) { + this.aliases.add(alias); + return this; + } + + /** + * Adds aliases that will be associated with the index when it gets created + */ + public CreateIndexRequest aliases(Collection aliases) { + this.aliases.addAll(aliases); + return this; + } + + /** + * Sets the settings and mappings as a single source. + * + * Note that the mapping definition should *not* be nested under a type name. + */ + public CreateIndexRequest source(String source, XContentType xContentType) { + return source(new BytesArray(source), xContentType); + } + + /** + * Sets the settings and mappings as a single source. + * + * Note that the mapping definition should *not* be nested under a type name. + */ + public CreateIndexRequest source(XContentBuilder source) { + return source(BytesReference.bytes(source), source.contentType()); + } + + /** + * Sets the settings and mappings as a single source. + * + * Note that the mapping definition should *not* be nested under a type name. + */ + public CreateIndexRequest source(BytesReference source, XContentType xContentType) { + Objects.requireNonNull(xContentType); + source(XContentHelper.convertToMap(source, false, xContentType).v2()); + return this; + } + + /** + * Sets the settings and mappings as a single source. + * + * Note that the mapping definition should *not* be nested under a type name. + */ + @SuppressWarnings("unchecked") + public CreateIndexRequest source(Map source) { + DeprecationHandler deprecationHandler = DeprecationHandler.THROW_UNSUPPORTED_OPERATION; + for (Map.Entry entry : source.entrySet()) { + String name = entry.getKey(); + if (SETTINGS.match(name, deprecationHandler)) { + settings((Map) entry.getValue()); + } else if (MAPPINGS.match(name, deprecationHandler)) { + mapping((Map) entry.getValue()); + } else if (ALIASES.match(name, deprecationHandler)) { + aliases((Map) entry.getValue()); + } + } + return this; + } + + public ActiveShardCount waitForActiveShards() { + return waitForActiveShards; + } + + /** + * Sets the number of shard copies that should be active for index creation to return. + * Defaults to {@link ActiveShardCount#DEFAULT}, which will wait for one shard copy + * (the primary) to become active. Set this value to {@link ActiveShardCount#ALL} to + * wait for all shards (primary and all replicas) to be active before returning. + * Otherwise, use {@link ActiveShardCount#from(int)} to set this value to any + * non-negative integer, up to the number of copies per shard (number of replicas + 1), + * to wait for the desired amount of shard copies to become active before returning. + * Index creation will only wait up until the timeout value for the number of shard copies + * to be active before returning. Check {@link CreateIndexResponse#isShardsAcknowledged()} to + * determine if the requisite shard copies were all started before returning or timing out. + * + * @param waitForActiveShards number of active shard copies to wait on + */ + public CreateIndexRequest waitForActiveShards(ActiveShardCount waitForActiveShards) { + this.waitForActiveShards = waitForActiveShards; + return this; + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + + builder.startObject(SETTINGS.getPreferredName()); + settings.toXContent(builder, params); + builder.endObject(); + + if (mappings != null) { + try (InputStream stream = mappings.streamInput()) { + builder.rawField(MAPPINGS.getPreferredName(), stream, mappingsXContentType); + } + } + + builder.startObject(ALIASES.getPreferredName()); + for (Alias alias : aliases) { + alias.toXContent(builder, params); + } + builder.endObject(); + + builder.endObject(); + return builder; + } +} diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/indices/CreateIndexResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/indices/CreateIndexResponse.java new file mode 100644 index 0000000000000..9755edd680f53 --- /dev/null +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/indices/CreateIndexResponse.java @@ -0,0 +1,74 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.client.indices; + +import org.elasticsearch.action.support.master.ShardsAcknowledgedResponse; +import org.elasticsearch.common.ParseField; +import org.elasticsearch.common.xcontent.ConstructingObjectParser; +import org.elasticsearch.common.xcontent.ObjectParser; +import org.elasticsearch.common.xcontent.XContentParser; + +import java.util.Objects; + +import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg; + +/** + * A response for a create index action. + */ +public class CreateIndexResponse extends ShardsAcknowledgedResponse { + + private static final ParseField INDEX = new ParseField("index"); + private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>("create_index", + true, args -> new CreateIndexResponse((boolean) args[0], (boolean) args[1], (String) args[2])); + + static { + declareAcknowledgedAndShardsAcknowledgedFields(PARSER); + PARSER.declareField(constructorArg(), (parser, context) -> parser.textOrNull(), INDEX, ObjectParser.ValueType.STRING_OR_NULL); + } + + private String index; + + public CreateIndexResponse(boolean acknowledged, boolean shardsAcknowledged, String index) { + super(acknowledged, shardsAcknowledged); + this.index = index; + } + + public String index() { + return index; + } + + public static CreateIndexResponse fromXContent(XContentParser parser) { + return PARSER.apply(parser, null); + } + + @Override + public boolean equals(Object o) { + if (super.equals(o)) { + CreateIndexResponse that = (CreateIndexResponse) o; + return Objects.equals(index, that.index); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), index); + } +} diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/CCRIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/CCRIT.java index 90799522372dc..97a379aa16a90 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/CCRIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/CCRIT.java @@ -24,8 +24,6 @@ import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest; import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsResponse; import org.elasticsearch.action.admin.indices.close.CloseIndexRequest; -import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; -import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; @@ -46,6 +44,8 @@ import org.elasticsearch.client.ccr.ResumeFollowRequest; import org.elasticsearch.client.ccr.UnfollowRequest; import org.elasticsearch.client.core.AcknowledgedResponse; +import org.elasticsearch.client.indices.CreateIndexRequest; +import org.elasticsearch.client.indices.CreateIndexResponse; import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.json.JsonXContent; diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/ESRestHighLevelClientTestCase.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/ESRestHighLevelClientTestCase.java index efe94596b81b6..976ae754d335f 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/ESRestHighLevelClientTestCase.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/ESRestHighLevelClientTestCase.java @@ -21,11 +21,11 @@ import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest; -import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.ingest.PutPipelineRequest; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.support.PlainActionFuture; +import org.elasticsearch.client.indices.CreateIndexRequest; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.ThreadContext; 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 72bc366e7a9c9..fe175b217bd5e 100644 --- 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 @@ -33,8 +33,6 @@ import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequest; import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheResponse; import org.elasticsearch.action.admin.indices.close.CloseIndexRequest; -import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; -import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.admin.indices.flush.FlushRequest; import org.elasticsearch.action.admin.indices.flush.FlushResponse; @@ -43,8 +41,6 @@ import org.elasticsearch.action.admin.indices.forcemerge.ForceMergeResponse; import org.elasticsearch.action.admin.indices.get.GetIndexRequest; import org.elasticsearch.action.admin.indices.get.GetIndexResponse; -import org.elasticsearch.client.indices.GetFieldMappingsRequest; -import org.elasticsearch.client.indices.GetFieldMappingsResponse; import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest; import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse; import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; @@ -70,7 +66,11 @@ import org.elasticsearch.action.support.broadcast.BroadcastResponse; import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.client.core.ShardsAcknowledgedResponse; +import org.elasticsearch.client.indices.CreateIndexRequest; +import org.elasticsearch.client.indices.CreateIndexResponse; import org.elasticsearch.client.indices.FreezeIndexRequest; +import org.elasticsearch.client.indices.GetFieldMappingsRequest; +import org.elasticsearch.client.indices.GetFieldMappingsResponse; import org.elasticsearch.client.indices.GetIndexTemplatesRequest; import org.elasticsearch.client.indices.IndexTemplatesExistRequest; import org.elasticsearch.client.indices.PutMappingRequest; @@ -93,6 +93,7 @@ import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.rest.RestStatus; +import org.elasticsearch.rest.action.admin.indices.RestCreateIndexAction; import org.elasticsearch.rest.action.admin.indices.RestGetFieldMappingAction; import org.elasticsearch.rest.action.admin.indices.RestPutMappingAction; @@ -212,7 +213,7 @@ public void testCreateIndex() throws IOException { mappingBuilder.startObject().startObject("properties").startObject("field"); mappingBuilder.field("type", "text"); mappingBuilder.endObject().endObject().endObject(); - createIndexRequest.mapping(MapperService.SINGLE_MAPPING_NAME, mappingBuilder); + createIndexRequest.mapping(mappingBuilder); CreateIndexResponse createIndexResponse = execute(createIndexRequest, highLevelClient().indices()::create, highLevelClient().indices()::createAsync); @@ -233,6 +234,70 @@ public void testCreateIndex() throws IOException { } } + @SuppressWarnings({"unchecked", "rawtypes"}) + public void testCreateIndexWithTypes() throws IOException { + { + // Create index + String indexName = "plain_index"; + assertFalse(indexExists(indexName)); + + org.elasticsearch.action.admin.indices.create.CreateIndexRequest createIndexRequest = + new org.elasticsearch.action.admin.indices.create.CreateIndexRequest(indexName); + + org.elasticsearch.action.admin.indices.create.CreateIndexResponse createIndexResponse = execute( + createIndexRequest, + highLevelClient().indices()::create, + highLevelClient().indices()::createAsync, + expectWarnings(RestCreateIndexAction.TYPES_DEPRECATION_MESSAGE)); + assertTrue(createIndexResponse.isAcknowledged()); + + assertTrue(indexExists(indexName)); + } + { + // Create index with mappings, aliases and settings + String indexName = "rich_index"; + assertFalse(indexExists(indexName)); + + org.elasticsearch.action.admin.indices.create.CreateIndexRequest createIndexRequest = + new org.elasticsearch.action.admin.indices.create.CreateIndexRequest(indexName); + + Alias alias = new Alias("alias_name"); + alias.filter("{\"term\":{\"year\":2016}}"); + alias.routing("1"); + createIndexRequest.alias(alias); + + Settings.Builder settings = Settings.builder(); + settings.put(SETTING_NUMBER_OF_REPLICAS, 2); + createIndexRequest.settings(settings); + + XContentBuilder mappingBuilder = JsonXContent.contentBuilder(); + mappingBuilder.startObject().startObject("properties").startObject("field"); + mappingBuilder.field("type", "text"); + mappingBuilder.endObject().endObject().endObject(); + createIndexRequest.mapping(MapperService.SINGLE_MAPPING_NAME, mappingBuilder); + + org.elasticsearch.action.admin.indices.create.CreateIndexResponse createIndexResponse = execute( + createIndexRequest, + highLevelClient().indices()::create, + highLevelClient().indices()::createAsync, + expectWarnings(RestCreateIndexAction.TYPES_DEPRECATION_MESSAGE)); + assertTrue(createIndexResponse.isAcknowledged()); + + Map getIndexResponse = getAsMap(indexName); + assertEquals("2", XContentMapValues.extractValue(indexName + ".settings.index.number_of_replicas", getIndexResponse)); + + Map aliasData = + (Map)XContentMapValues.extractValue(indexName + ".aliases.alias_name", getIndexResponse); + assertNotNull(aliasData); + assertEquals("1", aliasData.get("index_routing")); + Map filter = (Map) aliasData.get("filter"); + Map term = (Map) filter.get("term"); + assertEquals(2016, term.get("year")); + + assertEquals("text", XContentMapValues.extractValue(indexName + ".mappings.properties.field.type", getIndexResponse)); + } + } + public void testGetSettings() throws IOException { String indexName = "get_settings_index"; Settings basicSettings = Settings.builder() @@ -915,7 +980,9 @@ public void testShrink() throws IOException { .put("index.number_of_replicas", 0) .putNull("index.routing.allocation.require._name") .build(); - resizeRequest.setTargetIndex(new CreateIndexRequest("target").settings(targetSettings).alias(new Alias("alias"))); + resizeRequest.setTargetIndex(new org.elasticsearch.action.admin.indices.create.CreateIndexRequest("target") + .settings(targetSettings) + .alias(new Alias("alias"))); ResizeResponse resizeResponse = execute(resizeRequest, highLevelClient().indices()::shrink, highLevelClient().indices()::shrinkAsync); assertTrue(resizeResponse.isAcknowledged()); @@ -938,7 +1005,9 @@ public void testSplit() throws IOException { ResizeRequest resizeRequest = new ResizeRequest("target", "source"); resizeRequest.setResizeType(ResizeType.SPLIT); Settings targetSettings = Settings.builder().put("index.number_of_shards", 4).put("index.number_of_replicas", 0).build(); - resizeRequest.setTargetIndex(new CreateIndexRequest("target").settings(targetSettings).alias(new Alias("alias"))); + resizeRequest.setTargetIndex(new org.elasticsearch.action.admin.indices.create.CreateIndexRequest("target") + .settings(targetSettings) + .alias(new Alias("alias"))); ResizeResponse resizeResponse = execute(resizeRequest, highLevelClient().indices()::split, highLevelClient().indices()::splitAsync); assertTrue(resizeResponse.isAcknowledged()); assertTrue(resizeResponse.isShardsAcknowledged()); diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesRequestConvertersTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesRequestConvertersTests.java index 3e4dcd0209764..5e08381720ec7 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesRequestConvertersTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesRequestConvertersTests.java @@ -32,7 +32,6 @@ import org.elasticsearch.action.admin.indices.analyze.AnalyzeRequest; import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequest; import org.elasticsearch.action.admin.indices.close.CloseIndexRequest; -import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.admin.indices.flush.FlushRequest; import org.elasticsearch.action.admin.indices.flush.SyncedFlushRequest; @@ -50,6 +49,8 @@ import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest; import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryRequest; import org.elasticsearch.action.support.master.AcknowledgedRequest; +import org.elasticsearch.client.indices.CreateIndexRequest; +import org.elasticsearch.client.indices.RandomCreateIndexGenerator; import org.elasticsearch.client.indices.GetIndexTemplatesRequest; import org.elasticsearch.client.indices.IndexTemplatesExistRequest; import org.elasticsearch.client.indices.PutMappingRequest; @@ -59,7 +60,6 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.util.CollectionUtils; -import org.elasticsearch.index.RandomCreateIndexGenerator; import org.elasticsearch.test.ESTestCase; import org.junit.Assert; @@ -75,7 +75,6 @@ import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; import static org.elasticsearch.index.RandomCreateIndexGenerator.randomAliases; -import static org.elasticsearch.index.RandomCreateIndexGenerator.randomCreateIndexRequest; import static org.elasticsearch.index.RandomCreateIndexGenerator.randomIndexSettings; import static org.elasticsearch.index.alias.RandomAliasActionsGenerator.randomAliasAction; import static org.elasticsearch.rest.BaseRestHandler.INCLUDE_TYPE_NAME_PARAMETER; @@ -127,7 +126,23 @@ public void testIndicesExistEmptyIndices() { } public void testCreateIndex() throws IOException { - CreateIndexRequest createIndexRequest = randomCreateIndexRequest(); + CreateIndexRequest createIndexRequest = RandomCreateIndexGenerator.randomCreateIndexRequest(); + + Map expectedParams = new HashMap<>(); + RequestConvertersTests.setRandomTimeout(createIndexRequest, AcknowledgedRequest.DEFAULT_ACK_TIMEOUT, expectedParams); + RequestConvertersTests.setRandomMasterTimeout(createIndexRequest, expectedParams); + RequestConvertersTests.setRandomWaitForActiveShards(createIndexRequest::waitForActiveShards, expectedParams); + + Request request = IndicesRequestConverters.createIndex(createIndexRequest); + Assert.assertEquals("/" + createIndexRequest.index(), request.getEndpoint()); + Assert.assertEquals(expectedParams, request.getParameters()); + Assert.assertEquals(HttpPut.METHOD_NAME, request.getMethod()); + RequestConvertersTests.assertToXContentBody(createIndexRequest, request.getEntity()); + } + + public void testCreateIndexWithTypes() throws IOException { + org.elasticsearch.action.admin.indices.create.CreateIndexRequest createIndexRequest = + org.elasticsearch.index.RandomCreateIndexGenerator.randomCreateIndexRequest(); Map expectedParams = new HashMap<>(); RequestConvertersTests.setRandomTimeout(createIndexRequest::timeout, AcknowledgedRequest.DEFAULT_ACK_TIMEOUT, expectedParams); @@ -143,8 +158,8 @@ public void testCreateIndex() throws IOException { } public void testCreateIndexNullIndex() { - ActionRequestValidationException validationException = new CreateIndexRequest(null).validate(); - Assert.assertNotNull(validationException); + IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> new CreateIndexRequest(null)); + assertEquals(e.getMessage(), "The index name cannot be null."); } public void testUpdateAliases() throws IOException { @@ -754,7 +769,8 @@ private void resizeTest(ResizeType resizeType, CheckedFunction + request.mapping(// <1> "{\n" + - " \"_doc\": {\n" + - " \"properties\": {\n" + - " \"message\": {\n" + - " \"type\": \"text\"\n" + - " }\n" + + " \"properties\": {\n" + + " \"message\": {\n" + + " \"type\": \"text\"\n" + " }\n" + " }\n" + "}", // <2> @@ -325,7 +324,7 @@ public void testCreateIndex() throws IOException { Map mapping = new HashMap<>(); mapping.put("properties", properties); jsonMap.put("_doc", mapping); - request.mapping("_doc", jsonMap); // <1> + request.mapping(jsonMap); // <1> //end::create-index-mappings-map CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT); assertTrue(createIndexResponse.isAcknowledged()); @@ -351,19 +350,11 @@ public void testCreateIndex() throws IOException { builder.endObject(); } builder.endObject(); - request.mapping("_doc", builder); // <1> + request.mapping(builder); // <1> //end::create-index-mappings-xcontent CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT); assertTrue(createIndexResponse.isAcknowledged()); } - { - request = new CreateIndexRequest("twitter4"); - //tag::create-index-mappings-shortcut - request.mapping("_doc", "message", "type=text"); // <1> - //end::create-index-mappings-shortcut - CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT); - assertTrue(createIndexResponse.isAcknowledged()); - } request = new CreateIndexRequest("twitter5"); // tag::create-index-request-aliases @@ -371,15 +362,13 @@ public void testCreateIndex() throws IOException { // end::create-index-request-aliases // tag::create-index-request-timeout - request.timeout(TimeValue.timeValueMinutes(2)); // <1> - request.timeout("2m"); // <2> + request.setTimeout(TimeValue.timeValueMinutes(2)); // <1> // end::create-index-request-timeout // tag::create-index-request-masterTimeout - request.masterNodeTimeout(TimeValue.timeValueMinutes(1)); // <1> - request.masterNodeTimeout("1m"); // <2> + request.setMasterTimeout(TimeValue.timeValueMinutes(1)); // <1> // end::create-index-request-masterTimeout // tag::create-index-request-waitForActiveShards - request.waitForActiveShards(2); // <1> + request.waitForActiveShards(ActiveShardCount.from(2)); // <1> request.waitForActiveShards(ActiveShardCount.DEFAULT); // <2> // end::create-index-request-waitForActiveShards { @@ -1118,7 +1107,7 @@ public void testGetSettings() throws Exception { { Settings settings = Settings.builder().put("number_of_shards", 3).build(); CreateIndexResponse createIndexResponse = client.indices().create( - new CreateIndexRequest("index", settings), RequestOptions.DEFAULT); + new CreateIndexRequest("index").settings(settings), RequestOptions.DEFAULT); assertTrue(createIndexResponse.isAcknowledged()); } @@ -1182,7 +1171,7 @@ public void testGetSettingsWithDefaults() throws Exception { { Settings settings = Settings.builder().put("number_of_shards", 3).build(); CreateIndexResponse createIndexResponse = client.indices().create( - new CreateIndexRequest("index", settings), RequestOptions.DEFAULT); + new CreateIndexRequest("index").settings(settings), RequestOptions.DEFAULT); assertTrue(createIndexResponse.isAcknowledged()); } @@ -1233,9 +1222,11 @@ public void testGetIndex() throws Exception { { Settings settings = Settings.builder().put("number_of_shards", 3).build(); String mappings = "{\"properties\":{\"field-1\":{\"type\":\"integer\"}}}"; + CreateIndexRequest createIndexRequest = new CreateIndexRequest("index") + .settings(settings) + .mapping(mappings, XContentType.JSON); CreateIndexResponse createIndexResponse = client.indices().create( - new CreateIndexRequest("index", settings).mapping("_doc", mappings, XContentType.JSON), - RequestOptions.DEFAULT); + createIndexRequest, RequestOptions.DEFAULT); assertTrue(createIndexResponse.isAcknowledged()); } diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/MlClientDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/MlClientDocumentationIT.java index eb74421c7a1c6..68881206b487f 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/MlClientDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/MlClientDocumentationIT.java @@ -20,7 +20,6 @@ import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.LatchedActionListener; -import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.get.GetRequest; import org.elasticsearch.action.get.GetResponse; @@ -33,6 +32,7 @@ import org.elasticsearch.client.MlTestStateCleaner; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestHighLevelClient; +import org.elasticsearch.client.indices.CreateIndexRequest; import org.elasticsearch.client.ml.CloseJobRequest; import org.elasticsearch.client.ml.CloseJobResponse; import org.elasticsearch.client.ml.DeleteCalendarEventRequest; @@ -139,6 +139,7 @@ import org.elasticsearch.client.ml.job.util.PageParams; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.unit.TimeValue; +import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.aggregations.AggregatorFactories; @@ -869,7 +870,16 @@ public void testPreviewDatafeed() throws Exception { String datafeedId = job.getId() + "-feed"; String indexName = "preview_data_2"; CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName); - createIndexRequest.mapping("_doc", "timestamp", "type=date", "total", "type=long"); + createIndexRequest.mapping(XContentFactory.jsonBuilder().startObject() + .startObject("properties") + .startObject("timestamp") + .field("type", "date") + .endObject() + .startObject("total") + .field("type", "long") + .endObject() + .endObject() + .endObject()); highLevelClient().indices().create(createIndexRequest, RequestOptions.DEFAULT); DatafeedConfig datafeed = DatafeedConfig.builder(datafeedId, job.getId()) .setIndices(indexName) @@ -928,7 +938,16 @@ public void testStartDatafeed() throws Exception { String datafeedId = job.getId() + "-feed"; String indexName = "start_data_2"; CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName); - createIndexRequest.mapping("_doc", "timestamp", "type=date", "total", "type=long"); + createIndexRequest.mapping(XContentFactory.jsonBuilder().startObject() + .startObject("properties") + .startObject("timestamp") + .field("type", "date") + .endObject() + .startObject("total") + .field("type", "long") + .endObject() + .endObject() + .endObject()); highLevelClient().indices().create(createIndexRequest, RequestOptions.DEFAULT); DatafeedConfig datafeed = DatafeedConfig.builder(datafeedId, job.getId()) .setIndices(indexName) @@ -1048,7 +1067,16 @@ public void testGetDatafeedStats() throws Exception { String datafeedId1 = job.getId() + "-feed"; String indexName = "datafeed_stats_data_2"; CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName); - createIndexRequest.mapping("_doc", "timestamp", "type=date", "total", "type=long"); + createIndexRequest.mapping(XContentFactory.jsonBuilder().startObject() + .startObject("properties") + .startObject("timestamp") + .field("type", "date") + .endObject() + .startObject("total") + .field("type", "long") + .endObject() + .endObject() + .endObject()); highLevelClient().indices().create(createIndexRequest, RequestOptions.DEFAULT); DatafeedConfig datafeed = DatafeedConfig.builder(datafeedId1, job.getId()) .setIndices(indexName) diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SearchDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SearchDocumentationIT.java index 3a49a13479e87..ff5deb5cbdfcc 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SearchDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SearchDocumentationIT.java @@ -23,8 +23,6 @@ import org.apache.lucene.search.TotalHits; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.LatchedActionListener; -import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; -import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkResponse; import org.elasticsearch.action.explain.ExplainRequest; @@ -52,11 +50,14 @@ import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.client.core.CountRequest; import org.elasticsearch.client.core.CountResponse; +import org.elasticsearch.client.indices.CreateIndexRequest; +import org.elasticsearch.client.indices.CreateIndexResponse; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.document.DocumentField; import org.elasticsearch.common.text.Text; import org.elasticsearch.common.unit.Fuzziness; import org.elasticsearch.common.unit.TimeValue; +import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.index.get.GetResult; import org.elasticsearch.index.query.MatchQueryBuilder; @@ -1249,12 +1250,26 @@ public void onFailure(Exception e) { private void indexSearchTestData() throws IOException { CreateIndexRequest authorsRequest = new CreateIndexRequest("authors") - .mapping("_doc", "user", "type=keyword,doc_values=false"); + .mapping(XContentFactory.jsonBuilder().startObject() + .startObject("properties") + .startObject("user") + .field("type", "keyword") + .field("doc_values", "false") + .endObject() + .endObject() + .endObject()); CreateIndexResponse authorsResponse = highLevelClient().indices().create(authorsRequest, RequestOptions.DEFAULT); assertTrue(authorsResponse.isAcknowledged()); CreateIndexRequest reviewersRequest = new CreateIndexRequest("contributors") - .mapping("_doc", "user", "type=keyword,store=true"); + .mapping(XContentFactory.jsonBuilder().startObject() + .startObject("properties") + .startObject("user") + .field("type", "keyword") + .field("store", "true") + .endObject() + .endObject() + .endObject()); CreateIndexResponse reviewersResponse = highLevelClient().indices().create(reviewersRequest, RequestOptions.DEFAULT); assertTrue(reviewersResponse.isAcknowledged()); @@ -1368,7 +1383,14 @@ public void onFailure(Exception e) { private static void indexCountTestData() throws IOException { CreateIndexRequest authorsRequest = new CreateIndexRequest("author") - .mapping("_doc", "user", "type=keyword,doc_values=false"); + .mapping(XContentFactory.jsonBuilder().startObject() + .startObject("properties") + .startObject("user") + .field("type", "keyword") + .field("doc_values", "false") + .endObject() + .endObject() + .endObject()); CreateIndexResponse authorsResponse = highLevelClient().indices().create(authorsRequest, RequestOptions.DEFAULT); assertTrue(authorsResponse.isAcknowledged()); diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SnapshotClientDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SnapshotClientDocumentationIT.java index 22ef30c92b78c..d80c24be6618a 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SnapshotClientDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SnapshotClientDocumentationIT.java @@ -38,7 +38,6 @@ import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotStatus; import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusRequest; import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusResponse; -import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.client.ESRestHighLevelClientTestCase; @@ -46,6 +45,7 @@ import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.Response; import org.elasticsearch.client.RestHighLevelClient; +import org.elasticsearch.client.indices.CreateIndexRequest; import org.elasticsearch.cluster.SnapshotsInProgress; import org.elasticsearch.cluster.metadata.RepositoryMetaData; import org.elasticsearch.common.settings.Settings; diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/CreateIndexRequestTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/CreateIndexRequestTests.java new file mode 100644 index 0000000000000..374f024401155 --- /dev/null +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/CreateIndexRequestTests.java @@ -0,0 +1,93 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.client.indices; + +import org.elasticsearch.action.admin.indices.alias.Alias; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.test.AbstractXContentTestCase; + +import java.io.IOException; +import java.util.Set; +import java.util.function.Predicate; + +import static org.elasticsearch.client.indices.CreateIndexRequest.ALIASES; +import static org.elasticsearch.client.indices.CreateIndexRequest.MAPPINGS; +import static org.elasticsearch.client.indices.CreateIndexRequest.SETTINGS; + +public class CreateIndexRequestTests extends AbstractXContentTestCase { + + @Override + protected CreateIndexRequest createTestInstance() { + return RandomCreateIndexGenerator.randomCreateIndexRequest(); + } + + @Override + protected CreateIndexRequest doParseInstance(XContentParser parser) throws IOException { + return new CreateIndexRequest("index").source(parser.map()); + } + + @Override + protected void assertEqualInstances(CreateIndexRequest expected, CreateIndexRequest actual) { + assertEquals(expected.settings(), actual.settings()); + assertAliasesEqual(expected.aliases(), actual.aliases()); + assertMappingsEqual(expected, actual); + } + + private void assertMappingsEqual(CreateIndexRequest expected, CreateIndexRequest actual) { + if (expected.mappings() == null) { + assertNull(actual.mappings()); + } else { + assertNotNull(actual.mappings()); + try (XContentParser expectedJson = createParser(expected.mappingsXContentType().xContent(), expected.mappings()); + XContentParser actualJson = createParser(actual.mappingsXContentType().xContent(), actual.mappings())) { + assertEquals(expectedJson.map(), actualJson.map()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + private void assertAliasesEqual(Set expected, Set actual) { + assertEquals(expected, actual); + + for (Alias expectedAlias : expected) { + for (Alias actualAlias : actual) { + if (expectedAlias.equals(actualAlias)) { + // As Alias#equals only looks at name, we check the equality of the other Alias parameters here. + assertEquals(expectedAlias.filter(), actualAlias.filter()); + assertEquals(expectedAlias.indexRouting(), actualAlias.indexRouting()); + assertEquals(expectedAlias.searchRouting(), actualAlias.searchRouting()); + } + } + } + } + + @Override + protected Predicate getRandomFieldsExcludeFilter() { + return field -> field.startsWith(MAPPINGS.getPreferredName()) + || field.startsWith(SETTINGS.getPreferredName()) + || field.startsWith(ALIASES.getPreferredName()); + } + + @Override + protected boolean supportsUnknownFields() { + return true; + } +} diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/PutMappingRequestTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/PutMappingRequestTests.java index 50224aa1b9ad7..e4fd0708b540c 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/PutMappingRequestTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/PutMappingRequestTests.java @@ -21,7 +21,6 @@ import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.index.RandomCreateIndexGenerator; import org.elasticsearch.test.AbstractXContentTestCase; import java.io.IOException; diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/RandomCreateIndexGenerator.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/RandomCreateIndexGenerator.java new file mode 100644 index 0000000000000..179b7e728b620 --- /dev/null +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/RandomCreateIndexGenerator.java @@ -0,0 +1,61 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.client.indices; + +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentFactory; + +import java.io.IOException; + +public class RandomCreateIndexGenerator { + + /** + * Returns a random {@link CreateIndexRequest}. + * + * Randomizes the index name, the aliases, mappings and settings associated with the + * index. When present, the mappings make no mention of types. + */ + public static CreateIndexRequest randomCreateIndexRequest() { + try { + // Create a random server request, and copy its contents into the HLRC request. + // Because client requests only accept typeless mappings, we must swap out the + // mapping definition for one that does not contain types. + org.elasticsearch.action.admin.indices.create.CreateIndexRequest serverRequest = + org.elasticsearch.index.RandomCreateIndexGenerator.randomCreateIndexRequest(); + return new CreateIndexRequest(serverRequest.index()) + .settings(serverRequest.settings()) + .aliases(serverRequest.aliases()) + .mapping(randomMapping()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * Creates a random mapping, with no mention of types. + */ + public static XContentBuilder randomMapping() throws IOException { + XContentBuilder builder = XContentFactory.jsonBuilder(); + builder.startObject(); + org.elasticsearch.index.RandomCreateIndexGenerator.randomMappingFields(builder, true); + builder.endObject(); + return builder; + } +} diff --git a/docs/java-rest/high-level/indices/create_index.asciidoc b/docs/java-rest/high-level/indices/create_index.asciidoc index 997b860b2786f..e6352d481ef86 100644 --- a/docs/java-rest/high-level/indices/create_index.asciidoc +++ b/docs/java-rest/high-level/indices/create_index.asciidoc @@ -55,13 +55,6 @@ include-tagged::{doc-tests-file}[{api}-mappings-xcontent] <1> Mapping source provided as an `XContentBuilder` object, the Elasticsearch built-in helpers to generate JSON content -["source","java",subs="attributes,callouts,macros"] --------------------------------------------------- -include-tagged::{doc-tests-file}[{api}-mappings-shortcut] --------------------------------------------------- -<1> Mapping source provided as `Object` key-pairs, which gets converted to -JSON format - ==== Index aliases Aliases can be set at index creation time diff --git a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestCreateIndexAction.java b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestCreateIndexAction.java index ed2724b95bb47..61e8af47a43d5 100644 --- a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestCreateIndexAction.java +++ b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestCreateIndexAction.java @@ -19,9 +19,11 @@ package org.elasticsearch.rest.action.admin.indices; +import org.apache.logging.log4j.LogManager; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.support.ActiveShardCount; import org.elasticsearch.client.node.NodeClient; +import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.LoggingDeprecationHandler; import org.elasticsearch.common.xcontent.XContentHelper; @@ -37,6 +39,11 @@ import java.util.Map; public class RestCreateIndexAction extends BaseRestHandler { + private static final DeprecationLogger deprecationLogger = new DeprecationLogger( + LogManager.getLogger(RestPutMappingAction.class)); + public static final String TYPES_DEPRECATION_MESSAGE = "[types removal] Using include_type_name in create " + + "index requests is deprecated. The parameter will be removed in the next major version."; + public RestCreateIndexAction(Settings settings, RestController controller) { super(settings); controller.registerHandler(RestRequest.Method.PUT, "/{index}", this); @@ -51,6 +58,11 @@ public String getName() { public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException { final boolean includeTypeName = request.paramAsBoolean(INCLUDE_TYPE_NAME_PARAMETER, DEFAULT_INCLUDE_TYPE_NAME_POLICY); + + if (request.hasParam(INCLUDE_TYPE_NAME_PARAMETER)) { + deprecationLogger.deprecatedAndMaybeLog("create_index_with_types", TYPES_DEPRECATION_MESSAGE); + } + CreateIndexRequest createIndexRequest = new CreateIndexRequest(request.param("index")); if (request.hasContent()) { Map sourceAsMap = XContentHelper.convertToMap(request.content(), false, request.getXContentType()).v2(); diff --git a/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequestTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequestTests.java index 593cdc60e8a23..53e188e36c9a8 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequestTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequestTests.java @@ -134,7 +134,7 @@ private static PutMappingRequest createTestItem() throws IOException { String type = randomAlphaOfLength(5); request.type(type); - request.source(RandomCreateIndexGenerator.randomMapping()); + request.source(RandomCreateIndexGenerator.randomMapping(type)); return request; } diff --git a/server/src/test/java/org/elasticsearch/rest/action/admin/indices/RestCreateIndexActionTests.java b/server/src/test/java/org/elasticsearch/rest/action/admin/indices/RestCreateIndexActionTests.java new file mode 100644 index 0000000000000..1ec0a0f949965 --- /dev/null +++ b/server/src/test/java/org/elasticsearch/rest/action/admin/indices/RestCreateIndexActionTests.java @@ -0,0 +1,62 @@ +/* + * 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.rest.action.admin.indices; + +import org.elasticsearch.client.node.NodeClient; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.test.rest.FakeRestRequest; +import org.elasticsearch.test.rest.RestActionTestCase; +import org.junit.Before; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import static org.elasticsearch.rest.BaseRestHandler.INCLUDE_TYPE_NAME_PARAMETER; +import static org.mockito.Mockito.mock; + +public class RestCreateIndexActionTests extends RestActionTestCase { + private RestCreateIndexAction action; + + @Before + public void setupAction() { + action = new RestCreateIndexAction(Settings.EMPTY, controller()); + } + + public void testIncludeTypeName() throws IOException { + Map params = new HashMap<>(); + params.put(INCLUDE_TYPE_NAME_PARAMETER, randomFrom("true", "false")); + RestRequest deprecatedRequest = new FakeRestRequest.Builder(xContentRegistry()) + .withMethod(RestRequest.Method.PUT) + .withPath("/some_index") + .withParams(params) + .build(); + + action.prepareRequest(deprecatedRequest, mock(NodeClient.class)); + assertWarnings(RestCreateIndexAction.TYPES_DEPRECATION_MESSAGE); + + RestRequest validRequest = new FakeRestRequest.Builder(xContentRegistry()) + .withMethod(RestRequest.Method.PUT) + .withPath("/some_index") + .build(); + action.prepareRequest(validRequest, mock(NodeClient.class)); + } +} diff --git a/test/framework/src/main/java/org/elasticsearch/index/RandomCreateIndexGenerator.java b/test/framework/src/main/java/org/elasticsearch/index/RandomCreateIndexGenerator.java index e4836150c6e86..345ef1f58bcac 100644 --- a/test/framework/src/main/java/org/elasticsearch/index/RandomCreateIndexGenerator.java +++ b/test/framework/src/main/java/org/elasticsearch/index/RandomCreateIndexGenerator.java @@ -40,8 +40,10 @@ public final class RandomCreateIndexGenerator { private RandomCreateIndexGenerator() {} /** - * Returns a random {@link CreateIndexRequest}. Randomizes the index name, the aliases, - * mappings and settings associated with the index. + * Returns a random {@link CreateIndexRequest}. + * + * Randomizes the index name, the aliases, mappings and settings associated with the + * index. If present, the mapping definition will be nested under a type name. */ public static CreateIndexRequest randomCreateIndexRequest() throws IOException { String index = randomAlphaOfLength(5); @@ -78,20 +80,6 @@ public static Settings randomIndexSettings() { return builder.build(); } - - /** - * Creates a random mapping, with no mention of types. - */ - public static XContentBuilder randomMapping() throws IOException { - XContentBuilder builder = XContentFactory.contentBuilder(randomFrom(XContentType.values())); - builder.startObject(); - - randomMappingFields(builder, true); - - builder.endObject(); - return builder; - } - /** * Creates a random mapping, with the mapping definition nested * under the given type name. diff --git a/test/framework/src/main/java/org/elasticsearch/test/AbstractXContentTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/AbstractXContentTestCase.java index 9507c5e12f8c2..136f51bed3c8c 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/AbstractXContentTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/AbstractXContentTestCase.java @@ -19,8 +19,8 @@ package org.elasticsearch.test; -import org.elasticsearch.common.CheckedBiFunction; import org.elasticsearch.common.CheckedBiConsumer; +import org.elasticsearch.common.CheckedBiFunction; import org.elasticsearch.common.CheckedFunction; import org.elasticsearch.common.Strings; import org.elasticsearch.common.bytes.BytesReference;