diff --git a/src/main/asciidoc/reference/elasticsearch-migration-guide-5.0-5.1.adoc b/src/main/asciidoc/reference/elasticsearch-migration-guide-5.0-5.1.adoc index 58482570e..1acac05f4 100644 --- a/src/main/asciidoc/reference/elasticsearch-migration-guide-5.0-5.1.adoc +++ b/src/main/asciidoc/reference/elasticsearch-migration-guide-5.0-5.1.adoc @@ -14,3 +14,13 @@ But besides the values defined by the enum, it is possible to have similarities Therefore, the annotation property was changed from the type of the enum to a simple `String`. The previous enum values like `Similarity.Default` do still exist as String constants, so existing code will compile unmodified. Adaptions are necessary when this enum was used at other places than as a property of the `@Field` annotation. + +[[elasticsearch-migration-guide-5.0-5.1.deprecations]] +== Deprecations + +=== template functions + +The functions in the `IndexOperations` and `ReactiverIndexOperations` to manage index templates that were introduced in Spring Data Elasticsearch 4.1 +have been deprecated. They were using the old Elasticsearch API that was deprecated in Elasticsearch version 7.8. + +Please use the new functions that are based on the compsable index template API instead. diff --git a/src/main/java/org/springframework/data/elasticsearch/client/elc/ElasticsearchTemplate.java b/src/main/java/org/springframework/data/elasticsearch/client/elc/ElasticsearchTemplate.java index f00641347..b6b57f96a 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/elc/ElasticsearchTemplate.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/elc/ElasticsearchTemplate.java @@ -115,16 +115,20 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate { // region child templates @Override public IndexOperations indexOps(Class clazz) { - return new IndicesTemplate(client.indices(), elasticsearchConverter, clazz); + return new IndicesTemplate(client.indices(), getClusterTemplate(), elasticsearchConverter, clazz); } @Override public IndexOperations indexOps(IndexCoordinates index) { - return new IndicesTemplate(client.indices(), elasticsearchConverter, index); + return new IndicesTemplate(client.indices(), getClusterTemplate(), elasticsearchConverter, index); } @Override public ClusterOperations cluster() { + return getClusterTemplate(); + } + + private ClusterTemplate getClusterTemplate() { return new ClusterTemplate(client.cluster(), elasticsearchConverter); } // endregion diff --git a/src/main/java/org/springframework/data/elasticsearch/client/elc/IndicesTemplate.java b/src/main/java/org/springframework/data/elasticsearch/client/elc/IndicesTemplate.java index 57c8163bc..208422ade 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/elc/IndicesTemplate.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/elc/IndicesTemplate.java @@ -37,15 +37,15 @@ import org.springframework.data.elasticsearch.core.IndexOperations; import org.springframework.data.elasticsearch.core.ResourceUtil; import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter; import org.springframework.data.elasticsearch.core.document.Document; -import org.springframework.data.elasticsearch.core.index.AliasActions; -import org.springframework.data.elasticsearch.core.index.AliasData; +import org.springframework.data.elasticsearch.core.index.*; +import org.springframework.data.elasticsearch.core.index.DeleteIndexTemplateRequest; import org.springframework.data.elasticsearch.core.index.DeleteTemplateRequest; +import org.springframework.data.elasticsearch.core.index.ExistsIndexTemplateRequest; import org.springframework.data.elasticsearch.core.index.ExistsTemplateRequest; +import org.springframework.data.elasticsearch.core.index.GetIndexTemplateRequest; import org.springframework.data.elasticsearch.core.index.GetTemplateRequest; -import org.springframework.data.elasticsearch.core.index.MappingBuilder; +import org.springframework.data.elasticsearch.core.index.PutIndexTemplateRequest; import org.springframework.data.elasticsearch.core.index.PutTemplateRequest; -import org.springframework.data.elasticsearch.core.index.Settings; -import org.springframework.data.elasticsearch.core.index.TemplateData; import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity; import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; import org.springframework.lang.Nullable; @@ -62,30 +62,37 @@ public class IndicesTemplate extends ChildTemplate boundClass; @Nullable protected final IndexCoordinates boundIndex; - public IndicesTemplate(ElasticsearchIndicesClient client, ElasticsearchConverter elasticsearchConverter, - Class boundClass) { + public IndicesTemplate(ElasticsearchIndicesClient client, ClusterTemplate clusterTemplate, + ElasticsearchConverter elasticsearchConverter, Class boundClass) { super(client, elasticsearchConverter); + Assert.notNull(clusterTemplate, "cluster must not be null"); Assert.notNull(elasticsearchConverter, "elasticsearchConverter must not be null"); Assert.notNull(boundClass, "boundClass may not be null"); + this.clusterTemplate = clusterTemplate; this.elasticsearchConverter = elasticsearchConverter; this.boundClass = boundClass; this.boundIndex = null; } - public IndicesTemplate(ElasticsearchIndicesClient client, ElasticsearchConverter elasticsearchConverter, - IndexCoordinates boundIndex) { + public IndicesTemplate(ElasticsearchIndicesClient client, ClusterTemplate clusterTemplate, + ElasticsearchConverter elasticsearchConverter, IndexCoordinates boundIndex) { super(client, elasticsearchConverter); + Assert.notNull(clusterTemplate, "cluster must not be null"); Assert.notNull(elasticsearchConverter, "elasticsearchConverter must not be null"); Assert.notNull(boundIndex, "boundIndex must not be null"); + this.clusterTemplate = clusterTemplate; this.elasticsearchConverter = elasticsearchConverter; this.boundClass = null; this.boundIndex = boundIndex; @@ -338,6 +345,87 @@ public class IndicesTemplate extends ChildTemplate client.deleteTemplate(deleteTemplateRequestES)).acknowledged(); } + @Override + public boolean putIndexTemplate(PutIndexTemplateRequest putIndexTemplateRequest) { + + co.elastic.clients.elasticsearch.indices.PutIndexTemplateRequest putIndexTemplateRequestES = requestConverter + .indicesPutIndexTemplateRequest(putIndexTemplateRequest); + + return execute(client -> client.putIndexTemplate(putIndexTemplateRequestES)).acknowledged(); + } + + @Override + public boolean existsIndexTemplate(ExistsIndexTemplateRequest existsIndexTemplateRequest) { + + Assert.notNull(existsIndexTemplateRequest, "existsIndexTemplateRequest must not be null"); + + co.elastic.clients.elasticsearch.indices.ExistsIndexTemplateRequest existsTemplateRequestES = requestConverter + .indicesExistsIndexTemplateRequest(existsIndexTemplateRequest); + return execute(client -> client.existsIndexTemplate(existsTemplateRequestES)).value(); + } + + @Override + public List getIndexTemplate(GetIndexTemplateRequest getIndexTemplateRequest) { + + Assert.notNull(getIndexTemplateRequest, "getIndexTemplateRequest must not be null"); + + co.elastic.clients.elasticsearch.indices.GetIndexTemplateRequest getIndexTemplateRequestES = requestConverter + .indicesGetIndexTemplateRequest(getIndexTemplateRequest); + var getIndexTemplateResponse = execute(client -> client.getIndexTemplate(getIndexTemplateRequestES)); + return responseConverter.getIndexTemplates(getIndexTemplateResponse); + } + + @Override + public boolean deleteIndexTemplate(DeleteIndexTemplateRequest deleteIndexTemplateRequest) { + + Assert.notNull(deleteIndexTemplateRequest, "deleteIndexTemplateRequest must not be null"); + + co.elastic.clients.elasticsearch.indices.DeleteIndexTemplateRequest deleteIndexTemplateRequestES = requestConverter + .indicesDeleteIndexTemplateRequest(deleteIndexTemplateRequest); + return execute(client -> client.deleteIndexTemplate(deleteIndexTemplateRequestES)).acknowledged(); + } + + @Override + public boolean putComponentTemplate(PutComponentTemplateRequest putComponentTemplateRequest) { + + Assert.notNull(putComponentTemplateRequest, "putComponentTemplateRequest must not be null"); + + co.elastic.clients.elasticsearch.cluster.PutComponentTemplateRequest putComponentTemplateRequestES = requestConverter + .clusterPutComponentTemplateRequest(putComponentTemplateRequest); + // the new Elasticsearch client has this call in the cluster index + return clusterTemplate.execute(client -> client.putComponentTemplate(putComponentTemplateRequestES)).acknowledged(); + } + + @Override + public boolean existsComponentTemplate(ExistsComponentTemplateRequest existsComponentTemplateRequest) { + + Assert.notNull(existsComponentTemplateRequest, "existsComponentTemplateRequest must not be null"); + + co.elastic.clients.elasticsearch.cluster.ExistsComponentTemplateRequest existsComponentTemplateRequestES = requestConverter + .clusterExistsComponentTemplateRequest(existsComponentTemplateRequest); + return clusterTemplate.execute(client -> client.existsComponentTemplate(existsComponentTemplateRequestES)).value(); + } + + @Override + public List getComponentTemplate(GetComponentTemplateRequest getComponentTemplateRequest) { + + co.elastic.clients.elasticsearch.cluster.GetComponentTemplateRequest getComponentTemplateRequestES = requestConverter + .clusterGetComponentTemplateRequest(getComponentTemplateRequest); + var response = clusterTemplate.execute(client -> client.getComponentTemplate(getComponentTemplateRequestES)); + return responseConverter.clusterGetComponentTemplates(response); + } + + @Override + public boolean deleteComponentTemplate(DeleteComponentTemplateRequest deleteComponentTemplateRequest) { + + Assert.notNull(deleteComponentTemplateRequest, "deleteComponentTemplateRequest must not be null"); + + co.elastic.clients.elasticsearch.cluster.DeleteComponentTemplateRequest deleteComponentTemplateRequestES = requestConverter + .clusterDeleteComponentTemplateRequest(deleteComponentTemplateRequest); + return clusterTemplate.execute(client -> client.deleteComponentTemplate(deleteComponentTemplateRequestES)) + .acknowledged(); + } + @Override public List getInformation(IndexCoordinates indexCoordinates) { diff --git a/src/main/java/org/springframework/data/elasticsearch/client/elc/ReactiveClusterTemplate.java b/src/main/java/org/springframework/data/elasticsearch/client/elc/ReactiveClusterTemplate.java index bd38ab1eb..697aa0909 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/elc/ReactiveClusterTemplate.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/elc/ReactiveClusterTemplate.java @@ -20,8 +20,8 @@ import co.elastic.clients.elasticsearch.cluster.HealthResponse; import co.elastic.clients.transport.ElasticsearchTransport; import reactor.core.publisher.Mono; -import org.springframework.data.elasticsearch.client.erhlc.ReactiveClusterOperations; import org.springframework.data.elasticsearch.core.cluster.ClusterHealth; +import org.springframework.data.elasticsearch.core.cluster.ReactiveClusterOperations; import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter; /** diff --git a/src/main/java/org/springframework/data/elasticsearch/client/elc/ReactiveElasticsearchClusterClient.java b/src/main/java/org/springframework/data/elasticsearch/client/elc/ReactiveElasticsearchClusterClient.java index b888151ca..0e5f4b7d2 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/elc/ReactiveElasticsearchClusterClient.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/elc/ReactiveElasticsearchClusterClient.java @@ -16,10 +16,10 @@ package org.springframework.data.elasticsearch.client.elc; import co.elastic.clients.ApiClient; -import co.elastic.clients.elasticsearch.cluster.HealthRequest; -import co.elastic.clients.elasticsearch.cluster.HealthResponse; +import co.elastic.clients.elasticsearch.cluster.*; import co.elastic.clients.transport.ElasticsearchTransport; import co.elastic.clients.transport.TransportOptions; +import co.elastic.clients.transport.endpoints.BooleanResponse; import co.elastic.clients.util.ObjectBuilder; import reactor.core.publisher.Mono; @@ -53,4 +53,47 @@ public class ReactiveElasticsearchClusterClient public Mono health(Function> fn) { return health(fn.apply(new HealthRequest.Builder()).build()); } + + public Mono putComponentTemplate( + PutComponentTemplateRequest putComponentTemplateRequest) { + return Mono.fromFuture(transport.performRequestAsync(putComponentTemplateRequest, + PutComponentTemplateRequest._ENDPOINT, transportOptions)); + } + + public Mono putComponentTemplate( + Function> fn) { + return putComponentTemplate(fn.apply(new PutComponentTemplateRequest.Builder()).build()); + } + + public Mono getComponentTemplate( + GetComponentTemplateRequest getComponentTemplateRequest) { + return Mono.fromFuture(transport.performRequestAsync(getComponentTemplateRequest, + GetComponentTemplateRequest._ENDPOINT, transportOptions)); + } + + public Mono getComponentTemplate( + Function> fn) { + return getComponentTemplate(fn.apply(new GetComponentTemplateRequest.Builder()).build()); + } + + public Mono existsComponentTemplate(ExistsComponentTemplateRequest existsComponentTemplateRequest) { + return Mono.fromFuture(transport.performRequestAsync(existsComponentTemplateRequest, + ExistsComponentTemplateRequest._ENDPOINT, transportOptions)); + } + + public Mono existsComponentTemplate( + Function> fn) { + return existsComponentTemplate(fn.apply(new ExistsComponentTemplateRequest.Builder()).build()); + } + + public Mono deleteComponentTemplate( + DeleteComponentTemplateRequest deleteComponentTemplateRequest) { + return Mono.fromFuture(transport.performRequestAsync(deleteComponentTemplateRequest, + DeleteComponentTemplateRequest._ENDPOINT, transportOptions)); + } + + public Mono deleteComponentTemplate( + Function> fn) { + return deleteComponentTemplate(fn.apply(new DeleteComponentTemplateRequest.Builder()).build()); + } } diff --git a/src/main/java/org/springframework/data/elasticsearch/client/elc/ReactiveElasticsearchTemplate.java b/src/main/java/org/springframework/data/elasticsearch/client/elc/ReactiveElasticsearchTemplate.java index 0f2046a3c..1fdb0b116 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/elc/ReactiveElasticsearchTemplate.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/elc/ReactiveElasticsearchTemplate.java @@ -15,8 +15,8 @@ */ package org.springframework.data.elasticsearch.client.elc; -import static co.elastic.clients.util.ApiTypeHelper.*; -import static org.springframework.data.elasticsearch.client.elc.TypeUtils.*; +import static co.elastic.clients.util.ApiTypeHelper.DANGEROUS_disableRequiredPropertiesCheck; +import static org.springframework.data.elasticsearch.client.elc.TypeUtils.result; import co.elastic.clients.elasticsearch._types.Result; import co.elastic.clients.elasticsearch.core.*; @@ -46,24 +46,14 @@ import org.springframework.data.elasticsearch.BulkFailureException; import org.springframework.data.elasticsearch.NoSuchIndexException; import org.springframework.data.elasticsearch.UncategorizedElasticsearchException; import org.springframework.data.elasticsearch.client.UnsupportedBackendOperation; -import org.springframework.data.elasticsearch.client.erhlc.ReactiveClusterOperations; -import org.springframework.data.elasticsearch.core.AbstractReactiveElasticsearchTemplate; -import org.springframework.data.elasticsearch.core.AggregationContainer; -import org.springframework.data.elasticsearch.core.IndexedObjectInformation; -import org.springframework.data.elasticsearch.core.MultiGetItem; -import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations; -import org.springframework.data.elasticsearch.core.ReactiveIndexOperations; +import org.springframework.data.elasticsearch.core.*; +import org.springframework.data.elasticsearch.core.cluster.ReactiveClusterOperations; import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter; import org.springframework.data.elasticsearch.core.document.Document; import org.springframework.data.elasticsearch.core.document.SearchDocument; import org.springframework.data.elasticsearch.core.document.SearchDocumentResponse; import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; -import org.springframework.data.elasticsearch.core.query.BaseQuery; -import org.springframework.data.elasticsearch.core.query.BulkOptions; -import org.springframework.data.elasticsearch.core.query.ByQueryResponse; -import org.springframework.data.elasticsearch.core.query.Query; -import org.springframework.data.elasticsearch.core.query.SearchTemplateQuery; -import org.springframework.data.elasticsearch.core.query.UpdateQuery; +import org.springframework.data.elasticsearch.core.query.*; import org.springframework.data.elasticsearch.core.query.UpdateResponse; import org.springframework.data.elasticsearch.core.reindex.ReindexRequest; import org.springframework.data.elasticsearch.core.reindex.ReindexResponse; @@ -616,16 +606,23 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch @Override public ReactiveIndexOperations indexOps(IndexCoordinates index) { - return new ReactiveIndicesTemplate(client.indices(), converter, index); + return new ReactiveIndicesTemplate(client.indices(), getReactiveClusterTemplate(), converter, index); } @Override public ReactiveIndexOperations indexOps(Class clazz) { - return new ReactiveIndicesTemplate(client.indices(), converter, clazz); + return new ReactiveIndicesTemplate(client.indices(), getReactiveClusterTemplate(), converter, clazz); } @Override public ReactiveClusterOperations cluster() { + return getReactiveClusterTemplate(); + } + + /** + * @since 5.1 + */ + private ReactiveClusterTemplate getReactiveClusterTemplate() { return new ReactiveClusterTemplate(client.cluster(), converter); } diff --git a/src/main/java/org/springframework/data/elasticsearch/client/elc/ReactiveIndicesTemplate.java b/src/main/java/org/springframework/data/elasticsearch/client/elc/ReactiveIndicesTemplate.java index b5b2f003c..d857945b9 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/elc/ReactiveIndicesTemplate.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/elc/ReactiveIndicesTemplate.java @@ -15,7 +15,7 @@ */ package org.springframework.data.elasticsearch.client.elc; -import static org.springframework.util.StringUtils.*; +import static org.springframework.util.StringUtils.hasText; import co.elastic.clients.elasticsearch._types.AcknowledgedResponseBase; import co.elastic.clients.elasticsearch.indices.*; @@ -37,15 +37,15 @@ import org.springframework.data.elasticsearch.core.ReactiveIndexOperations; import org.springframework.data.elasticsearch.core.ReactiveResourceUtil; import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter; import org.springframework.data.elasticsearch.core.document.Document; -import org.springframework.data.elasticsearch.core.index.AliasActions; -import org.springframework.data.elasticsearch.core.index.AliasData; +import org.springframework.data.elasticsearch.core.index.*; +import org.springframework.data.elasticsearch.core.index.DeleteIndexTemplateRequest; import org.springframework.data.elasticsearch.core.index.DeleteTemplateRequest; +import org.springframework.data.elasticsearch.core.index.ExistsIndexTemplateRequest; import org.springframework.data.elasticsearch.core.index.ExistsTemplateRequest; +import org.springframework.data.elasticsearch.core.index.GetIndexTemplateRequest; import org.springframework.data.elasticsearch.core.index.GetTemplateRequest; +import org.springframework.data.elasticsearch.core.index.PutIndexTemplateRequest; import org.springframework.data.elasticsearch.core.index.PutTemplateRequest; -import org.springframework.data.elasticsearch.core.index.ReactiveMappingBuilder; -import org.springframework.data.elasticsearch.core.index.Settings; -import org.springframework.data.elasticsearch.core.index.TemplateData; import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity; import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; import org.springframework.lang.Nullable; @@ -58,27 +58,35 @@ public class ReactiveIndicesTemplate extends ReactiveChildTemplate implements ReactiveIndexOperations { + // we need a cluster client as well because ES has put some methods from the indices API into the cluster client + // (component templates) + private final ReactiveClusterTemplate clusterTemplate; + @Nullable private final Class boundClass; private final IndexCoordinates boundIndexCoordinates; - public ReactiveIndicesTemplate(ReactiveElasticsearchIndicesClient client, + public ReactiveIndicesTemplate(ReactiveElasticsearchIndicesClient client, ReactiveClusterTemplate clusterTemplate, ElasticsearchConverter elasticsearchConverter, IndexCoordinates index) { super(client, elasticsearchConverter); Assert.notNull(index, "index must not be null"); + Assert.notNull(clusterTemplate, "clusterTemplate must not be null"); + this.clusterTemplate = clusterTemplate; this.boundClass = null; this.boundIndexCoordinates = index; } - public ReactiveIndicesTemplate(ReactiveElasticsearchIndicesClient client, + public ReactiveIndicesTemplate(ReactiveElasticsearchIndicesClient client, ReactiveClusterTemplate clusterTemplate, ElasticsearchConverter elasticsearchConverter, Class clazz) { super(client, elasticsearchConverter); Assert.notNull(clazz, "clazz must not be null"); + Assert.notNull(clusterTemplate, "clusterTemplate must not be null"); + this.clusterTemplate = clusterTemplate; this.boundClass = clazz; this.boundIndexCoordinates = getIndexCoordinatesFor(clazz); } @@ -271,6 +279,99 @@ public class ReactiveIndicesTemplate return putTemplateResponse.map(PutTemplateResponse::acknowledged); } + @Override + public Mono putComponentTemplate(PutComponentTemplateRequest putComponentTemplateRequest) { + + Assert.notNull(putComponentTemplateRequest, "putComponentTemplateRequest must not be null"); + + co.elastic.clients.elasticsearch.cluster.PutComponentTemplateRequest putComponentTemplateRequestES = requestConverter + .clusterPutComponentTemplateRequest(putComponentTemplateRequest); + // the new Elasticsearch client has this call in the cluster index + return Mono.from(clusterTemplate.execute(client -> client.putComponentTemplate(putComponentTemplateRequestES))) + .map(AcknowledgedResponseBase::acknowledged); + } + + @Override + public Flux getComponentTemplate(GetComponentTemplateRequest getComponentTemplateRequest) { + + Assert.notNull(getComponentTemplateRequest, "getComponentTemplateRequest must not be null"); + + co.elastic.clients.elasticsearch.cluster.GetComponentTemplateRequest getComponentTemplateRequestES = requestConverter + .clusterGetComponentTemplateRequest(getComponentTemplateRequest); + return Flux.from(clusterTemplate.execute(client -> client.getComponentTemplate(getComponentTemplateRequestES))) + .flatMapIterable(responseConverter::clusterGetComponentTemplates); + } + + @Override + public Mono existsComponentTemplate(ExistsComponentTemplateRequest existsComponentTemplateRequest) { + + Assert.notNull(existsComponentTemplateRequest, "existsComponentTemplateRequest must not be null"); + + co.elastic.clients.elasticsearch.cluster.ExistsComponentTemplateRequest existsComponentTemplateRequestES = requestConverter + .clusterExistsComponentTemplateRequest(existsComponentTemplateRequest); + + return Mono + .from(clusterTemplate.execute(client -> client.existsComponentTemplate(existsComponentTemplateRequestES))) + .map(BooleanResponse::value); + } + + @Override + public Mono deleteComponentTemplate(DeleteComponentTemplateRequest deleteComponentTemplateRequest) { + + Assert.notNull(deleteComponentTemplateRequest, "deleteComponentTemplateRequest must not be null"); + + co.elastic.clients.elasticsearch.cluster.DeleteComponentTemplateRequest deleteComponentTemplateRequestES = requestConverter + .clusterDeleteComponentTemplateRequest(deleteComponentTemplateRequest); + return Mono + .from(clusterTemplate.execute(client -> client.deleteComponentTemplate(deleteComponentTemplateRequestES))) + .map(AcknowledgedResponseBase::acknowledged); + } + + @Override + public Mono putIndexTemplate(PutIndexTemplateRequest putIndexTemplateRequest) { + + Assert.notNull(putIndexTemplateRequest, "putIndexTemplateRequest must not be null"); + + co.elastic.clients.elasticsearch.indices.PutIndexTemplateRequest putIndexTemplateRequestES = requestConverter + .indicesPutIndexTemplateRequest(putIndexTemplateRequest); + + return Mono.from(execute(client -> client.putIndexTemplate(putIndexTemplateRequestES))) + .map(PutIndexTemplateResponse::acknowledged); + } + + @Override + public Mono existsIndexTemplate(ExistsIndexTemplateRequest existsIndexTemplateRequest) { + + Assert.notNull(existsIndexTemplateRequest, "existsIndexTemplateRequest must not be null"); + + co.elastic.clients.elasticsearch.indices.ExistsIndexTemplateRequest existsIndexTemplateRequestES = requestConverter + .indicesExistsIndexTemplateRequest(existsIndexTemplateRequest); + return Mono.from(execute(client -> client.existsIndexTemplate(existsIndexTemplateRequestES))) + .map(BooleanResponse::value); + } + + @Override + public Flux getIndexTemplate(GetIndexTemplateRequest getIndexTemplateRequest) { + + Assert.notNull(getIndexTemplateRequest, "getIndexTemplateRequest must not be null"); + + co.elastic.clients.elasticsearch.indices.GetIndexTemplateRequest getIndexTemplateRequestES = requestConverter + .indicesGetIndexTemplateRequest(getIndexTemplateRequest); + return Mono.from(execute(client -> client.getIndexTemplate(getIndexTemplateRequestES))) + .flatMapIterable(responseConverter::getIndexTemplates); + } + + @Override + public Mono deleteIndexTemplate(DeleteIndexTemplateRequest deleteIndexTemplateRequest) { + + Assert.notNull(deleteIndexTemplateRequest, "deleteIndexTemplateRequest must not be null"); + + co.elastic.clients.elasticsearch.indices.DeleteIndexTemplateRequest deleteIndexTemplateRequestES = requestConverter + .indicesDeleteIndexTemplateRequest(deleteIndexTemplateRequest); + return Mono.from(execute(client -> client.deleteIndexTemplate(deleteIndexTemplateRequestES))) + .map(AcknowledgedResponseBase::acknowledged); + } + @Override public Mono getTemplate(GetTemplateRequest getTemplateRequest) { diff --git a/src/main/java/org/springframework/data/elasticsearch/client/elc/RequestConverter.java b/src/main/java/org/springframework/data/elasticsearch/client/elc/RequestConverter.java index 3910636aa..4778bd594 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/elc/RequestConverter.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/elc/RequestConverter.java @@ -19,10 +19,16 @@ import static org.springframework.data.elasticsearch.client.elc.TypeUtils.*; import static org.springframework.util.CollectionUtils.isEmpty; import co.elastic.clients.elasticsearch._types.*; -import co.elastic.clients.elasticsearch._types.mapping.*; +import co.elastic.clients.elasticsearch._types.mapping.FieldType; +import co.elastic.clients.elasticsearch._types.mapping.RuntimeField; +import co.elastic.clients.elasticsearch._types.mapping.RuntimeFieldType; import co.elastic.clients.elasticsearch._types.query_dsl.FieldAndFormat; import co.elastic.clients.elasticsearch._types.query_dsl.Like; -import co.elastic.clients.elasticsearch.cluster.HealthRequest; +import co.elastic.clients.elasticsearch.cluster.*; +import co.elastic.clients.elasticsearch.cluster.DeleteComponentTemplateRequest; +import co.elastic.clients.elasticsearch.cluster.ExistsComponentTemplateRequest; +import co.elastic.clients.elasticsearch.cluster.GetComponentTemplateRequest; +import co.elastic.clients.elasticsearch.cluster.PutComponentTemplateRequest; import co.elastic.clients.elasticsearch.core.*; import co.elastic.clients.elasticsearch.core.bulk.BulkOperation; import co.elastic.clients.elasticsearch.core.bulk.CreateOperation; @@ -34,16 +40,15 @@ import co.elastic.clients.elasticsearch.core.search.Highlight; import co.elastic.clients.elasticsearch.core.search.Rescore; import co.elastic.clients.elasticsearch.core.search.SourceConfig; import co.elastic.clients.elasticsearch.indices.*; +import co.elastic.clients.elasticsearch.indices.ExistsIndexTemplateRequest; import co.elastic.clients.elasticsearch.indices.ExistsRequest; import co.elastic.clients.elasticsearch.indices.update_aliases.Action; import co.elastic.clients.json.JsonData; import co.elastic.clients.json.JsonpDeserializer; import co.elastic.clients.json.JsonpMapper; -import jakarta.json.stream.JsonGenerator; import jakarta.json.stream.JsonParser; import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.StringReader; import java.nio.charset.StandardCharsets; import java.time.Duration; @@ -58,9 +63,12 @@ import org.springframework.data.elasticsearch.core.ScriptType; import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter; import org.springframework.data.elasticsearch.core.document.Document; import org.springframework.data.elasticsearch.core.index.*; +import org.springframework.data.elasticsearch.core.index.DeleteIndexTemplateRequest; import org.springframework.data.elasticsearch.core.index.DeleteTemplateRequest; import org.springframework.data.elasticsearch.core.index.ExistsTemplateRequest; +import org.springframework.data.elasticsearch.core.index.GetIndexTemplateRequest; import org.springframework.data.elasticsearch.core.index.GetTemplateRequest; +import org.springframework.data.elasticsearch.core.index.PutIndexTemplateRequest; import org.springframework.data.elasticsearch.core.index.PutTemplateRequest; import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity; import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty; @@ -102,9 +110,101 @@ class RequestConverter { } // region Cluster client - public HealthRequest clusterHealthRequest() { + public co.elastic.clients.elasticsearch.cluster.HealthRequest clusterHealthRequest() { return new HealthRequest.Builder().build(); } + + public co.elastic.clients.elasticsearch.cluster.PutComponentTemplateRequest clusterPutComponentTemplateRequest( + org.springframework.data.elasticsearch.core.index.PutComponentTemplateRequest putComponentTemplateRequest) { + + Assert.notNull(putComponentTemplateRequest, "putComponentTemplateRequest must not be null"); + + return PutComponentTemplateRequest.of(b -> b // + .name(putComponentTemplateRequest.name()) // + .create(putComponentTemplateRequest.create()) // + .version(putComponentTemplateRequest.version()) // + .masterTimeout(time(putComponentTemplateRequest.masterTimeout())) // + .template(isb -> { + var componentTemplateData = putComponentTemplateRequest.template(); + isb // + .mappings(typeMapping(componentTemplateData.mapping())) // + .settings(indexSettings(componentTemplateData.settings())); + // same code schema, but different Elasticsearch builder types + // noinspection DuplicatedCode + var aliasActions = componentTemplateData.aliasActions(); + if (aliasActions != null) { + aliasActions.getActions().forEach(aliasAction -> { + if (aliasAction instanceof AliasAction.Add add) { + var parameters = add.getParameters(); + // noinspection DuplicatedCode + String[] parametersAliases = parameters.getAliases(); + if (parametersAliases != null) { + for (String aliasName : parametersAliases) { + isb.aliases(aliasName, aliasBuilder -> buildAlias(parameters, aliasBuilder)); + } + } + } + }); + } + return isb; + })); + } + + private Alias.Builder buildAlias(AliasActionParameters parameters, Alias.Builder aliasBuilder) { + + // noinspection DuplicatedCode + if (parameters.getRouting() != null) { + aliasBuilder.routing(parameters.getRouting()); + } + + if (parameters.getIndexRouting() != null) { + aliasBuilder.indexRouting(parameters.getIndexRouting()); + } + + if (parameters.getSearchRouting() != null) { + aliasBuilder.searchRouting(parameters.getSearchRouting()); + } + + if (parameters.getHidden() != null) { + aliasBuilder.isHidden(parameters.getHidden()); + } + + if (parameters.getWriteIndex() != null) { + aliasBuilder.isWriteIndex(parameters.getWriteIndex()); + } + + Query filterQuery = parameters.getFilterQuery(); + + if (filterQuery != null) { + co.elastic.clients.elasticsearch._types.query_dsl.Query esQuery = getQuery(filterQuery, null); + + if (esQuery != null) { + aliasBuilder.filter(esQuery); + } + } + return aliasBuilder; + } + + public ExistsComponentTemplateRequest clusterExistsComponentTemplateRequest( + org.springframework.data.elasticsearch.core.index.ExistsComponentTemplateRequest existsComponentTemplateRequest) { + + Assert.notNull(existsComponentTemplateRequest, "existsComponentTemplateRequest must not be null"); + + return ExistsComponentTemplateRequest.of(b -> b.name(existsComponentTemplateRequest.templateName())); + } + + public GetComponentTemplateRequest clusterGetComponentTemplateRequest( + org.springframework.data.elasticsearch.core.index.GetComponentTemplateRequest getComponentTemplateRequest) { + + Assert.notNull(getComponentTemplateRequest, "getComponentTemplateRequest must not be null"); + + return GetComponentTemplateRequest.of(b -> b.name(getComponentTemplateRequest.templateName())); + } + + public DeleteComponentTemplateRequest clusterDeleteComponentTemplateRequest( + org.springframework.data.elasticsearch.core.index.DeleteComponentTemplateRequest deleteComponentTemplateRequest) { + return DeleteComponentTemplateRequest.of(b -> b.name(deleteComponentTemplateRequest.templateName())); + } // endregion // region Indices client @@ -121,20 +221,12 @@ class RequestConverter { Assert.notNull(indexCoordinates, "indexCoordinates must not be null"); Assert.notNull(settings, "settings must not be null"); - CreateIndexRequest.Builder createRequestBuilder = new CreateIndexRequest.Builder(); - - createRequestBuilder.index(indexCoordinates.getIndexName()); - // note: the new client does not support the index.storeType anymore - createRequestBuilder.settings(IndexSettings.of(b -> b // - .withJson(new StringReader(Document.from(settings).toJson())))); - - if (mapping != null) { - createRequestBuilder.mappings(TypeMapping.of(b -> b // - .withJson(new StringReader(mapping.toJson())))); - } - - return createRequestBuilder.build(); + return new CreateIndexRequest.Builder() // + .index(indexCoordinates.getIndexName()) // + .settings(indexSettings(settings)) // + .mappings(typeMapping(mapping)) // + .build(); } public RefreshRequest indicesRefreshRequest(IndexCoordinates indexCoordinates) { @@ -235,18 +327,7 @@ class RequestConverter { Assert.notNull(indexCoordinates, "indexCoordinates must not be null"); - return new GetMappingRequest.Builder().index(Arrays.asList(indexCoordinates.getIndexNames())).build(); - } - - private Property getProperty(Object value) { - // noinspection SpellCheckingInspection - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - JsonGenerator generator = jsonpMapper.jsonProvider().createGenerator(baos); - jsonpMapper.serialize(value, generator); - generator.close(); - // noinspection SpellCheckingInspection - ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); - return fromJson(bais, Property._DESERIALIZER); + return new GetMappingRequest.Builder().index(List.of(indexCoordinates.getIndexNames())).build(); } public GetIndicesSettingsRequest indicesGetSettingsRequest(IndexCoordinates indexCoordinates, @@ -303,7 +384,7 @@ class RequestConverter { } if (putTemplateRequest.getMappings() != null) { - builder.mappings(fromJson(putTemplateRequest.getMappings().toJson(), TypeMapping._DESERIALIZER)); + builder.mappings(typeMapping(putTemplateRequest.getMappings())); } if (putTemplateRequest.getVersion() != null) { @@ -314,43 +395,14 @@ class RequestConverter { if (aliasActions != null) { aliasActions.getActions().forEach(aliasAction -> { AliasActionParameters parameters = aliasAction.getParameters(); + // noinspection DuplicatedCode String[] parametersAliases = parameters.getAliases(); if (parametersAliases != null) { for (String aliasName : parametersAliases) { builder.aliases(aliasName, aliasBuilder -> { - // noinspection DuplicatedCode - if (parameters.getRouting() != null) { - aliasBuilder.routing(parameters.getRouting()); - } - - if (parameters.getIndexRouting() != null) { - aliasBuilder.indexRouting(parameters.getIndexRouting()); - } - - if (parameters.getSearchRouting() != null) { - aliasBuilder.searchRouting(parameters.getSearchRouting()); - } - - if (parameters.getHidden() != null) { - aliasBuilder.isHidden(parameters.getHidden()); - } - - if (parameters.getWriteIndex() != null) { - aliasBuilder.isWriteIndex(parameters.getWriteIndex()); - } - - Query filterQuery = parameters.getFilterQuery(); - - if (filterQuery != null) { - co.elastic.clients.elasticsearch._types.query_dsl.Query esQuery = getQuery(filterQuery, null); - - if (esQuery != null) { - aliasBuilder.filter(esQuery); - } - } - return aliasBuilder; + return buildAlias(parameters, aliasBuilder); }); } } @@ -360,6 +412,55 @@ class RequestConverter { return builder.build(); } + public co.elastic.clients.elasticsearch.indices.PutIndexTemplateRequest indicesPutIndexTemplateRequest( + PutIndexTemplateRequest putIndexTemplateRequest) { + + Assert.notNull(putIndexTemplateRequest, "putIndexTemplateRequest must not be null"); + + var builder = new co.elastic.clients.elasticsearch.indices.PutIndexTemplateRequest.Builder() + .name(putIndexTemplateRequest.name()) // + .indexPatterns(Arrays.asList(putIndexTemplateRequest.indexPatterns())) // + .template(t -> { + t // + .settings(indexSettings(putIndexTemplateRequest.settings())) // + .mappings(typeMapping(putIndexTemplateRequest.mapping())); + + // same code schema, but different Elasticsearch builder types + // noinspection DuplicatedCode + var aliasActions = putIndexTemplateRequest.aliasActions(); + if (aliasActions != null) { + aliasActions.getActions().forEach(aliasAction -> { + if (aliasAction instanceof AliasAction.Add add) { + var parameters = add.getParameters(); + // noinspection DuplicatedCode + String[] parametersAliases = parameters.getAliases(); + if (parametersAliases != null) { + for (String aliasName : parametersAliases) { + t.aliases(aliasName, aliasBuilder -> buildAlias(parameters, aliasBuilder)); + } + } + } + }); + } + return t; + }); + + if (!putIndexTemplateRequest.composedOf().isEmpty()) { + builder.composedOf(putIndexTemplateRequest.composedOf()); + } + + return builder.build(); + } + + public ExistsIndexTemplateRequest indicesExistsIndexTemplateRequest( + org.springframework.data.elasticsearch.core.index.ExistsIndexTemplateRequest existsIndexTemplateRequest) { + + Assert.notNull(existsIndexTemplateRequest, "existsIndexTemplateRequest must not be null"); + + return co.elastic.clients.elasticsearch.indices.ExistsIndexTemplateRequest + .of(b -> b.name(existsIndexTemplateRequest.templateName())); + } + public co.elastic.clients.elasticsearch.indices.ExistsTemplateRequest indicesExistsTemplateRequest( ExistsTemplateRequest existsTemplateRequest) { @@ -369,6 +470,24 @@ class RequestConverter { .of(etr -> etr.name(existsTemplateRequest.getTemplateName())); } + public co.elastic.clients.elasticsearch.indices.GetIndexTemplateRequest indicesGetIndexTemplateRequest( + GetIndexTemplateRequest getIndexTemplateRequest) { + + Assert.notNull(getIndexTemplateRequest, "getIndexTemplateRequest must not be null"); + + return co.elastic.clients.elasticsearch.indices.GetIndexTemplateRequest + .of(gitr -> gitr.name(getIndexTemplateRequest.templateName())); + } + + public co.elastic.clients.elasticsearch.indices.DeleteIndexTemplateRequest indicesDeleteIndexTemplateRequest( + DeleteIndexTemplateRequest deleteIndexTemplateRequest) { + + Assert.notNull(deleteIndexTemplateRequest, "deleteIndexTemplateRequest must not be null"); + + return co.elastic.clients.elasticsearch.indices.DeleteIndexTemplateRequest + .of(ditr -> ditr.name(deleteIndexTemplateRequest.templateName())); + } + public co.elastic.clients.elasticsearch.indices.DeleteTemplateRequest indicesDeleteTemplateRequest( DeleteTemplateRequest existsTemplateRequest) { @@ -440,7 +559,7 @@ class RequestConverter { } } - builder.refresh(TypeUtils.refresh(refreshPolicy)); + builder.refresh(refresh(refreshPolicy)); return builder.build(); } @@ -607,9 +726,9 @@ class RequestConverter { builder.timeout(tb -> tb.time(Long.valueOf(bulkOptions.getTimeout().toMillis()).toString() + "ms")); } - builder.refresh(TypeUtils.refresh(refreshPolicy)); + builder.refresh(refresh(refreshPolicy)); if (bulkOptions.getRefreshPolicy() != null) { - builder.refresh(TypeUtils.refresh(bulkOptions.getRefreshPolicy())); + builder.refresh(refresh(bulkOptions.getRefreshPolicy())); } if (bulkOptions.getWaitForActiveShards() != null) { @@ -752,13 +871,13 @@ class RequestConverter { ReindexRequest.Dest dest = reindexRequest.getDest(); return d // .index(dest.getIndex().getIndexName()) // - .versionType(TypeUtils.versionType(dest.getVersionType())) // - .opType(TypeUtils.opType(dest.getOpType())); + .versionType(versionType(dest.getVersionType())) // + .opType(opType(dest.getOpType())); } // ); if (reindexRequest.getConflicts() != null) { - builder.conflicts(TypeUtils.conflicts(reindexRequest.getConflicts())); + builder.conflicts(conflicts(reindexRequest.getConflicts())); } ReindexRequest.Script script = reindexRequest.getScript(); @@ -771,7 +890,7 @@ class RequestConverter { if (reindexRequest.getWaitForActiveShards() != null) { builder.waitForActiveShards(wfas -> wfas // - .count(TypeUtils.waitForActiveShardsCount(reindexRequest.getWaitForActiveShards()))); + .count(waitForActiveShardsCount(reindexRequest.getWaitForActiveShards()))); } builder // @@ -796,7 +915,7 @@ class RequestConverter { if (routing != null) { r.routing(routing); } - r.refresh(TypeUtils.refresh(refreshPolicy)); + r.refresh(refresh(refreshPolicy)); return r; }); } @@ -869,7 +988,7 @@ class RequestConverter { .docAsUpsert(query.getDocAsUpsert()) // .ifSeqNo(query.getIfSeqNo() != null ? Long.valueOf(query.getIfSeqNo()) : null) // .ifPrimaryTerm(query.getIfPrimaryTerm() != null ? Long.valueOf(query.getIfPrimaryTerm()) : null) // - .refresh(TypeUtils.refresh(refreshPolicy)) // + .refresh(refresh(refreshPolicy)) // .retryOnConflict(query.getRetryOnConflict()) // ; @@ -953,7 +1072,7 @@ class RequestConverter { } if (updateQuery.getWaitForActiveShards() != null) { - ub.waitForActiveShards(w -> w.count(TypeUtils.waitForActiveShardsCount(updateQuery.getWaitForActiveShards()))); + ub.waitForActiveShards(w -> w.count(waitForActiveShardsCount(updateQuery.getWaitForActiveShards()))); } return ub; @@ -1299,7 +1418,7 @@ class RequestConverter { return Rescore.of(r -> r // .query(rq -> rq // .query(getQuery(rescorerQuery.getQuery(), null)) // - .scoreMode(TypeUtils.scoreMode(rescorerQuery.getScoreMode())) // + .scoreMode(scoreMode(rescorerQuery.getScoreMode())) // .queryWeight(rescorerQuery.getQueryWeight() != null ? Double.valueOf(rescorerQuery.getQueryWeight()) : 1.0) // .rescoreQueryWeight( rescorerQuery.getRescoreQueryWeight() != null ? Double.valueOf(rescorerQuery.getRescoreQueryWeight()) @@ -1359,9 +1478,8 @@ class RequestConverter { .geoDistance(gd -> gd // .field(fieldName) // .location(loc -> loc.latlon(Queries.latLon(geoDistanceOrder.getGeoPoint())))// - .distanceType(TypeUtils.geoDistanceType(geoDistanceOrder.getDistanceType())) - .mode(TypeUtils.sortMode(finalMode)) // - .unit(TypeUtils.distanceUnit(geoDistanceOrder.getUnit())) // + .distanceType(geoDistanceType(geoDistanceOrder.getDistanceType())).mode(sortMode(finalMode)) // + .unit(distanceUnit(geoDistanceOrder.getUnit())) // .ignoreUnmapped(geoDistanceOrder.getIgnoreUnmapped()))); } else { String missing = (order.getNullHandling() == Sort.NullHandling.NULLS_FIRST) ? "_first" @@ -1371,10 +1489,10 @@ class RequestConverter { .field(f -> { f.field(fieldName) // .order(sortOrder) // - .mode(TypeUtils.sortMode(finalMode)); + .mode(sortMode(finalMode)); if (finalUnmappedType != null) { - FieldType fieldType = TypeUtils.fieldType(finalUnmappedType); + FieldType fieldType = fieldType(finalUnmappedType); if (fieldType != null) { f.unmappedType(fieldType); diff --git a/src/main/java/org/springframework/data/elasticsearch/client/elc/ResponseConverter.java b/src/main/java/org/springframework/data/elasticsearch/client/elc/ResponseConverter.java index 90831f90a..11bd0fefa 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/elc/ResponseConverter.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/elc/ResponseConverter.java @@ -15,37 +15,28 @@ */ package org.springframework.data.elasticsearch.client.elc; -import static org.springframework.data.elasticsearch.client.elc.JsonUtils.*; +import static org.springframework.data.elasticsearch.client.elc.JsonUtils.toJson; +import static org.springframework.data.elasticsearch.client.elc.TypeUtils.removePrefixFromJson; +import static org.springframework.data.elasticsearch.client.elc.TypeUtils.typeMapping; import co.elastic.clients.elasticsearch._types.BulkIndexByScrollFailure; import co.elastic.clients.elasticsearch._types.ErrorCause; import co.elastic.clients.elasticsearch._types.Time; import co.elastic.clients.elasticsearch._types.query_dsl.Query; +import co.elastic.clients.elasticsearch.cluster.ComponentTemplateSummary; +import co.elastic.clients.elasticsearch.cluster.GetComponentTemplateResponse; import co.elastic.clients.elasticsearch.cluster.HealthResponse; import co.elastic.clients.elasticsearch.core.DeleteByQueryResponse; import co.elastic.clients.elasticsearch.core.GetScriptResponse; import co.elastic.clients.elasticsearch.core.UpdateByQueryResponse; import co.elastic.clients.elasticsearch.core.mget.MultiGetError; import co.elastic.clients.elasticsearch.core.mget.MultiGetResponseItem; -import co.elastic.clients.elasticsearch.indices.Alias; -import co.elastic.clients.elasticsearch.indices.AliasDefinition; -import co.elastic.clients.elasticsearch.indices.GetAliasResponse; -import co.elastic.clients.elasticsearch.indices.GetIndexResponse; -import co.elastic.clients.elasticsearch.indices.GetIndicesSettingsResponse; -import co.elastic.clients.elasticsearch.indices.GetMappingResponse; -import co.elastic.clients.elasticsearch.indices.GetTemplateResponse; -import co.elastic.clients.elasticsearch.indices.IndexSettings; -import co.elastic.clients.elasticsearch.indices.IndexState; -import co.elastic.clients.elasticsearch.indices.TemplateMapping; +import co.elastic.clients.elasticsearch.indices.*; +import co.elastic.clients.elasticsearch.indices.get_index_template.IndexTemplateItem; import co.elastic.clients.elasticsearch.indices.get_mapping.IndexMappingRecord; import co.elastic.clients.json.JsonpMapper; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; @@ -56,9 +47,7 @@ import org.springframework.data.elasticsearch.core.IndexInformation; import org.springframework.data.elasticsearch.core.MultiGetItem; import org.springframework.data.elasticsearch.core.cluster.ClusterHealth; import org.springframework.data.elasticsearch.core.document.Document; -import org.springframework.data.elasticsearch.core.index.AliasData; -import org.springframework.data.elasticsearch.core.index.Settings; -import org.springframework.data.elasticsearch.core.index.TemplateData; +import org.springframework.data.elasticsearch.core.index.*; import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; import org.springframework.data.elasticsearch.core.query.ByQueryResponse; import org.springframework.data.elasticsearch.core.query.StringQuery; @@ -107,6 +96,54 @@ class ResponseConverter { .withUnassignedShards(healthResponse.unassignedShards()) // .build(); // } + + public List clusterGetComponentTemplates( + GetComponentTemplateResponse getComponentTemplateResponse) { + + Assert.notNull(getComponentTemplateResponse, "getComponentTemplateResponse must not be null"); + + var componentTemplates = new ArrayList(); + getComponentTemplateResponse.componentTemplates().forEach(componentTemplate -> { + componentTemplates.add(clusterGetComponentTemplate(componentTemplate)); + }); + + return componentTemplates; + } + + private TemplateResponse clusterGetComponentTemplate( + co.elastic.clients.elasticsearch.cluster.ComponentTemplate componentTemplate) { + var componentTemplateNode = componentTemplate.componentTemplate(); + var componentTemplateSummary = componentTemplateNode.template(); + return TemplateResponse.builder() // + .withName(componentTemplate.name()) // + .withVersion(componentTemplateNode.version()) // + .withTemplateData(clusterGetComponentTemplateData(componentTemplateSummary)) // + .build(); + } + + private TemplateResponseData clusterGetComponentTemplateData( + ComponentTemplateSummary componentTemplateSummary) { + + var mapping = typeMapping(componentTemplateSummary.mappings()); + var settings = new Settings(); + componentTemplateSummary.settings().forEach((key, indexSettings) -> { + settings.put(key, Settings.parse(removePrefixFromJson(indexSettings.toString()))); + }); + + Function, String> keyMapper = Map.Entry::getKey; + Function, AliasData> valueMapper = entry -> indicesGetAliasData( + entry.getKey(), entry.getValue()); + + Map aliases = componentTemplateSummary.aliases().entrySet().stream() + .collect(Collectors.toMap(keyMapper, valueMapper)); + + return TemplateResponseData.builder() // + .withMapping(mapping) // + .withSettings(settings) // + .withAliases(aliases) // + .build(); + } + // endregion // region indices client @@ -265,6 +302,59 @@ class ResponseConverter { return null; } + public List getIndexTemplates(GetIndexTemplateResponse getIndexTemplateResponse) { + + Assert.notNull(getIndexTemplateResponse, "getIndexTemplateResponse must not be null"); + + var componentTemplates = new ArrayList(); + getIndexTemplateResponse.indexTemplates().forEach(indexTemplateItem -> { + componentTemplates.add(indexGetComponentTemplate(indexTemplateItem)); + }); + + return componentTemplates; + } + + private TemplateResponse indexGetComponentTemplate(IndexTemplateItem indexTemplateItem) { + var indexTemplate = indexTemplateItem.indexTemplate(); + var composedOf = indexTemplate.composedOf(); + var indexTemplateSummary = indexTemplate.template(); + return TemplateResponse.builder() // + .withName(indexTemplateItem.name()) // + .withVersion(indexTemplate.version()) // + .withTemplateData(indexGetComponentTemplateData(indexTemplateSummary, composedOf)) // + .build(); + } + + private TemplateResponseData indexGetComponentTemplateData(IndexTemplateSummary indexTemplateSummary, + List composedOf) { + var mapping = typeMapping(indexTemplateSummary.mappings()); + + Function indexSettingsToSettings = indexSettings -> { + + if (indexSettings == null) { + return null; + } + + Settings parsedSettings = Settings.parse(toJson(indexSettings, jsonpMapper)); + return (indexSettings.index() != null) ? parsedSettings : new Settings().append("index", parsedSettings); + }; + var settings = indexSettingsToSettings.apply(indexTemplateSummary.settings()); + + Function, String> keyMapper = Map.Entry::getKey; + Function, AliasData> valueMapper = entry -> indicesGetAliasData(entry.getKey(), + entry.getValue()); + + Map aliases1 = indexTemplateSummary.aliases(); + Map aliases = aliases1.entrySet().stream().collect(Collectors.toMap(keyMapper, valueMapper)); + + return TemplateResponseData.builder() // + .withMapping(mapping) // + .withSettings(settings) // + .withAliases(aliases) // + .withComposedOf(composedOf) // + .build(); + } + // endregion // region document operations @@ -465,6 +555,5 @@ class ResponseConverter { return null; } } - // endregion } diff --git a/src/main/java/org/springframework/data/elasticsearch/client/elc/TypeUtils.java b/src/main/java/org/springframework/data/elasticsearch/client/elc/TypeUtils.java index 488382fb5..ba2ae1c5d 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/elc/TypeUtils.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/elc/TypeUtils.java @@ -17,27 +17,21 @@ package org.springframework.data.elasticsearch.client.elc; import co.elastic.clients.elasticsearch._types.*; import co.elastic.clients.elasticsearch._types.mapping.FieldType; -import co.elastic.clients.elasticsearch.core.search.BoundaryScanner; -import co.elastic.clients.elasticsearch.core.search.HighlighterEncoder; -import co.elastic.clients.elasticsearch.core.search.HighlighterFragmenter; -import co.elastic.clients.elasticsearch.core.search.HighlighterOrder; -import co.elastic.clients.elasticsearch.core.search.HighlighterTagsSchema; -import co.elastic.clients.elasticsearch.core.search.HighlighterType; -import co.elastic.clients.elasticsearch.core.search.ScoreMode; +import co.elastic.clients.elasticsearch._types.mapping.TypeMapping; +import co.elastic.clients.elasticsearch.core.search.*; +import co.elastic.clients.elasticsearch.indices.IndexSettings; +import java.io.StringReader; import java.time.Duration; import java.util.EnumSet; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import org.springframework.data.elasticsearch.core.RefreshPolicy; -import org.springframework.data.elasticsearch.core.query.GeoDistanceOrder; -import org.springframework.data.elasticsearch.core.query.IndexQuery; +import org.springframework.data.elasticsearch.core.document.Document; +import org.springframework.data.elasticsearch.core.query.*; import org.springframework.data.elasticsearch.core.query.IndicesOptions; -import org.springframework.data.elasticsearch.core.query.Order; -import org.springframework.data.elasticsearch.core.query.Query; -import org.springframework.data.elasticsearch.core.query.RescorerQuery; -import org.springframework.data.elasticsearch.core.query.UpdateResponse; import org.springframework.data.elasticsearch.core.reindex.ReindexRequest; import org.springframework.lang.Nullable; @@ -406,4 +400,27 @@ final class TypeUtils { .map(wildcardState -> ExpandWildcard.valueOf(wildcardState.name().toLowerCase())).collect(Collectors.toList()) : null; } + + @Nullable + static TypeMapping typeMapping(@Nullable Document mapping) { + if (mapping != null) { + return TypeMapping.of(b -> b.withJson(new StringReader(mapping.toJson()))); + } + return null; + } + + @Nullable + static Document typeMapping(@Nullable TypeMapping typeMapping) { + return (typeMapping != null) ? Document.parse(removePrefixFromJson(typeMapping.toString())) : null; + } + + public static String removePrefixFromJson(String jsonWithPrefix) { + return jsonWithPrefix.substring(jsonWithPrefix.indexOf("{")); + } + + @Nullable + static IndexSettings indexSettings(@Nullable Map settings) { + return settings != null ? IndexSettings.of(b -> b.withJson(new StringReader(Document.from(settings).toJson()))) + : null; + } } diff --git a/src/main/java/org/springframework/data/elasticsearch/client/erhlc/DefaultReactiveClusterOperations.java b/src/main/java/org/springframework/data/elasticsearch/client/erhlc/DefaultReactiveClusterOperations.java index 94454c495..8852719ad 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/erhlc/DefaultReactiveClusterOperations.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/erhlc/DefaultReactiveClusterOperations.java @@ -20,6 +20,7 @@ import reactor.core.publisher.Mono; import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest; import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations; import org.springframework.data.elasticsearch.core.cluster.ClusterHealth; +import org.springframework.data.elasticsearch.core.cluster.ReactiveClusterOperations; /** * Default implementation of {@link ReactiveClusterOperations} using the {@link ReactiveElasticsearchOperations}. diff --git a/src/main/java/org/springframework/data/elasticsearch/client/erhlc/ReactiveElasticsearchTemplate.java b/src/main/java/org/springframework/data/elasticsearch/client/erhlc/ReactiveElasticsearchTemplate.java index f847ae26c..d29737993 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/erhlc/ReactiveElasticsearchTemplate.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/erhlc/ReactiveElasticsearchTemplate.java @@ -47,24 +47,13 @@ import org.reactivestreams.Publisher; import org.springframework.data.elasticsearch.BulkFailureException; import org.springframework.data.elasticsearch.NoSuchIndexException; import org.springframework.data.elasticsearch.UncategorizedElasticsearchException; -import org.springframework.data.elasticsearch.core.AbstractReactiveElasticsearchTemplate; -import org.springframework.data.elasticsearch.core.AggregationContainer; -import org.springframework.data.elasticsearch.core.IndexedObjectInformation; -import org.springframework.data.elasticsearch.core.MultiGetItem; -import org.springframework.data.elasticsearch.core.ReactiveIndexOperations; -import org.springframework.data.elasticsearch.core.RefreshPolicy; -import org.springframework.data.elasticsearch.core.SearchHitMapping; -import org.springframework.data.elasticsearch.core.SearchHitSupport; -import org.springframework.data.elasticsearch.core.SearchPage; +import org.springframework.data.elasticsearch.core.*; +import org.springframework.data.elasticsearch.core.cluster.ReactiveClusterOperations; import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter; import org.springframework.data.elasticsearch.core.document.SearchDocument; import org.springframework.data.elasticsearch.core.document.SearchDocumentResponse; import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; -import org.springframework.data.elasticsearch.core.query.BulkOptions; -import org.springframework.data.elasticsearch.core.query.ByQueryResponse; -import org.springframework.data.elasticsearch.core.query.Query; -import org.springframework.data.elasticsearch.core.query.UpdateQuery; -import org.springframework.data.elasticsearch.core.query.UpdateResponse; +import org.springframework.data.elasticsearch.core.query.*; import org.springframework.data.elasticsearch.core.reindex.ReindexRequest; import org.springframework.data.elasticsearch.core.reindex.ReindexResponse; import org.springframework.http.HttpStatus; diff --git a/src/main/java/org/springframework/data/elasticsearch/client/erhlc/ReactiveIndexTemplate.java b/src/main/java/org/springframework/data/elasticsearch/client/erhlc/ReactiveIndexTemplate.java index 1f17c92f5..c44bfffda 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/erhlc/ReactiveIndexTemplate.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/erhlc/ReactiveIndexTemplate.java @@ -15,13 +15,9 @@ */ package org.springframework.data.elasticsearch.client.erhlc; -import static org.elasticsearch.client.Requests.*; -import static org.springframework.util.StringUtils.*; +import static org.elasticsearch.client.Requests.refreshRequest; +import static org.springframework.util.StringUtils.hasText; -import org.springframework.data.elasticsearch.core.IndexInformation; -import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations; -import org.springframework.data.elasticsearch.core.ReactiveIndexOperations; -import org.springframework.data.elasticsearch.core.ReactiveResourceUtil; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -36,27 +32,21 @@ import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.admin.indices.settings.get.GetSettingsRequest; import org.elasticsearch.action.admin.indices.template.delete.DeleteIndexTemplateRequest; import org.elasticsearch.client.GetAliasesResponse; -import org.elasticsearch.client.indices.CreateIndexRequest; -import org.elasticsearch.client.indices.GetIndexRequest; -import org.elasticsearch.client.indices.GetIndexTemplatesRequest; -import org.elasticsearch.client.indices.GetMappingsRequest; -import org.elasticsearch.client.indices.IndexTemplatesExistRequest; +import org.elasticsearch.client.indices.*; import org.elasticsearch.client.indices.PutIndexTemplateRequest; import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.elasticsearch.NoSuchIndexException; import org.springframework.data.elasticsearch.annotations.Mapping; +import org.springframework.data.elasticsearch.core.IndexInformation; +import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations; +import org.springframework.data.elasticsearch.core.ReactiveIndexOperations; +import org.springframework.data.elasticsearch.core.ReactiveResourceUtil; import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter; import org.springframework.data.elasticsearch.core.document.Document; -import org.springframework.data.elasticsearch.core.index.AliasActions; -import org.springframework.data.elasticsearch.core.index.AliasData; -import org.springframework.data.elasticsearch.core.index.DeleteTemplateRequest; -import org.springframework.data.elasticsearch.core.index.ExistsTemplateRequest; -import org.springframework.data.elasticsearch.core.index.GetTemplateRequest; -import org.springframework.data.elasticsearch.core.index.PutTemplateRequest; -import org.springframework.data.elasticsearch.core.index.ReactiveMappingBuilder; -import org.springframework.data.elasticsearch.core.index.Settings; -import org.springframework.data.elasticsearch.core.index.TemplateData; +import org.springframework.data.elasticsearch.core.index.*; +import org.springframework.data.elasticsearch.core.index.DeleteComponentTemplateRequest; +import org.springframework.data.elasticsearch.core.index.PutComponentTemplateRequest; import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity; import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; import org.springframework.lang.Nullable; @@ -290,6 +280,48 @@ class ReactiveIndexTemplate implements ReactiveIndexOperations { return Mono.from(operations.executeWithIndicesClient(client -> client.putTemplate(putIndexTemplateRequest))); } + @Override + public Mono putComponentTemplate(PutComponentTemplateRequest putComponentTemplateRequest) { + throw new UnsupportedOperationException("not implemented"); + } + + @Override + public Flux getComponentTemplate(GetComponentTemplateRequest request) { + throw new UnsupportedOperationException("not implemented"); + } + + @Override + public Mono existsComponentTemplate(ExistsComponentTemplateRequest existsComponentTemplateRequest) { + throw new UnsupportedOperationException("not implemented"); + } + + @Override + public Mono deleteComponentTemplate(DeleteComponentTemplateRequest deleteComponentTemplateRequest) { + throw new UnsupportedOperationException("not implemented"); + } + + @Override + public Mono putIndexTemplate( + org.springframework.data.elasticsearch.core.index.PutIndexTemplateRequest putIndexTemplateRequest) { + throw new UnsupportedOperationException("not implemented"); + } + + @Override + public Mono existsIndexTemplate(ExistsIndexTemplateRequest existsIndexTemplateRequest) { + throw new UnsupportedOperationException("not implemented"); + } + + @Override + public Flux getIndexTemplate(GetIndexTemplateRequest getIndexTemplateRequest) { + throw new UnsupportedOperationException("not implemented"); + } + + @Override + public Mono deleteIndexTemplate( + org.springframework.data.elasticsearch.core.index.DeleteIndexTemplateRequest deleteIndexTemplateRequest) { + throw new UnsupportedOperationException("not implemented"); + } + @Override public Mono getTemplate(GetTemplateRequest getTemplateRequest) { diff --git a/src/main/java/org/springframework/data/elasticsearch/client/erhlc/RequestFactory.java b/src/main/java/org/springframework/data/elasticsearch/client/erhlc/RequestFactory.java index e0fc6e66b..1e29f0b6c 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/erhlc/RequestFactory.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/erhlc/RequestFactory.java @@ -348,7 +348,8 @@ class RequestFactory { for (String aliasName : parametersAliases) { Alias alias = new Alias(aliasName); - if (parameters.getRouting() != null) { + //noinspection DuplicatedCode + if (parameters.getRouting() != null) { alias.routing(parameters.getRouting()); } diff --git a/src/main/java/org/springframework/data/elasticsearch/client/erhlc/RestIndexTemplate.java b/src/main/java/org/springframework/data/elasticsearch/client/erhlc/RestIndexTemplate.java index 72df90893..b9a309003 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/erhlc/RestIndexTemplate.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/erhlc/RestIndexTemplate.java @@ -44,14 +44,7 @@ import org.springframework.data.elasticsearch.core.AbstractIndexTemplate; import org.springframework.data.elasticsearch.core.IndexInformation; import org.springframework.data.elasticsearch.core.IndexOperations; import org.springframework.data.elasticsearch.core.document.Document; -import org.springframework.data.elasticsearch.core.index.AliasActions; -import org.springframework.data.elasticsearch.core.index.AliasData; -import org.springframework.data.elasticsearch.core.index.DeleteTemplateRequest; -import org.springframework.data.elasticsearch.core.index.ExistsTemplateRequest; -import org.springframework.data.elasticsearch.core.index.GetTemplateRequest; -import org.springframework.data.elasticsearch.core.index.PutTemplateRequest; -import org.springframework.data.elasticsearch.core.index.Settings; -import org.springframework.data.elasticsearch.core.index.TemplateData; +import org.springframework.data.elasticsearch.core.index.*; import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -231,6 +224,48 @@ class RestIndexTemplate extends AbstractIndexTemplate implements IndexOperations client -> client.indices().deleteTemplate(deleteIndexTemplateRequest, RequestOptions.DEFAULT).isAcknowledged()); } + @Override + public boolean putIndexTemplate( + org.springframework.data.elasticsearch.core.index.PutIndexTemplateRequest putIndexTemplateRequest) { + throw new UnsupportedOperationException("not implemented"); + } + + @Override + public boolean existsIndexTemplate(ExistsIndexTemplateRequest existsTemplateRequest) { + throw new UnsupportedOperationException("not implemented"); + } + + @Override + public List getIndexTemplate(GetIndexTemplateRequest getIndexTemplateRequest) { + throw new UnsupportedOperationException("not implemented"); + } + + @Override + public boolean deleteIndexTemplate( + org.springframework.data.elasticsearch.core.index.DeleteIndexTemplateRequest deleteIndexTemplateRequest) { + throw new UnsupportedOperationException("not implemented"); + } + + @Override + public boolean putComponentTemplate(PutComponentTemplateRequest putComponentTemplateRequest) { + throw new UnsupportedOperationException("not implemented"); + } + + @Override + public boolean existsComponentTemplate(ExistsComponentTemplateRequest existsComponentTemplateRequest) { + throw new UnsupportedOperationException("not implemented"); + } + + @Override + public List getComponentTemplate(GetComponentTemplateRequest getComponentTemplateRequest) { + throw new UnsupportedOperationException("not implemented"); + } + + @Override + public boolean deleteComponentTemplate(DeleteComponentTemplateRequest deleteComponentTemplateRequest) { + throw new UnsupportedOperationException("not implemented"); + } + @Override public List getInformation(IndexCoordinates index) { diff --git a/src/main/java/org/springframework/data/elasticsearch/core/IndexOperations.java b/src/main/java/org/springframework/data/elasticsearch/core/IndexOperations.java index 7b44fe0c7..4caa3c68b 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/IndexOperations.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/IndexOperations.java @@ -20,14 +20,7 @@ import java.util.Map; import java.util.Set; import org.springframework.data.elasticsearch.core.document.Document; -import org.springframework.data.elasticsearch.core.index.AliasActions; -import org.springframework.data.elasticsearch.core.index.AliasData; -import org.springframework.data.elasticsearch.core.index.DeleteTemplateRequest; -import org.springframework.data.elasticsearch.core.index.ExistsTemplateRequest; -import org.springframework.data.elasticsearch.core.index.GetTemplateRequest; -import org.springframework.data.elasticsearch.core.index.PutTemplateRequest; -import org.springframework.data.elasticsearch.core.index.Settings; -import org.springframework.data.elasticsearch.core.index.TemplateData; +import org.springframework.data.elasticsearch.core.index.*; import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; import org.springframework.lang.Nullable; @@ -224,16 +217,65 @@ public interface IndexOperations { * @param putTemplateRequest template request parameters * @return true if successful * @since 4.1 + * @deprecated since 5.1, as the underlying Elasticsearch API is deprecated. */ + @Deprecated boolean putTemplate(PutTemplateRequest putTemplateRequest); + /** + * Creates an index template + * + * @param putIndexTemplateRequest template request parameters + * @return {@literal true} if successful + * @since 5.1 + */ + boolean putIndexTemplate(PutIndexTemplateRequest putIndexTemplateRequest); + + /** + * Writes a component index template that can be used in a composable index template. + * + * @param putComponentTemplateRequest index template request parameters + * @return {@literal true} if successful + * @since 5.1 + */ + boolean putComponentTemplate(PutComponentTemplateRequest putComponentTemplateRequest); + + /** + * Checks wether a component index template exists. + * + * @param existsComponentTemplateRequest the parameters for the request + * @return {@literal true} if the componentTemplate exists. + * @since 5.1 + */ + boolean existsComponentTemplate(ExistsComponentTemplateRequest existsComponentTemplateRequest); + + /** + * Get a component template. + * + * @param getComponentTemplateRequest parameters for the request, may contain wildcard names + * @return the found {@link TemplateResponse}s, may be empty + * @since 5.1 + */ + List getComponentTemplate(GetComponentTemplateRequest getComponentTemplateRequest); + + /** + * Deletes the given component index template + * + * @param deleteComponentTemplateRequest request parameters + * @return {@literal true} if successful. + * @since 5.1 + */ + boolean deleteComponentTemplate(DeleteComponentTemplateRequest deleteComponentTemplateRequest); + /** * gets an index template using the legacy Elasticsearch interface. * * @param templateName the template name * @return TemplateData, {@literal null} if no template with the given name exists. * @since 4.1 + * @deprecated since 5.1, as the underlying Elasticsearch API is deprecated. */ + @Deprecated @Nullable default TemplateData getTemplate(String templateName) { return getTemplate(new GetTemplateRequest(templateName)); @@ -245,7 +287,9 @@ public interface IndexOperations { * @param getTemplateRequest the request parameters * @return TemplateData, {@literal null} if no template with the given name exists. * @since 4.1 + * @deprecated since 5.1, as the underlying Elasticsearch API is deprecated. */ + @Deprecated @Nullable TemplateData getTemplate(GetTemplateRequest getTemplateRequest); @@ -255,7 +299,9 @@ public interface IndexOperations { * @param templateName the template name * @return {@literal true} if the index exists * @since 4.1 + * @deprecated since 5.1, as the underlying Elasticsearch API is deprecated. */ + @Deprecated default boolean existsTemplate(String templateName) { return existsTemplate(new ExistsTemplateRequest(templateName)); } @@ -266,9 +312,69 @@ public interface IndexOperations { * @param existsTemplateRequest the request parameters * @return {@literal true} if the index exists * @since 4.1 + * @deprecated since 5.1, as the underlying Elasticsearch API is deprecated. */ + @Deprecated boolean existsTemplate(ExistsTemplateRequest existsTemplateRequest); + /** + * check if an index template exists. + * + * @param templateName the template name + * @return true if the index template exists + * @since 5.1 + */ + default boolean existsIndexTemplate(String templateName) { + return existsIndexTemplate(new ExistsIndexTemplateRequest(templateName)); + } + + /** + * check if an index template exists. + * + * @param existsTemplateRequest the request parameters + * @return true if the index template exists + * @since 5.1 + */ + boolean existsIndexTemplate(ExistsIndexTemplateRequest existsTemplateRequest); + + /** + * Gets an index template. + * + * @param templateName template name + * @since 5.1 + */ + default List getIndexTemplate(String templateName) { + return getIndexTemplate(new GetIndexTemplateRequest(templateName)); + } + + /** + * Gets an index template. + * + * @param getIndexTemplateRequest the request parameters + * @since 5.1 + */ + List getIndexTemplate(GetIndexTemplateRequest getIndexTemplateRequest); + + /** + * Deletes an index template. + * + * @param templateName template name + * @return true if successful + * @since 5.1 + */ + default boolean deleteIndexTemplate(String templateName) { + return deleteIndexTemplate(new DeleteIndexTemplateRequest(templateName)); + } + + /** + * Deletes an index template. + * + * @param deleteIndexTemplateRequest template request parameters + * @return true if successful + * @since 5.1 + */ + boolean deleteIndexTemplate(DeleteIndexTemplateRequest deleteIndexTemplateRequest); + /** * Deletes an index template using the legacy Elasticsearch interface (@see * https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-templates-v1.html). @@ -276,7 +382,9 @@ public interface IndexOperations { * @param templateName the template name * @return true if successful * @since 4.1 + * @deprecated since 5.1, as the underlying Elasticsearch API is deprecated. */ + @Deprecated default boolean deleteTemplate(String templateName) { return deleteTemplate(new DeleteTemplateRequest(templateName)); } @@ -288,7 +396,9 @@ public interface IndexOperations { * @param deleteTemplateRequest template request parameters * @return true if successful * @since 4.1 + * @deprecated since 5.1, as the underlying Elasticsearch API is deprecated. */ + @Deprecated boolean deleteTemplate(DeleteTemplateRequest deleteTemplateRequest); // endregion diff --git a/src/main/java/org/springframework/data/elasticsearch/core/ReactiveElasticsearchOperations.java b/src/main/java/org/springframework/data/elasticsearch/core/ReactiveElasticsearchOperations.java index 999bc147a..8cc95a825 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/ReactiveElasticsearchOperations.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/ReactiveElasticsearchOperations.java @@ -16,9 +16,9 @@ package org.springframework.data.elasticsearch.core; import org.reactivestreams.Publisher; -import org.springframework.data.elasticsearch.client.erhlc.ReactiveClusterOperations; import org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchClient; import org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchTemplate; +import org.springframework.data.elasticsearch.core.cluster.ReactiveClusterOperations; import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter; import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity; import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; diff --git a/src/main/java/org/springframework/data/elasticsearch/core/ReactiveIndexOperations.java b/src/main/java/org/springframework/data/elasticsearch/core/ReactiveIndexOperations.java index b7b7881cd..ad5d21951 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/ReactiveIndexOperations.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/ReactiveIndexOperations.java @@ -22,14 +22,7 @@ import java.util.Map; import java.util.Set; import org.springframework.data.elasticsearch.core.document.Document; -import org.springframework.data.elasticsearch.core.index.AliasActions; -import org.springframework.data.elasticsearch.core.index.AliasData; -import org.springframework.data.elasticsearch.core.index.DeleteTemplateRequest; -import org.springframework.data.elasticsearch.core.index.ExistsTemplateRequest; -import org.springframework.data.elasticsearch.core.index.GetTemplateRequest; -import org.springframework.data.elasticsearch.core.index.PutTemplateRequest; -import org.springframework.data.elasticsearch.core.index.Settings; -import org.springframework.data.elasticsearch.core.index.TemplateData; +import org.springframework.data.elasticsearch.core.index.*; import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; /** @@ -226,16 +219,125 @@ public interface ReactiveIndexOperations { * @param putTemplateRequest template request parameters * @return Mono of {@literal true} if the template could be stored * @since 4.1 + * @deprecated since 5.1, as the underlying Elasticsearch API is deprecated. */ + @Deprecated Mono putTemplate(PutTemplateRequest putTemplateRequest); + /** + * Writes a component index template that can be used in a composable index template. + * + * @param putComponentTemplateRequest index template request parameters + * @return {@literal true} if successful + * @since 5.1 + */ + Mono putComponentTemplate(PutComponentTemplateRequest putComponentTemplateRequest); + + /** + * Get component template(s). + * + * @param getComponentTemplateRequest the getComponentTemplateRequest parameters + * @return a {@link Flux} of {@link TemplateResponse} + * @since 5.1 + */ + Flux getComponentTemplate(GetComponentTemplateRequest getComponentTemplateRequest); + + /** + * Checks wether a component index template exists. + * + * @param existsComponentTemplateRequest the parameters for the request + * @return Mono with the value if the componentTemplate exists. + * @since 5.1 + */ + Mono existsComponentTemplate(ExistsComponentTemplateRequest existsComponentTemplateRequest); + + /** + * Deletes a component index template. + * + * @param deleteComponentTemplateRequest the parameters for the request + * @return Mono with the value if the request was acknowledged. + * @since 5.1 + */ + Mono deleteComponentTemplate(DeleteComponentTemplateRequest deleteComponentTemplateRequest); + + /** + * Creates an index template. + * + * @param putIndexTemplateRequest template request parameters + * @return {@literal true} if successful + * @since 5.1 + */ + Mono putIndexTemplate(PutIndexTemplateRequest putIndexTemplateRequest); + + /** + * Checks if an index template exists. + * + * @param indexTemplateName the name of the index template + * @return Mono with the value if the index template exists. + * @since 5.1 + */ + default Mono existsIndexTemplate(String indexTemplateName) { + return existsIndexTemplate(new ExistsIndexTemplateRequest(indexTemplateName)); + } + + /** + * Checks if an index template exists. + * + * @param existsIndexTemplateRequest the parameters for the request + * @return Mono with the value if the index template exists. + * @since 5.1 + */ + Mono existsIndexTemplate(ExistsIndexTemplateRequest existsIndexTemplateRequest); + + /** + * Get index template(s). + * + * @param indexTemplateName the name of the index template + * @return a {@link Flux} of {@link TemplateResponse} + * @since 5.1 + */ + default Flux getIndexTemplate(String indexTemplateName) { + return getIndexTemplate(new GetIndexTemplateRequest(indexTemplateName)); + } + + /** + * Get index template(s). + * + * @param getIndexTemplateRequest + * @return a {@link Flux} of {@link TemplateResponse} + * @since 5.1 + */ + Flux getIndexTemplate(GetIndexTemplateRequest getIndexTemplateRequest); + + /** + * Deletes an index template. + * + * @param indexTemplateName the name of the index template + * @return Mono with the value if the request was acknowledged. + * @since 5.1 + */ + default Mono deleteIndexTemplate(String indexTemplateName) { + return deleteIndexTemplate(new DeleteIndexTemplateRequest(indexTemplateName)); + } + + /** + * Deletes an index template. + * + * @param deleteIndexTemplateRequest the parameters for the request + * @return Mono with the value if the request was acknowledged. + * @since 5.1 + */ + Mono deleteIndexTemplate(DeleteIndexTemplateRequest deleteIndexTemplateRequest); + /** * gets an index template using the legacy Elasticsearch interface. * * @param templateName the template name * @return Mono of TemplateData, {@literal Mono.empty()} if no template with the given name exists. * @since 4.1 + * @deprecated since 5.1, as the underlying Elasticsearch API is deprecated. */ + @Deprecated default Mono getTemplate(String templateName) { return getTemplate(new GetTemplateRequest(templateName)); } @@ -246,7 +348,9 @@ public interface ReactiveIndexOperations { * @param getTemplateRequest the request parameters * @return Mono of TemplateData, {@literal Mono.empty()} if no template with the given name exists. * @since 4.1 + * @deprecated since 5.1, as the underlying Elasticsearch API is deprecated. */ + @Deprecated Mono getTemplate(GetTemplateRequest getTemplateRequest); /** @@ -256,7 +360,9 @@ public interface ReactiveIndexOperations { * @param templateName the template name * @return Mono of {@literal true} if the template exists * @since 4.1 + * @deprecated since 5.1, as the underlying Elasticsearch API is deprecated. */ + @Deprecated default Mono existsTemplate(String templateName) { return existsTemplate(new ExistsTemplateRequest(templateName)); } @@ -268,7 +374,9 @@ public interface ReactiveIndexOperations { * @param existsTemplateRequest template request parameters * @return Mono of {@literal true} if the template exists * @since 4.1 + * @deprecated since 5.1, as the underlying Elasticsearch API is deprecated. */ + @Deprecated Mono existsTemplate(ExistsTemplateRequest existsTemplateRequest); /** @@ -278,7 +386,9 @@ public interface ReactiveIndexOperations { * @param templateName the template name * @return Mono of {@literal true} if the template could be deleted * @since 4.1 + * @deprecated since 5.1, as the underlying Elasticsearch API is deprecated. */ + @Deprecated default Mono deleteTemplate(String templateName) { return deleteTemplate(new DeleteTemplateRequest(templateName)); } @@ -290,7 +400,9 @@ public interface ReactiveIndexOperations { * @param deleteTemplateRequest template request parameters * @return Mono of {@literal true} if the template could be deleted * @since 4.1 + * @deprecated since 5.1, as the underlying Elasticsearch API is deprecated. */ + @Deprecated Mono deleteTemplate(DeleteTemplateRequest deleteTemplateRequest); // endregion diff --git a/src/main/java/org/springframework/data/elasticsearch/client/erhlc/ReactiveClusterOperations.java b/src/main/java/org/springframework/data/elasticsearch/core/cluster/ReactiveClusterOperations.java similarity index 84% rename from src/main/java/org/springframework/data/elasticsearch/client/erhlc/ReactiveClusterOperations.java rename to src/main/java/org/springframework/data/elasticsearch/core/cluster/ReactiveClusterOperations.java index 04927a71d..03108f629 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/erhlc/ReactiveClusterOperations.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/cluster/ReactiveClusterOperations.java @@ -13,20 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.elasticsearch.client.erhlc; +package org.springframework.data.elasticsearch.core.cluster; import reactor.core.publisher.Mono; -import org.springframework.data.elasticsearch.core.cluster.ClusterHealth; - /** * Reactive Elasticsearch operations on cluster level. * * @author Peter-Josef Meisch * @since 4.2 - * @deprecated since 5.0 */ -@Deprecated public interface ReactiveClusterOperations { /** diff --git a/src/main/java/org/springframework/data/elasticsearch/core/index/ComponentTemplateRequestData.java b/src/main/java/org/springframework/data/elasticsearch/core/index/ComponentTemplateRequestData.java new file mode 100644 index 000000000..ca0ab6d41 --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/core/index/ComponentTemplateRequestData.java @@ -0,0 +1,71 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed 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 + * + * https://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.springframework.data.elasticsearch.core.index; + +import java.util.Map; + +import org.springframework.data.elasticsearch.core.document.Document; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; + +/** + * A component template to be used in a component template request. + * + * @author Peter-Josef Meisch + * @since 5.1 + */ +public record ComponentTemplateRequestData(@Nullable Settings settings, @Nullable Document mapping, + @Nullable AliasActions aliasActions, @Nullable Boolean allowAutoCreate) { + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + @Nullable private Settings settings; + @Nullable private Document mapping; + @Nullable private AliasActions aliasActions; + @Nullable private Boolean allowAutoCreate; + + public Builder withSettings(Map settings) { + this.settings = new Settings(settings); + return this; + } + + public Builder withMapping(Document mapping) { + this.mapping = mapping; + return this; + } + + public Builder withAliasActions(AliasActions aliasActions) { + + aliasActions.getActions().forEach(action -> Assert.isTrue(action instanceof AliasAction.Add, + "only alias add actions are allowed in templates")); + + this.aliasActions = aliasActions; + return this; + } + + public Builder withAllowAutoCreate(@Nullable Boolean allowAutoCreate) { + this.allowAutoCreate = allowAutoCreate; + return this; + } + + public ComponentTemplateRequestData build() { + return new ComponentTemplateRequestData(settings, mapping, aliasActions, allowAutoCreate); + } + } +} diff --git a/src/main/java/org/springframework/data/elasticsearch/core/index/DeleteComponentTemplateRequest.java b/src/main/java/org/springframework/data/elasticsearch/core/index/DeleteComponentTemplateRequest.java new file mode 100644 index 000000000..a1d4b94a9 --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/core/index/DeleteComponentTemplateRequest.java @@ -0,0 +1,28 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed 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 + * + * https://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.springframework.data.elasticsearch.core.index; + +import org.springframework.util.Assert; + +/** + * @author Peter-Josef Meisch + * @since 5.1 + */ +public record DeleteComponentTemplateRequest(String templateName) { + public DeleteComponentTemplateRequest { + Assert.notNull(templateName, "templateName must not be null"); + } +} diff --git a/src/main/java/org/springframework/data/elasticsearch/core/index/DeleteIndexTemplateRequest.java b/src/main/java/org/springframework/data/elasticsearch/core/index/DeleteIndexTemplateRequest.java new file mode 100644 index 000000000..866e60c97 --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/core/index/DeleteIndexTemplateRequest.java @@ -0,0 +1,28 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed 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 + * + * https://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.springframework.data.elasticsearch.core.index; + +import org.springframework.util.Assert; + +/** + * @author Peter-Josef Meisch + * @since 5.1 + */ +public record DeleteIndexTemplateRequest(String templateName) { + public DeleteIndexTemplateRequest { + Assert.notNull(templateName, "templateName must not be null"); + } +} diff --git a/src/main/java/org/springframework/data/elasticsearch/core/index/ExistsComponentTemplateRequest.java b/src/main/java/org/springframework/data/elasticsearch/core/index/ExistsComponentTemplateRequest.java new file mode 100644 index 000000000..fee29bf7f --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/core/index/ExistsComponentTemplateRequest.java @@ -0,0 +1,28 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed 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 + * + * https://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.springframework.data.elasticsearch.core.index; + +import org.springframework.util.Assert; + +/** + * @author Peter-Josef Meisch + * @since 5.1 + */ +public record ExistsComponentTemplateRequest(String templateName) { + public ExistsComponentTemplateRequest { + Assert.notNull(templateName, "templateName must not be null"); + } +} diff --git a/src/main/java/org/springframework/data/elasticsearch/core/index/ExistsIndexTemplateRequest.java b/src/main/java/org/springframework/data/elasticsearch/core/index/ExistsIndexTemplateRequest.java new file mode 100644 index 000000000..f20dbfa1e --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/core/index/ExistsIndexTemplateRequest.java @@ -0,0 +1,28 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed 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 + * + * https://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.springframework.data.elasticsearch.core.index; + +import org.springframework.util.Assert; + +/** + * @author Peter-Josef Meisch + * @since 5.1 + */ +public record ExistsIndexTemplateRequest(String templateName) { + public ExistsIndexTemplateRequest { + Assert.notNull(templateName, "templateName must not be null"); + } +} diff --git a/src/main/java/org/springframework/data/elasticsearch/core/index/GetComponentTemplateRequest.java b/src/main/java/org/springframework/data/elasticsearch/core/index/GetComponentTemplateRequest.java new file mode 100644 index 000000000..a737c38ff --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/core/index/GetComponentTemplateRequest.java @@ -0,0 +1,28 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed 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 + * + * https://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.springframework.data.elasticsearch.core.index; + +import org.springframework.util.Assert; + +/** + * @author Peter-Josef Meisch + * @since 5.1 + */ +public record GetComponentTemplateRequest(String templateName) { + public GetComponentTemplateRequest { + Assert.notNull(templateName, "templateName must not be null"); + } +} diff --git a/src/main/java/org/springframework/data/elasticsearch/core/index/GetIndexTemplateRequest.java b/src/main/java/org/springframework/data/elasticsearch/core/index/GetIndexTemplateRequest.java new file mode 100644 index 000000000..08fb51bd6 --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/core/index/GetIndexTemplateRequest.java @@ -0,0 +1,28 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed 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 + * + * https://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.springframework.data.elasticsearch.core.index; + +import org.springframework.util.Assert; + +/** + * @author Peter-Josef Meisch + * @since 5.1 + */ +public record GetIndexTemplateRequest(String templateName) { + public GetIndexTemplateRequest { + Assert.notNull(templateName, "templateName must not be null"); + } +} diff --git a/src/main/java/org/springframework/data/elasticsearch/core/index/PutComponentTemplateRequest.java b/src/main/java/org/springframework/data/elasticsearch/core/index/PutComponentTemplateRequest.java new file mode 100644 index 000000000..8fdbf409c --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/core/index/PutComponentTemplateRequest.java @@ -0,0 +1,78 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed 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 + * + * https://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.springframework.data.elasticsearch.core.index; + +import java.time.Duration; + +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; + +/** + * @author Peter-Josef Meisch + * @since 5.1 + */ +public record PutComponentTemplateRequest(String name, @Nullable Long version, @Nullable Boolean create, + @Nullable Duration masterTimeout, ComponentTemplateRequestData template) { + public PutComponentTemplateRequest { + Assert.notNull(name, "name must not be null"); + Assert.notNull(template, "template must not be null"); + } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + @Nullable private String name; + @Nullable private Long version; + @Nullable private Boolean create; + @Nullable private Duration masterTimeout; + @Nullable private ComponentTemplateRequestData template; + + public Builder withName(String name) { + this.name = name; + return this; + } + + public Builder withVersion(Long version) { + this.version = version; + return this; + } + + public Builder withCreate(Boolean create) { + this.create = create; + return this; + } + + public Builder withMasterTimeout(Duration masterTimeout) { + this.masterTimeout = masterTimeout; + return this; + } + + public Builder withTemplateData(ComponentTemplateRequestData template) { + this.template = template; + return this; + } + + public PutComponentTemplateRequest build() { + + Assert.notNull(name, "name must not be null"); + Assert.notNull(template, "template must not be null"); + + return new PutComponentTemplateRequest(name, version, create, masterTimeout, template); + } + } +} diff --git a/src/main/java/org/springframework/data/elasticsearch/core/index/PutIndexTemplateRequest.java b/src/main/java/org/springframework/data/elasticsearch/core/index/PutIndexTemplateRequest.java new file mode 100644 index 000000000..0783c050d --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/core/index/PutIndexTemplateRequest.java @@ -0,0 +1,85 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed 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 + * + * https://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.springframework.data.elasticsearch.core.index; + +import java.util.List; + +import org.springframework.data.elasticsearch.core.document.Document; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; + +/** + * @author Peter-Josef Meisch + * @since 5.1 + */ +public record PutIndexTemplateRequest(String name, String[] indexPatterns, @Nullable Settings settings, + @Nullable Document mapping, @Nullable AliasActions aliasActions, List composedOf) { + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + @Nullable private String name; + @Nullable private String[] indexPatterns; + @Nullable private Settings settings; + @Nullable private Document mapping; + @Nullable AliasActions aliasActions; + + @Nullable List composedOf; + + public Builder withName(String name) { + this.name = name; + return this; + } + + public Builder withIndexPatterns(String... indexPatterns) { + this.indexPatterns = indexPatterns; + return this; + } + + public Builder withSettings(Settings settings) { + this.settings = settings; + return this; + } + + public Builder withMapping(Document mapping) { + this.mapping = mapping; + return this; + } + + public Builder withAliasActions(AliasActions aliasActions) { + this.aliasActions = aliasActions; + return this; + } + + public Builder withComposedOf(List composedOf) { + this.composedOf = composedOf; + return this; + } + + public PutIndexTemplateRequest build() { + + Assert.notNull(name, "name must not be null"); + Assert.notNull(indexPatterns, "indexPatterns must not be null"); + Assert.isTrue(indexPatterns.length > 0, "indexPatterns must not be empty"); + + return new PutIndexTemplateRequest(name, indexPatterns, settings, mapping, aliasActions, + composedOf != null ? composedOf : List.of()); + } + } +} diff --git a/src/main/java/org/springframework/data/elasticsearch/core/index/TemplateResponse.java b/src/main/java/org/springframework/data/elasticsearch/core/index/TemplateResponse.java new file mode 100644 index 000000000..0ed58e4f7 --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/core/index/TemplateResponse.java @@ -0,0 +1,59 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed 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 + * + * https://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.springframework.data.elasticsearch.core.index; + +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; + +/** + * @author Peter-Josef Meisch + * @since 5.1 + */ +public record TemplateResponse(String name, @Nullable Long version, @Nullable TemplateResponseData templateData) { + public TemplateResponse { + Assert.notNull(name, "name must not be null"); + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + + @Nullable private String name; + @Nullable private Long version; + @Nullable private TemplateResponseData templateData; + + public Builder withName(String name) { + this.name = name; + return this; + } + + public Builder withVersion(Long version) { + this.version = version; + return this; + } + + public Builder withTemplateData(TemplateResponseData templateData) { + this.templateData = templateData; + return this; + } + + public TemplateResponse build() { + return new TemplateResponse(name, version, templateData); + } + } +} diff --git a/src/main/java/org/springframework/data/elasticsearch/core/index/TemplateResponseData.java b/src/main/java/org/springframework/data/elasticsearch/core/index/TemplateResponseData.java new file mode 100644 index 000000000..925a6f59c --- /dev/null +++ b/src/main/java/org/springframework/data/elasticsearch/core/index/TemplateResponseData.java @@ -0,0 +1,72 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed 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 + * + * https://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.springframework.data.elasticsearch.core.index; + +import java.util.List; +import java.util.Map; + +import org.springframework.data.elasticsearch.core.document.Document; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; + +/** + * @author Peter-Josef Meisch + * @since 5.1 + */ +public record TemplateResponseData(@Nullable Document mapping, @Nullable Settings settings, + Map aliases, List composedOf) { + + public TemplateResponseData { + Assert.notNull(aliases, "aliases must not be null"); + } + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + @Nullable private Document mapping; + @Nullable private Settings settings; + @Nullable private Map aliases; + + @Nullable private List composedOf; + + public Builder withMapping(@Nullable Document mapping) { + this.mapping = mapping; + return this; + } + + public Builder withSettings(@Nullable Settings settings) { + this.settings = settings; + return this; + } + + public Builder withAliases(@Nullable Map aliases) { + this.aliases = aliases; + return this; + } + + public Builder withComposedOf(@Nullable List composedOf) { + this.composedOf = composedOf; + return this; + } + + public TemplateResponseData build() { + return new TemplateResponseData(mapping, settings, aliases != null ? aliases : Map.of(), + composedOf != null ? composedOf : List.of()); + } + } +} diff --git a/src/main/java/org/springframework/data/elasticsearch/repository/query/AbstractElasticsearchRepositoryQuery.java b/src/main/java/org/springframework/data/elasticsearch/repository/query/AbstractElasticsearchRepositoryQuery.java index 722b7b18f..2c417e9ef 100644 --- a/src/main/java/org/springframework/data/elasticsearch/repository/query/AbstractElasticsearchRepositoryQuery.java +++ b/src/main/java/org/springframework/data/elasticsearch/repository/query/AbstractElasticsearchRepositoryQuery.java @@ -15,6 +15,8 @@ */ package org.springframework.data.elasticsearch.repository.query; +import java.util.Collections; + import org.springframework.data.domain.PageRequest; import org.springframework.data.elasticsearch.core.ElasticsearchOperations; import org.springframework.data.elasticsearch.core.SearchHitSupport; @@ -32,8 +34,6 @@ import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; -import java.util.Collections; - /** * AbstractElasticsearchRepositoryQuery * @@ -100,7 +100,7 @@ public abstract class AbstractElasticsearchRepositoryQuery implements Repository } } else if (queryMethod.isStreamQuery()) { query.setPageable(parameterAccessor.getPageable().isPaged() ? parameterAccessor.getPageable() - : PageRequest.of(0, DEFAULT_STREAM_BATCH_SIZE)); + : PageRequest.of(0, DEFAULT_STREAM_BATCH_SIZE)); result = StreamUtils.createStreamFromIterator(elasticsearchOperations.searchForStream(query, clazz, index)); } else if (queryMethod.isCollectionQuery()) { @@ -109,7 +109,7 @@ public abstract class AbstractElasticsearchRepositoryQuery implements Repository if (itemCount == 0) { result = new SearchHitsImpl<>(0, TotalHitsRelation.EQUAL_TO, Float.NaN, null, - query.getPointInTime() != null ? query.getPointInTime().id() : null, Collections.emptyList(), null, null); + query.getPointInTime() != null ? query.getPointInTime().id() : null, Collections.emptyList(), null, null); } else { query.setPageable(PageRequest.of(0, Math.max(1, itemCount))); } @@ -126,8 +126,8 @@ public abstract class AbstractElasticsearchRepositoryQuery implements Repository } return (queryMethod.isNotSearchHitMethod() && queryMethod.isNotSearchPageMethod()) - ? SearchHitSupport.unwrapSearchHits(result) - : result; + ? SearchHitSupport.unwrapSearchHits(result) + : result; } public Query createQuery(Object[] parameters) { @@ -148,9 +148,6 @@ public abstract class AbstractElasticsearchRepositoryQuery implements Repository query.addSourceFilter(sourceFilter); } - // todo #2338 remove that call, this should be done when the real request is built -// elasticsearchConverter.updateQuery(query, clazz); - return query; } diff --git a/src/test/java/org/springframework/data/elasticsearch/client/elc/DocumentAdaptersUnitTests.java b/src/test/java/org/springframework/data/elasticsearch/client/elc/DocumentAdaptersUnitTests.java index 7889b8f48..37f800ad8 100644 --- a/src/test/java/org/springframework/data/elasticsearch/client/elc/DocumentAdaptersUnitTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/client/elc/DocumentAdaptersUnitTests.java @@ -35,7 +35,6 @@ import org.springframework.data.elasticsearch.core.document.SearchDocument; * @author Peter-Josef Meisch * @since 4.4 */ -// todo #1973 check that all is tested what was in the elasticsearch7 version class DocumentAdaptersUnitTests { private final JsonpMapper jsonpMapper = new JacksonJsonpMapper(); diff --git a/src/test/java/org/springframework/data/elasticsearch/client/elc/ReactiveIndicesTemplateTest.java b/src/test/java/org/springframework/data/elasticsearch/client/elc/ReactiveIndicesTemplateTest.java index 779d9783e..3a63cb109 100644 --- a/src/test/java/org/springframework/data/elasticsearch/client/elc/ReactiveIndicesTemplateTest.java +++ b/src/test/java/org/springframework/data/elasticsearch/client/elc/ReactiveIndicesTemplateTest.java @@ -15,9 +15,17 @@ */ package org.springframework.data.elasticsearch.client.elc; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + import co.elastic.clients.elasticsearch.indices.RefreshRequest; import co.elastic.clients.json.JsonpMapper; import co.elastic.clients.transport.ElasticsearchTransport; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.util.List; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -27,13 +35,6 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter; import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; -import reactor.core.publisher.Mono; -import reactor.test.StepVerifier; - -import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.*; /** * @author Urs Keller @@ -43,6 +44,7 @@ import static org.mockito.Mockito.*; class ReactiveIndicesTemplateTest { @Mock private ElasticsearchConverter elasticsearchConverter; @Mock private ReactiveElasticsearchIndicesClient client; + @Mock private ReactiveClusterTemplate cluster; @Mock private ElasticsearchTransport transport; @Mock private JsonpMapper jsonpMapper; @Captor ArgumentCaptor refreshRequest; @@ -59,7 +61,8 @@ class ReactiveIndicesTemplateTest { @Test void refresh() { IndexCoordinates indexCoordinate = IndexCoordinates.of("i1", "i2"); - ReactiveIndicesTemplate template = new ReactiveIndicesTemplate(client, elasticsearchConverter, indexCoordinate); + ReactiveIndicesTemplate template = new ReactiveIndicesTemplate(client, cluster, elasticsearchConverter, + indexCoordinate); doReturn(Mono.empty()).when(client).refresh(any(RefreshRequest.class)); template.refresh().as(StepVerifier::create).verifyComplete(); diff --git a/src/test/java/org/springframework/data/elasticsearch/core/cluster/ClusterOperationsReactiveIntegrationTests.java b/src/test/java/org/springframework/data/elasticsearch/core/cluster/ClusterOperationsReactiveIntegrationTests.java index 2245d7a1b..a189302e1 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/cluster/ClusterOperationsReactiveIntegrationTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/cluster/ClusterOperationsReactiveIntegrationTests.java @@ -26,7 +26,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.elasticsearch.client.erhlc.ReactiveClusterOperations; import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations; import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest; diff --git a/src/test/java/org/springframework/data/elasticsearch/core/indices/IndexOperationsELCIntegrationTests.java b/src/test/java/org/springframework/data/elasticsearch/core/index/IndexOperationsELCIntegrationTests.java similarity index 95% rename from src/test/java/org/springframework/data/elasticsearch/core/indices/IndexOperationsELCIntegrationTests.java rename to src/test/java/org/springframework/data/elasticsearch/core/index/IndexOperationsELCIntegrationTests.java index e110179c2..01d5ba293 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/indices/IndexOperationsELCIntegrationTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/index/IndexOperationsELCIntegrationTests.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.elasticsearch.core.indices; +package org.springframework.data.elasticsearch.core.index; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/src/test/java/org/springframework/data/elasticsearch/core/indices/IndexOperationsERHLCIntegrationTests.java b/src/test/java/org/springframework/data/elasticsearch/core/index/IndexOperationsERHLCIntegrationTests.java similarity index 95% rename from src/test/java/org/springframework/data/elasticsearch/core/indices/IndexOperationsERHLCIntegrationTests.java rename to src/test/java/org/springframework/data/elasticsearch/core/index/IndexOperationsERHLCIntegrationTests.java index feb1f73ba..5571c05b8 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/indices/IndexOperationsERHLCIntegrationTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/index/IndexOperationsERHLCIntegrationTests.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.elasticsearch.core.indices; +package org.springframework.data.elasticsearch.core.index; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/src/test/java/org/springframework/data/elasticsearch/core/indices/IndexOperationsIntegrationTests.java b/src/test/java/org/springframework/data/elasticsearch/core/index/IndexOperationsIntegrationTests.java similarity index 94% rename from src/test/java/org/springframework/data/elasticsearch/core/indices/IndexOperationsIntegrationTests.java rename to src/test/java/org/springframework/data/elasticsearch/core/index/IndexOperationsIntegrationTests.java index 8063e6747..0ef035815 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/indices/IndexOperationsIntegrationTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/index/IndexOperationsIntegrationTests.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.elasticsearch.core.indices; +package org.springframework.data.elasticsearch.core.index; -import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThat; import java.util.List; import java.util.Map; @@ -36,11 +36,6 @@ import org.springframework.data.elasticsearch.annotations.Setting; import org.springframework.data.elasticsearch.core.ElasticsearchOperations; import org.springframework.data.elasticsearch.core.IndexInformation; import org.springframework.data.elasticsearch.core.IndexOperations; -import org.springframework.data.elasticsearch.core.index.AliasAction; -import org.springframework.data.elasticsearch.core.index.AliasActionParameters; -import org.springframework.data.elasticsearch.core.index.AliasActions; -import org.springframework.data.elasticsearch.core.index.AliasData; -import org.springframework.data.elasticsearch.core.index.Settings; import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest; import org.springframework.data.elasticsearch.utils.IndexNameProvider; diff --git a/src/test/java/org/springframework/data/elasticsearch/core/index/IndexTemplateIntegrationTests.java b/src/test/java/org/springframework/data/elasticsearch/core/index/IndexTemplateIntegrationTests.java index bd66a28f8..8d16126de 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/index/IndexTemplateIntegrationTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/index/IndexTemplateIntegrationTests.java @@ -15,13 +15,15 @@ */ package org.springframework.data.elasticsearch.core.index; -import static org.assertj.core.api.Assertions.assertThat; -import static org.skyscreamer.jsonassert.JSONAssert.assertEquals; +import static org.assertj.core.api.Assertions.*; +import static org.skyscreamer.jsonassert.JSONAssert.*; +import java.util.List; import java.util.Map; import java.util.UUID; import org.json.JSONException; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledIf; import org.springframework.beans.factory.annotation.Autowired; @@ -37,6 +39,7 @@ import org.springframework.data.elasticsearch.core.IndexOperations; import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; import org.springframework.data.elasticsearch.core.query.Criteria; import org.springframework.data.elasticsearch.core.query.CriteriaQuery; +import org.springframework.data.elasticsearch.core.query.Query; import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest; import org.springframework.lang.Nullable; @@ -55,7 +58,7 @@ public abstract class IndexTemplateIntegrationTests implements NewElasticsearchC @DisabledIf(value = "rhlcWithCluster8", disabledReason = "RHLC fails to parse response from ES 8.2") @Test // DATAES-612 - void shouldCreateTemplate() { + void shouldPutTemplate() { IndexOperations indexOps = operations.indexOps(IndexCoordinates.of("dont-care")); @@ -75,6 +78,232 @@ public abstract class IndexTemplateIntegrationTests implements NewElasticsearchC assertThat(acknowledged).isTrue(); } + @DisabledIf(value = "oldElasticsearchClient", disabledReason = "not implemented for the deprecated old client") + @Test // #1458 + @DisplayName("should create component template") + void shouldCreateComponentTemplate() { + + IndexOperations indexOps = operations.indexOps(IndexCoordinates.of("dont-care")); + + org.springframework.data.elasticsearch.core.document.Document mapping = indexOps.createMapping(TemplateClass.class); + Settings settings = indexOps.createSettings(TemplateClass.class); + + AliasActions aliasActions = new AliasActions( // + new AliasAction.Add(AliasActionParameters.builderForTemplate() // + .withAliases("alias1", "alias2") // + .withFilterQuery(Query.findAll()) // + .build())); // + + var putComponentTemplateRequest = PutComponentTemplateRequest.builder() // + .withName("test-component-template") // + .withTemplateData(ComponentTemplateRequestData.builder() // + .withAliasActions(aliasActions) // + .withMapping(mapping) // + .withSettings(settings) // + .build() // + ).build(); + + boolean acknowledged = indexOps.putComponentTemplate(putComponentTemplateRequest); + + assertThat(acknowledged).isTrue(); + } + + @DisabledIf(value = "oldElasticsearchClient", disabledReason = "not implemented for the deprecated old client") + @Test // #1458 + @DisplayName("should get component template") + void shouldGetComponentTemplate() throws JSONException { + IndexOperations indexOps = operations.indexOps(IndexCoordinates.of("dont-care")); + + org.springframework.data.elasticsearch.core.document.Document mapping = indexOps.createMapping(TemplateClass.class); + Settings settings = indexOps.createSettings(TemplateClass.class); + + var filterQuery = CriteriaQuery.builder(Criteria.where("message").is("foo")).build(); + AliasActions aliasActions = new AliasActions(new AliasAction.Add(AliasActionParameters.builderForTemplate() // + .withAliases("alias1", "alias2") // + .withFilterQuery(filterQuery, TemplateClass.class)// + .build())); + + PutComponentTemplateRequest putComponentTemplateRequest = PutComponentTemplateRequest.builder() // + .withName("test-component-template") // + .withVersion(42L) // + .withTemplateData(ComponentTemplateRequestData.builder() // + .withSettings(settings) // + .withMapping(mapping) // + .withAliasActions(aliasActions) // + .build()) // + .build(); + + boolean acknowledged = indexOps.putComponentTemplate(putComponentTemplateRequest); + assertThat(acknowledged).isTrue(); + + GetComponentTemplateRequest getComponentTemplateRequest = new GetComponentTemplateRequest( + putComponentTemplateRequest.name()); + var componentTemplates = indexOps.getComponentTemplate(getComponentTemplateRequest); + + assertThat(componentTemplates).isNotNull().hasSize(1); + var returnedComponentTemplate = componentTemplates.iterator().next(); + assertThat(returnedComponentTemplate.version()).isEqualTo(putComponentTemplateRequest.version()); + var componentTemplateData = returnedComponentTemplate.templateData(); + + assertEquals(mapping.toJson(), componentTemplateData.mapping().toJson(), false); + assertEquals(settings.flatten().toJson(), componentTemplateData.settings().flatten().toJson(), false); + var aliases = componentTemplateData.aliases(); + assertThat(aliases).hasSize(2); + AliasData alias1 = aliases.get("alias1"); + assertThat(alias1.getAlias()).isEqualTo("alias1"); + assertThat(alias1.getFilterQuery()).isNotNull(); + AliasData alias2 = aliases.get("alias2"); + assertThat(alias2.getFilterQuery()).isNotNull(); + assertThat(alias2.getAlias()).isEqualTo("alias2"); + } + + @DisabledIf(value = "oldElasticsearchClient", disabledReason = "not implemented for the deprecated old client") + @Test // #1458 + @DisplayName("should delete component template") + void shouldDeleteComponentTemplate() { + + IndexOperations indexOps = operations.indexOps(IndexCoordinates.of("dont-care")); + String templateName = "template" + UUID.randomUUID().toString(); + var putComponentTemplateRequest = PutComponentTemplateRequest.builder() // + .withName(templateName) // + .withTemplateData(ComponentTemplateRequestData.builder() // + .withSettings(indexOps.createSettings(TemplateClass.class)) // + .build() // + ).build(); + ExistsComponentTemplateRequest existsComponentTemplateRequest = new ExistsComponentTemplateRequest(templateName); + + boolean acknowledged = indexOps.putComponentTemplate(putComponentTemplateRequest); + assertThat(acknowledged).isTrue(); + + boolean exists = indexOps.existsComponentTemplate(existsComponentTemplateRequest); + assertThat(exists).isTrue(); + + acknowledged = indexOps.deleteComponentTemplate(new DeleteComponentTemplateRequest(templateName)); + assertThat(acknowledged).isTrue(); + + exists = indexOps.existsComponentTemplate(existsComponentTemplateRequest); + assertThat(exists).isFalse(); + } + + @DisabledIf(value = "oldElasticsearchClient", disabledReason = "not implemented for the deprecated old client") + @Test // #1458 + @DisplayName("should put, get and delete index template with template") + void shouldPutGetAndDeleteIndexTemplateWithTemplate() { + + IndexOperations indexOps = operations.indexOps(IndexCoordinates.of("dont-care")); + org.springframework.data.elasticsearch.core.document.Document mapping = indexOps.createMapping(TemplateClass.class); + Settings settings = indexOps.createSettings(TemplateClass.class); + + AliasActions aliasActions = new AliasActions( // + new AliasAction.Add(AliasActionParameters.builderForTemplate() // + .withAliases("alias1", "alias2") // + .withFilterQuery(Query.findAll()) // + .build())); // + var indexTemplateName = "test-index-template"; + var putIndexTemplateRequest = PutIndexTemplateRequest.builder() // + .withName(indexTemplateName) // + .withIndexPatterns("index-*", "endix-*") // + .withSettings(settings) // + .withMapping(mapping) // + .withAliasActions(aliasActions) // + .build(); + + boolean acknowledged = indexOps.putIndexTemplate(putIndexTemplateRequest); + assertThat(acknowledged).isTrue(); + + var exists = indexOps.existsIndexTemplate(indexTemplateName); + assertThat(exists).isTrue(); + + var indexTemplates = indexOps.getIndexTemplate(indexTemplateName); + assertThat(indexTemplates).hasSize(1); + + // delete template + acknowledged = indexOps.deleteIndexTemplate(indexTemplateName); + assertThat(acknowledged).isTrue(); + + exists = indexOps.existsIndexTemplate(indexTemplateName); + assertThat(exists).isFalse(); + } + + @DisabledIf(value = "oldElasticsearchClient", disabledReason = "not implemented for the deprecated old client") + @Test // #1458 + @DisplayName("should put, get and delete index template of components") + void shouldPutGetAndDeleteIndexTemplateOfComponents() { + + IndexOperations indexOps = operations.indexOps(IndexCoordinates.of("dont-care")); + + org.springframework.data.elasticsearch.core.document.Document mapping = indexOps.createMapping(TemplateClass.class); + Settings settings = indexOps.createSettings(TemplateClass.class); + + var filterQuery = CriteriaQuery.builder(Criteria.where("message").is("foo")).build(); + AliasActions aliasActions = new AliasActions(new AliasAction.Add(AliasActionParameters.builderForTemplate() // + .withAliases("alias1", "alias2") // + .withFilterQuery(filterQuery, TemplateClass.class)// + .build())); + + PutComponentTemplateRequest putComponentTemplateRequestMapping = PutComponentTemplateRequest.builder() // + .withName("test-component-template-mapping") // + .withVersion(42L) // + .withTemplateData(ComponentTemplateRequestData.builder() // + .withMapping(mapping) // + .build()) // + .build(); + + boolean acknowledged = indexOps.putComponentTemplate(putComponentTemplateRequestMapping); + assertThat(acknowledged).isTrue(); + + PutComponentTemplateRequest putComponentTemplateRequestSettings = PutComponentTemplateRequest.builder() // + .withName("test-component-template-settings") // + .withVersion(42L) // + .withTemplateData(ComponentTemplateRequestData.builder() // + .withSettings(settings) // + .build()) // + .build(); + + acknowledged = indexOps.putComponentTemplate(putComponentTemplateRequestSettings); + assertThat(acknowledged).isTrue(); + + PutComponentTemplateRequest putComponentTemplateRequestAliases = PutComponentTemplateRequest.builder() // + .withName("test-component-template-aliases") // + .withVersion(42L) // + .withTemplateData(ComponentTemplateRequestData.builder() // + .withAliasActions(aliasActions) // + .build()) // + .build(); + + acknowledged = indexOps.putComponentTemplate(putComponentTemplateRequestAliases); + assertThat(acknowledged).isTrue(); + + var indexTemplateName = "test-index-template"; + var composedOf = List.of("test-component-template-mapping", "test-component-template-settings", + "test-component-template-aliases"); + var putIndexTemplateRequest = PutIndexTemplateRequest.builder() // + .withName(indexTemplateName) // + .withIndexPatterns("index-*", "endix-*") // + .withComposedOf(composedOf) // + .build(); + + acknowledged = indexOps.putIndexTemplate(putIndexTemplateRequest); + assertThat(acknowledged).isTrue(); + + var indexTemplates = indexOps.getIndexTemplate(indexTemplateName); + assertThat(indexTemplates).hasSize(1); + assertThat(indexTemplates.get(0).templateData().composedOf()).isEqualTo(composedOf); + + // delete template and components + acknowledged = indexOps.deleteIndexTemplate(indexTemplateName); + assertThat(acknowledged).isTrue(); + acknowledged = indexOps + .deleteComponentTemplate(new DeleteComponentTemplateRequest("test-component-template-mapping")); + assertThat(acknowledged).isTrue(); + acknowledged = indexOps + .deleteComponentTemplate(new DeleteComponentTemplateRequest("test-component-template-settings")); + assertThat(acknowledged).isTrue(); + acknowledged = indexOps + .deleteComponentTemplate(new DeleteComponentTemplateRequest("test-component-template-aliases")); + assertThat(acknowledged).isTrue(); + } + @Test // DATAES-612 void shouldReturnNullOnNonExistingGetTemplate() { @@ -177,7 +406,6 @@ public abstract class IndexTemplateIntegrationTests implements NewElasticsearchC exists = indexOps.existsTemplate(existsTemplateRequest); assertThat(exists).isFalse(); - } @Document(indexName = "test-template") diff --git a/src/test/java/org/springframework/data/elasticsearch/core/indices/ReactiveIndexOperationsELCIntegrationTests.java b/src/test/java/org/springframework/data/elasticsearch/core/index/ReactiveIndexOperationsELCIntegrationTests.java similarity index 96% rename from src/test/java/org/springframework/data/elasticsearch/core/indices/ReactiveIndexOperationsELCIntegrationTests.java rename to src/test/java/org/springframework/data/elasticsearch/core/index/ReactiveIndexOperationsELCIntegrationTests.java index 2d98fd27d..7a460bba4 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/indices/ReactiveIndexOperationsELCIntegrationTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/index/ReactiveIndexOperationsELCIntegrationTests.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.elasticsearch.core.indices; +package org.springframework.data.elasticsearch.core.index; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/src/test/java/org/springframework/data/elasticsearch/core/indices/ReactiveIndexOperationsERHLCIntegrationTests.java b/src/test/java/org/springframework/data/elasticsearch/core/index/ReactiveIndexOperationsERHLCIntegrationTests.java similarity index 96% rename from src/test/java/org/springframework/data/elasticsearch/core/indices/ReactiveIndexOperationsERHLCIntegrationTests.java rename to src/test/java/org/springframework/data/elasticsearch/core/index/ReactiveIndexOperationsERHLCIntegrationTests.java index 90650e75c..23e0bedd8 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/indices/ReactiveIndexOperationsERHLCIntegrationTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/index/ReactiveIndexOperationsERHLCIntegrationTests.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.elasticsearch.core.indices; +package org.springframework.data.elasticsearch.core.index; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/src/test/java/org/springframework/data/elasticsearch/core/indices/ReactiveIndexOperationsIntegrationTests.java b/src/test/java/org/springframework/data/elasticsearch/core/index/ReactiveIndexOperationsIntegrationTests.java similarity index 65% rename from src/test/java/org/springframework/data/elasticsearch/core/indices/ReactiveIndexOperationsIntegrationTests.java rename to src/test/java/org/springframework/data/elasticsearch/core/index/ReactiveIndexOperationsIntegrationTests.java index a302422b7..17385558a 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/indices/ReactiveIndexOperationsIntegrationTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/index/ReactiveIndexOperationsIntegrationTests.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.elasticsearch.core.indices; +package org.springframework.data.elasticsearch.core.index; import static org.assertj.core.api.Assertions.*; import static org.skyscreamer.jsonassert.JSONAssert.*; @@ -22,16 +22,12 @@ import reactor.core.publisher.Mono; import reactor.test.StepVerifier; import java.time.LocalDate; -import java.util.Map; import java.util.Set; -import java.util.UUID; -import org.assertj.core.api.SoftAssertions; import org.json.JSONException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.DisabledIf; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.annotation.Id; import org.springframework.data.elasticsearch.NewElasticsearchClientDevelopment; @@ -44,16 +40,6 @@ import org.springframework.data.elasticsearch.annotations.Setting; import org.springframework.data.elasticsearch.core.AbstractReactiveElasticsearchTemplate; import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations; import org.springframework.data.elasticsearch.core.ReactiveIndexOperations; -import org.springframework.data.elasticsearch.core.index.AliasAction; -import org.springframework.data.elasticsearch.core.index.AliasActionParameters; -import org.springframework.data.elasticsearch.core.index.AliasActions; -import org.springframework.data.elasticsearch.core.index.AliasData; -import org.springframework.data.elasticsearch.core.index.DeleteTemplateRequest; -import org.springframework.data.elasticsearch.core.index.ExistsTemplateRequest; -import org.springframework.data.elasticsearch.core.index.GetTemplateRequest; -import org.springframework.data.elasticsearch.core.index.PutTemplateRequest; -import org.springframework.data.elasticsearch.core.index.Settings; -import org.springframework.data.elasticsearch.core.index.TemplateData; import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest; import org.springframework.data.elasticsearch.utils.IndexNameProvider; @@ -376,124 +362,6 @@ public abstract class ReactiveIndexOperationsIntegrationTests implements NewElas .verifyComplete(); } - @DisabledIf(value = "rhlcWithCluster8", disabledReason = "RHLC fails to parse response from ES 8.2") - @Test // DATAES-612 - void shouldPutTemplate() { - - org.springframework.data.elasticsearch.core.document.Document mapping = indexOperations - .createMapping(TemplateClass.class).block(); - Settings settings = indexOperations.createSettings(TemplateClass.class).block(); - - AliasActions aliasActions = new AliasActions( - new AliasAction.Add(AliasActionParameters.builderForTemplate().withAliases("alias1", "alias2").build())); - PutTemplateRequest putTemplateRequest = PutTemplateRequest.builder("test-template", "log-*") // - .withSettings(settings) // - .withMappings(mapping) // - .withAliasActions(aliasActions) // - .withOrder(11) // - .withVersion(42) // - .build(); - - Boolean acknowledged = indexOperations.putTemplate(putTemplateRequest).block(); - assertThat(acknowledged).isTrue(); - } - - @Test // DATAES-612 - void shouldReturnNullOnNonExistingGetTemplate() { - - String templateName = "template" + UUID.randomUUID().toString(); - - GetTemplateRequest getTemplateRequest = new GetTemplateRequest(templateName); - indexOperations.getTemplate(getTemplateRequest) // - .as(StepVerifier::create) // - .verifyComplete(); - } - - @DisabledIf(value = "rhlcWithCluster8", disabledReason = "RHLC fails to parse response from ES 8.2") - @Test // DATAES-612 - void shouldGetTemplate() throws JSONException { - - org.springframework.data.elasticsearch.core.document.Document mapping = indexOperations - .createMapping(TemplateClass.class).block(); - Settings settings = indexOperations.createSettings(TemplateClass.class).block(); - - AliasActions aliasActions = new AliasActions( - new AliasAction.Add(AliasActionParameters.builderForTemplate().withAliases("alias1", "alias2").build())); - PutTemplateRequest putTemplateRequest = PutTemplateRequest.builder("test-template", "log-*") // - .withSettings(settings) // - .withMappings(mapping) // - .withAliasActions(aliasActions) // - .withOrder(11) // - .withVersion(42) // - .build(); - - Boolean acknowledged = indexOperations.putTemplate(putTemplateRequest).block(); - assertThat(acknowledged).isTrue(); - - GetTemplateRequest getTemplateRequest = new GetTemplateRequest(putTemplateRequest.getName()); - TemplateData templateData = indexOperations.getTemplate(getTemplateRequest).block(); - - SoftAssertions softly = new SoftAssertions(); - softly.assertThat(templateData).isNotNull(); - softly.assertThat(templateData.getIndexPatterns()).containsExactlyInAnyOrder(putTemplateRequest.getIndexPatterns()); - assertEquals(settings.flatten().toJson(), templateData.getSettings().toJson(), false); - assertEquals(mapping.toJson(), templateData.getMapping().toJson(), false); - Map aliases = templateData.getAliases(); - softly.assertThat(aliases).hasSize(2); - AliasData alias1 = aliases.get("alias1"); - softly.assertThat(alias1.getAlias()).isEqualTo("alias1"); - AliasData alias2 = aliases.get("alias2"); - softly.assertThat(alias2.getAlias()).isEqualTo("alias2"); - softly.assertThat(templateData.getOrder()).isEqualTo(putTemplateRequest.getOrder()); - softly.assertThat(templateData.getVersion()).isEqualTo(putTemplateRequest.getVersion()); - softly.assertAll(); - } - - @Test // DATAES-612 - void shouldCheckTemplateExists() { - - String templateName = "template" + UUID.randomUUID().toString(); - ExistsTemplateRequest existsTemplateRequest = new ExistsTemplateRequest(templateName); - - boolean exists = indexOperations.existsTemplate(existsTemplateRequest).block(); - assertThat(exists).isFalse(); - - PutTemplateRequest putTemplateRequest = PutTemplateRequest.builder(templateName, "log-*") // - .withOrder(11) // - .withVersion(42) // - .build(); - - boolean acknowledged = indexOperations.putTemplate(putTemplateRequest).block(); - assertThat(acknowledged).isTrue(); - - exists = indexOperations.existsTemplate(existsTemplateRequest).block(); - assertThat(exists).isTrue(); - } - - @Test // DATAES-612 - void shouldDeleteTemplate() { - - String templateName = "template" + UUID.randomUUID().toString(); - ExistsTemplateRequest existsTemplateRequest = new ExistsTemplateRequest(templateName); - - PutTemplateRequest putTemplateRequest = PutTemplateRequest.builder(templateName, "log-*") // - .withOrder(11) // - .withVersion(42) // - .build(); - - boolean acknowledged = indexOperations.putTemplate(putTemplateRequest).block(); - assertThat(acknowledged).isTrue(); - - boolean exists = indexOperations.existsTemplate(existsTemplateRequest).block(); - assertThat(exists).isTrue(); - - acknowledged = indexOperations.deleteTemplate(new DeleteTemplateRequest(templateName)).block(); - assertThat(acknowledged).isTrue(); - - exists = indexOperations.existsTemplate(existsTemplateRequest).block(); - assertThat(exists).isFalse(); - } - @Document(indexName = "#{@indexNameProvider.indexName()}") @Setting(shards = 3, replicas = 2, refreshInterval = "4s") static class Entity { @@ -549,32 +417,4 @@ public abstract class ReactiveIndexOperationsIntegrationTests implements NewElas this.id = id; } } - - @Document(indexName = "#{@indexNameProvider.indexName()}") - @Setting(refreshInterval = "5s") - static class TemplateClass { - @Id - @Nullable private String id; - @Field(type = FieldType.Text) - @Nullable private String message; - - @Nullable - public String getId() { - return id; - } - - public void setId(@Nullable String id) { - this.id = id; - } - - @Nullable - public String getMessage() { - return message; - } - - public void setMessage(@Nullable String message) { - this.message = message; - } - } - } diff --git a/src/test/java/org/springframework/data/elasticsearch/core/index/ReactiveIndexTemplateELCIntegrationTests.java b/src/test/java/org/springframework/data/elasticsearch/core/index/ReactiveIndexTemplateELCIntegrationTests.java new file mode 100644 index 000000000..8062c9dd2 --- /dev/null +++ b/src/test/java/org/springframework/data/elasticsearch/core/index/ReactiveIndexTemplateELCIntegrationTests.java @@ -0,0 +1,43 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed 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 + * + * https://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.springframework.data.elasticsearch.core.index; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.data.elasticsearch.junit.jupiter.ReactiveElasticsearchTemplateConfiguration; +import org.springframework.data.elasticsearch.utils.IndexNameProvider; +import org.springframework.test.context.ContextConfiguration; + +/** + * @author Peter-Josef Meisch + */ +@ContextConfiguration(classes = { ReactiveIndexTemplateELCIntegrationTests.Config.class }) +public class ReactiveIndexTemplateELCIntegrationTests extends ReactiveIndexTemplateIntegrationTests { + @Configuration + @Import({ ReactiveElasticsearchTemplateConfiguration.class }) + static class Config { + @Bean + IndexNameProvider indexNameProvider() { + return new IndexNameProvider("reactive-index-template"); + } + } + + @Override + public boolean newElasticsearchClient() { + return true; + } +} diff --git a/src/test/java/org/springframework/data/elasticsearch/core/index/ReactiveIndexTemplateERHLCIntegrationTests.java b/src/test/java/org/springframework/data/elasticsearch/core/index/ReactiveIndexTemplateERHLCIntegrationTests.java new file mode 100644 index 000000000..a1981e05a --- /dev/null +++ b/src/test/java/org/springframework/data/elasticsearch/core/index/ReactiveIndexTemplateERHLCIntegrationTests.java @@ -0,0 +1,39 @@ +/* + * Copyright 2023 the original author or authors. + * + * Licensed 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 + * + * https://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.springframework.data.elasticsearch.core.index; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.data.elasticsearch.junit.jupiter.ReactiveElasticsearchRestTemplateConfiguration; +import org.springframework.data.elasticsearch.utils.IndexNameProvider; +import org.springframework.test.context.ContextConfiguration; + +/** + * @author Peter-Josef Meisch + */ +@ContextConfiguration(classes = { ReactiveIndexTemplateERHLCIntegrationTests.Config.class }) +public class ReactiveIndexTemplateERHLCIntegrationTests extends ReactiveIndexOperationsIntegrationTests { + + @Configuration + @Import({ ReactiveElasticsearchRestTemplateConfiguration.class }) + static class Config { + @Bean + IndexNameProvider indexNameProvider() { + return new IndexNameProvider("reactive-index-template-es7"); + } + } +} diff --git a/src/test/java/org/springframework/data/elasticsearch/core/index/ReactiveIndexTemplateIntegrationTests.java b/src/test/java/org/springframework/data/elasticsearch/core/index/ReactiveIndexTemplateIntegrationTests.java new file mode 100644 index 000000000..fdd2501bf --- /dev/null +++ b/src/test/java/org/springframework/data/elasticsearch/core/index/ReactiveIndexTemplateIntegrationTests.java @@ -0,0 +1,454 @@ +/* + * Copyright 2018-2023 the original author or authors. + * + * Licensed 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 + * + * https://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.springframework.data.elasticsearch.core.index; + +import static org.assertj.core.api.Assertions.*; +import static org.skyscreamer.jsonassert.JSONAssert.*; + +import reactor.test.StepVerifier; + +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.assertj.core.api.SoftAssertions; +import org.json.JSONException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledIf; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.annotation.Id; +import org.springframework.data.elasticsearch.NewElasticsearchClientDevelopment; +import org.springframework.data.elasticsearch.annotations.Document; +import org.springframework.data.elasticsearch.annotations.Field; +import org.springframework.data.elasticsearch.annotations.FieldType; +import org.springframework.data.elasticsearch.annotations.Setting; +import org.springframework.data.elasticsearch.core.AbstractReactiveElasticsearchTemplate; +import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations; +import org.springframework.data.elasticsearch.core.ReactiveIndexOperations; +import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; +import org.springframework.data.elasticsearch.core.query.Criteria; +import org.springframework.data.elasticsearch.core.query.CriteriaQuery; +import org.springframework.data.elasticsearch.core.query.Query; +import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest; +import org.springframework.data.elasticsearch.utils.IndexNameProvider; +import org.springframework.lang.Nullable; + +/** + * @author Peter-Josef Meisch + */ +@SpringIntegrationTest +public abstract class ReactiveIndexTemplateIntegrationTests implements NewElasticsearchClientDevelopment { + + @Autowired private ReactiveElasticsearchOperations operations; + @Autowired private IndexNameProvider indexNameProvider; + private ReactiveIndexOperations indexOperations; + + boolean rhlcWithCluster8() { + var clusterVersion = ((AbstractReactiveElasticsearchTemplate) operations).getClusterVersion().block(); + return (oldElasticsearchClient() && clusterVersion != null && clusterVersion.startsWith("8")); + } + + @BeforeEach + void setUp() { + indexNameProvider.increment(); + indexOperations = operations.indexOps(IndexCoordinates.of(indexNameProvider.indexName())); + } + + @Test + @Order(Integer.MAX_VALUE) + void cleanup() { + operations.indexOps(IndexCoordinates.of(indexNameProvider.getPrefix() + "*")).delete().block(); + } + + @DisabledIf(value = "rhlcWithCluster8", disabledReason = "RHLC fails to parse response from ES 8.2") + @Test // DATAES-612 + void shouldPutTemplate() { + + org.springframework.data.elasticsearch.core.document.Document mapping = indexOperations + .createMapping(TemplateClass.class).block(); + Settings settings = indexOperations.createSettings(TemplateClass.class).block(); + + AliasActions aliasActions = new AliasActions( + new AliasAction.Add(AliasActionParameters.builderForTemplate().withAliases("alias1", "alias2").build())); + PutTemplateRequest putTemplateRequest = PutTemplateRequest.builder("test-template", "log-*") // + .withSettings(settings) // + .withMappings(mapping) // + .withAliasActions(aliasActions) // + .withOrder(11) // + .withVersion(42) // + .build(); + + Boolean acknowledged = indexOperations.putTemplate(putTemplateRequest).block(); + assertThat(acknowledged).isTrue(); + } + + @DisabledIf(value = "oldElasticsearchClient", disabledReason = "not implemented for the deprecated old client") + @Test // #1458 + @DisplayName("should create component template") + void shouldCreateComponentTemplate() { + + ReactiveIndexOperations indexOps = operations.indexOps(IndexCoordinates.of("dont-care")); + + org.springframework.data.elasticsearch.core.document.Document mapping = indexOps.createMapping(TemplateClass.class) + .block(); + Settings settings = indexOps.createSettings(TemplateClass.class).block(); + + AliasActions aliasActions = new AliasActions( // + new AliasAction.Add(AliasActionParameters.builderForTemplate() // + .withAliases("alias1", "alias2") // + .withFilterQuery(Query.findAll()) // + .build())); // + + var putComponentTemplateRequest = PutComponentTemplateRequest.builder() // + .withName("test-component-template") // + .withTemplateData(ComponentTemplateRequestData.builder() // + .withAliasActions(aliasActions) // + .withMapping(mapping) // + .withSettings(settings) // + .build() // + ).build(); + + boolean acknowledged = indexOps.putComponentTemplate(putComponentTemplateRequest).block(); + + assertThat(acknowledged).isTrue(); + } + + @DisabledIf(value = "oldElasticsearchClient", disabledReason = "not implemented for the deprecated old client") + @Test // #1458 + @DisplayName("should get component template") + void shouldGetComponentTemplate() throws JSONException { + ReactiveIndexOperations indexOps = operations.indexOps(IndexCoordinates.of("dont-care")); + + org.springframework.data.elasticsearch.core.document.Document mapping = indexOps.createMapping(TemplateClass.class) + .block(); + Settings settings = indexOps.createSettings(TemplateClass.class).block(); + + var filterQuery = CriteriaQuery.builder(Criteria.where("message").is("foo")).build(); + AliasActions aliasActions = new AliasActions(new AliasAction.Add(AliasActionParameters.builderForTemplate() // + .withAliases("alias1", "alias2") // + .withFilterQuery(filterQuery, TemplateClass.class)// + .build())); + + PutComponentTemplateRequest putComponentTemplateRequest = PutComponentTemplateRequest.builder() // + .withName("test-component-template") // + .withVersion(42L) // + .withTemplateData(ComponentTemplateRequestData.builder() // + .withSettings(settings) // + .withMapping(mapping) // + .withAliasActions(aliasActions) // + .build()) // + .build(); + + boolean acknowledged = indexOps.putComponentTemplate(putComponentTemplateRequest).block(); + assertThat(acknowledged).isTrue(); + + GetComponentTemplateRequest getComponentTemplateRequest = new GetComponentTemplateRequest( + putComponentTemplateRequest.name()); + var componentTemplates = indexOps.getComponentTemplate(getComponentTemplateRequest).collectList().block(); + + assertThat(componentTemplates).isNotNull().hasSize(1); + var returnedComponentTemplate = componentTemplates.iterator().next(); + assertThat(returnedComponentTemplate.version()).isEqualTo(putComponentTemplateRequest.version()); + var componentTemplateData = returnedComponentTemplate.templateData(); + + assertEquals(mapping.toJson(), componentTemplateData.mapping().toJson(), false); + assertEquals(settings.flatten().toJson(), componentTemplateData.settings().flatten().toJson(), false); + var aliases = componentTemplateData.aliases(); + assertThat(aliases).hasSize(2); + AliasData alias1 = aliases.get("alias1"); + assertThat(alias1.getAlias()).isEqualTo("alias1"); + assertThat(alias1.getFilterQuery()).isNotNull(); + AliasData alias2 = aliases.get("alias2"); + assertThat(alias2.getFilterQuery()).isNotNull(); + assertThat(alias2.getAlias()).isEqualTo("alias2"); + } + + @DisabledIf(value = "oldElasticsearchClient", disabledReason = "not implemented for the deprecated old client") + @Test // #1458 + @DisplayName("should delete component template") + void shouldDeleteComponentTemplate() { + + ReactiveIndexOperations indexOps = operations.indexOps(IndexCoordinates.of("dont-care")); + String templateName = "template" + UUID.randomUUID().toString(); + var putComponentTemplateRequest = PutComponentTemplateRequest.builder() // + .withName(templateName) // + .withTemplateData(ComponentTemplateRequestData.builder() // + .withSettings(indexOps.createSettings(TemplateClass.class).block()) // + .build() // + ).build(); + ExistsComponentTemplateRequest existsComponentTemplateRequest = new ExistsComponentTemplateRequest(templateName); + + boolean acknowledged = indexOps.putComponentTemplate(putComponentTemplateRequest).block(); + assertThat(acknowledged).isTrue(); + + boolean exists = indexOps.existsComponentTemplate(existsComponentTemplateRequest).block(); + assertThat(exists).isTrue(); + + acknowledged = indexOps.deleteComponentTemplate(new DeleteComponentTemplateRequest(templateName)).block(); + assertThat(acknowledged).isTrue(); + + exists = indexOps.existsComponentTemplate(existsComponentTemplateRequest).block(); + assertThat(exists).isFalse(); + } + + @DisabledIf(value = "oldElasticsearchClient", disabledReason = "not implemented for the deprecated old client") + @Test // #1458 + @DisplayName("should put, get and delete index template with template") + void shouldPutGetAndDeleteIndexTemplateWithTemplate() { + + ReactiveIndexOperations indexOps = operations.indexOps(IndexCoordinates.of("dont-care")); + org.springframework.data.elasticsearch.core.document.Document mapping = indexOps.createMapping(TemplateClass.class) + .block(); + Settings settings = indexOps.createSettings(TemplateClass.class).block(); + + AliasActions aliasActions = new AliasActions( // + new AliasAction.Add(AliasActionParameters.builderForTemplate() // + .withAliases("alias1", "alias2") // + .withFilterQuery(Query.findAll()) // + .build())); // + var indexTemplateName = "test-index-template"; + var putIndexTemplateRequest = PutIndexTemplateRequest.builder() // + .withName(indexTemplateName) // + .withIndexPatterns("index-*", "endix-*") // + .withSettings(settings) // + .withMapping(mapping) // + .withAliasActions(aliasActions) // + .build(); + + Boolean acknowledged = indexOps.putIndexTemplate(putIndexTemplateRequest).block(); + assertThat(acknowledged).isTrue(); + + var exists = indexOps.existsIndexTemplate(indexTemplateName).block(); + assertThat(exists).isTrue(); + + var indexTemplates = indexOps.getIndexTemplate(indexTemplateName).collectList().block(); + assertThat(indexTemplates).hasSize(1); + + // delete template + acknowledged = indexOps.deleteIndexTemplate(indexTemplateName).block(); + assertThat(acknowledged).isTrue(); + + exists = indexOps.existsIndexTemplate(indexTemplateName).block(); + assertThat(exists).isFalse(); + } + + @DisabledIf(value = "oldElasticsearchClient", disabledReason = "not implemented for the deprecated old client") + @Test // #1458 + @DisplayName("should put, get and delete index template of components") + void shouldPutGetAndDeleteIndexTemplateOfComponents() { + + ReactiveIndexOperations indexOps = operations.indexOps(IndexCoordinates.of("dont-care")); + + org.springframework.data.elasticsearch.core.document.Document mapping = indexOps.createMapping(TemplateClass.class) + .block(); + Settings settings = indexOps.createSettings(TemplateClass.class).block(); + + var filterQuery = CriteriaQuery.builder(Criteria.where("message").is("foo")).build(); + AliasActions aliasActions = new AliasActions(new AliasAction.Add(AliasActionParameters.builderForTemplate() // + .withAliases("alias1", "alias2") // + .withFilterQuery(filterQuery, IndexTemplateIntegrationTests.TemplateClass.class)// + .build())); + + PutComponentTemplateRequest putComponentTemplateRequestMapping = PutComponentTemplateRequest.builder() // + .withName("test-component-template-mapping") // + .withVersion(42L) // + .withTemplateData(ComponentTemplateRequestData.builder() // + .withMapping(mapping) // + .build()) // + .build(); + + Boolean acknowledged = indexOps.putComponentTemplate(putComponentTemplateRequestMapping).block(); + assertThat(acknowledged).isTrue(); + + PutComponentTemplateRequest putComponentTemplateRequestSettings = PutComponentTemplateRequest.builder() // + .withName("test-component-template-settings") // + .withVersion(42L) // + .withTemplateData(ComponentTemplateRequestData.builder() // + .withSettings(settings) // + .build()) // + .build(); + + acknowledged = indexOps.putComponentTemplate(putComponentTemplateRequestSettings).block(); + assertThat(acknowledged).isTrue(); + + PutComponentTemplateRequest putComponentTemplateRequestAliases = PutComponentTemplateRequest.builder() // + .withName("test-component-template-aliases") // + .withVersion(42L) // + .withTemplateData(ComponentTemplateRequestData.builder() // + .withAliasActions(aliasActions) // + .build()) // + .build(); + + acknowledged = indexOps.putComponentTemplate(putComponentTemplateRequestAliases).block(); + assertThat(acknowledged).isTrue(); + + var indexTemplateName = "test-index-template"; + var composedOf = List.of("test-component-template-mapping", "test-component-template-settings", + "test-component-template-aliases"); + var putIndexTemplateRequest = PutIndexTemplateRequest.builder() // + .withName(indexTemplateName) // + .withIndexPatterns("index-*", "endix-*") // + .withComposedOf(composedOf) // + .build(); + + acknowledged = indexOps.putIndexTemplate(putIndexTemplateRequest).block(); + assertThat(acknowledged).isTrue(); + + var indexTemplates = indexOps.getIndexTemplate(indexTemplateName).collectList().block(); + assertThat(indexTemplates).hasSize(1); + assertThat(indexTemplates.get(0).templateData().composedOf()).isEqualTo(composedOf); + + // delete template and components + acknowledged = indexOps.deleteIndexTemplate(indexTemplateName).block(); + assertThat(acknowledged).isTrue(); + acknowledged = indexOps + .deleteComponentTemplate(new DeleteComponentTemplateRequest("test-component-template-mapping")).block(); + assertThat(acknowledged).isTrue(); + acknowledged = indexOps + .deleteComponentTemplate(new DeleteComponentTemplateRequest("test-component-template-settings")).block(); + assertThat(acknowledged).isTrue(); + acknowledged = indexOps + .deleteComponentTemplate(new DeleteComponentTemplateRequest("test-component-template-aliases")).block(); + assertThat(acknowledged).isTrue(); + } + + @Test // DATAES-612 + void shouldReturnNullOnNonExistingGetTemplate() { + + String templateName = "template" + UUID.randomUUID().toString(); + + GetTemplateRequest getTemplateRequest = new GetTemplateRequest(templateName); + indexOperations.getTemplate(getTemplateRequest) // + .as(StepVerifier::create) // + .verifyComplete(); + } + + @DisabledIf(value = "rhlcWithCluster8", disabledReason = "RHLC fails to parse response from ES 8.2") + @Test // DATAES-612 + void shouldGetTemplate() throws JSONException { + + org.springframework.data.elasticsearch.core.document.Document mapping = indexOperations + .createMapping(TemplateClass.class).block(); + Settings settings = indexOperations.createSettings(TemplateClass.class).block(); + + AliasActions aliasActions = new AliasActions( + new AliasAction.Add(AliasActionParameters.builderForTemplate().withAliases("alias1", "alias2").build())); + PutTemplateRequest putTemplateRequest = PutTemplateRequest.builder("test-template", "log-*") // + .withSettings(settings) // + .withMappings(mapping) // + .withAliasActions(aliasActions) // + .withOrder(11) // + .withVersion(42) // + .build(); + + Boolean acknowledged = indexOperations.putTemplate(putTemplateRequest).block(); + assertThat(acknowledged).isTrue(); + + GetTemplateRequest getTemplateRequest = new GetTemplateRequest(putTemplateRequest.getName()); + TemplateData templateData = indexOperations.getTemplate(getTemplateRequest).block(); + + SoftAssertions softly = new SoftAssertions(); + softly.assertThat(templateData).isNotNull(); + softly.assertThat(templateData.getIndexPatterns()).containsExactlyInAnyOrder(putTemplateRequest.getIndexPatterns()); + assertEquals(settings.flatten().toJson(), templateData.getSettings().toJson(), false); + assertEquals(mapping.toJson(), templateData.getMapping().toJson(), false); + Map aliases = templateData.getAliases(); + softly.assertThat(aliases).hasSize(2); + AliasData alias1 = aliases.get("alias1"); + softly.assertThat(alias1.getAlias()).isEqualTo("alias1"); + AliasData alias2 = aliases.get("alias2"); + softly.assertThat(alias2.getAlias()).isEqualTo("alias2"); + softly.assertThat(templateData.getOrder()).isEqualTo(putTemplateRequest.getOrder()); + softly.assertThat(templateData.getVersion()).isEqualTo(putTemplateRequest.getVersion()); + softly.assertAll(); + } + + @Test // DATAES-612 + void shouldCheckTemplateExists() { + + String templateName = "template" + UUID.randomUUID().toString(); + ExistsTemplateRequest existsTemplateRequest = new ExistsTemplateRequest(templateName); + + boolean exists = indexOperations.existsTemplate(existsTemplateRequest).block(); + assertThat(exists).isFalse(); + + PutTemplateRequest putTemplateRequest = PutTemplateRequest.builder(templateName, "log-*") // + .withOrder(11) // + .withVersion(42) // + .build(); + + boolean acknowledged = indexOperations.putTemplate(putTemplateRequest).block(); + assertThat(acknowledged).isTrue(); + + exists = indexOperations.existsTemplate(existsTemplateRequest).block(); + assertThat(exists).isTrue(); + } + + @Test // DATAES-612 + void shouldDeleteTemplate() { + + String templateName = "template" + UUID.randomUUID().toString(); + ExistsTemplateRequest existsTemplateRequest = new ExistsTemplateRequest(templateName); + + PutTemplateRequest putTemplateRequest = PutTemplateRequest.builder(templateName, "log-*") // + .withOrder(11) // + .withVersion(42) // + .build(); + + boolean acknowledged = indexOperations.putTemplate(putTemplateRequest).block(); + assertThat(acknowledged).isTrue(); + + boolean exists = indexOperations.existsTemplate(existsTemplateRequest).block(); + assertThat(exists).isTrue(); + + acknowledged = indexOperations.deleteTemplate(new DeleteTemplateRequest(templateName)).block(); + assertThat(acknowledged).isTrue(); + + exists = indexOperations.existsTemplate(existsTemplateRequest).block(); + assertThat(exists).isFalse(); + } + + @Document(indexName = "#{@indexNameProvider.indexName()}") + @Setting(refreshInterval = "5s") + static class TemplateClass { + @Id + @Nullable private String id; + @Field(type = FieldType.Text) + @Nullable private String message; + + @Nullable + public String getId() { + return id; + } + + public void setId(@Nullable String id) { + this.id = id; + } + + @Nullable + public String getMessage() { + return message; + } + + public void setMessage(@Nullable String message) { + this.message = message; + } + } + +}