From da7373ee3a9dc6a1ab18db5d4969c5ad0afd32dc Mon Sep 17 00:00:00 2001 From: marko-bekhta Date: Fri, 14 Nov 2025 18:57:42 +0100 Subject: [PATCH 1/4] HSEARCH-5482 Simple Elasticsearch client based on java.net.http.HttpClient --- .../jdk-rest-client/pom.xml | 64 ++++ ...csearchHttpClientConfigurationContext.java | 39 +++ .../ElasticsearchHttpClientConfigurer.java | 40 +++ ...JdkElasticsearchBackendClientSettings.java | 70 +++++ ...ElasticsearchBackendClientSpiSettings.java | 57 ++++ .../client/jdk/cfg/spi/NodeProvider.java | 243 ++++++++++++++++ .../client/jdk/cfg/spi/RestJdkClient.java | 56 ++++ .../impl/ClientJdkElasticsearchClient.java | 275 ++++++++++++++++++ ...tJdkElasticsearchClientBeanConfigurer.java | 20 ++ .../ClientJdkElasticsearchClientFactory.java | 261 +++++++++++++++++ ...csearchHttpClientConfigurationContext.java | 44 +++ .../jdk/impl/ClientJdkGsonHttpEntity.java | 51 ++++ .../impl/ClientJdkHttpRequestInterceptor.java | 124 ++++++++ .../jdk/impl/HttpRequestInterceptor.java | 13 + .../impl/HttpRequestInterceptorContext.java | 8 + .../logging/impl/ElasticsearchClientLog.java | 29 ++ .../client/jdk/package-info.java | 1 + ...engine.environment.bean.spi.BeanConfigurer | 1 + bom/platform-common/pom.xml | 5 + bom/public/pom.xml | 5 + build/jqassistant/rules/rules.xml | 1 + build/parents/build/pom.xml | 5 + build/reports/pom.xml | 4 + distribution/pom.xml | 9 +- documentation/pom.xml | 44 ++- .../reference/_backend-elasticsearch.adoc | 8 +- .../ElasticsearchHttpClientConfigurerIT.java | 4 +- .../client/jdk/HttpClientConfigurer.java | 34 +++ .../ElasticsearchHttpClientConfigurerIT.java | 2 +- .../{rest => rest4}/HttpClientConfigurer.java | 2 +- .../ElasticsearchHttpClientConfigurerIT.java | 64 ++++ .../{java => rest5}/HttpClientConfigurer.java | 2 +- ... => http-client-configurer-jdk.properties} | 2 +- .../http-client-configurer-rest5.properties | 7 + .../http-client-configurer.properties | 2 +- integrationtest/backend/elasticsearch/pom.xml | 50 ++++ .../ElasticsearchBootstrapFailureIT.java | 4 +- lucene-next/documentation/pom.xml | 6 + pom.xml | 1 + 39 files changed, 1641 insertions(+), 16 deletions(-) create mode 100644 backend/elasticsearch-client/jdk-rest-client/pom.xml create mode 100644 backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/ElasticsearchHttpClientConfigurationContext.java create mode 100644 backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/ElasticsearchHttpClientConfigurer.java create mode 100644 backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/ClientJdkElasticsearchBackendClientSettings.java create mode 100644 backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/spi/ClientJdkElasticsearchBackendClientSpiSettings.java create mode 100644 backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/spi/NodeProvider.java create mode 100644 backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/spi/RestJdkClient.java create mode 100644 backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchClient.java create mode 100644 backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchClientBeanConfigurer.java create mode 100644 backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchClientFactory.java create mode 100644 backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchHttpClientConfigurationContext.java create mode 100644 backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkGsonHttpEntity.java create mode 100644 backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkHttpRequestInterceptor.java create mode 100644 backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/HttpRequestInterceptor.java create mode 100644 backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/HttpRequestInterceptorContext.java create mode 100644 backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/logging/impl/ElasticsearchClientLog.java create mode 100644 backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/package-info.java create mode 100644 backend/elasticsearch-client/jdk-rest-client/src/main/resources/META-INF/services/org.hibernate.search.engine.environment.bean.spi.BeanConfigurer rename documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/{java => jdk}/ElasticsearchHttpClientConfigurerIT.java (94%) create mode 100644 documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/jdk/HttpClientConfigurer.java rename documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/{rest => rest4}/ElasticsearchHttpClientConfigurerIT.java (99%) rename documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/{rest => rest4}/HttpClientConfigurer.java (98%) create mode 100644 documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/rest5/ElasticsearchHttpClientConfigurerIT.java rename documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/{java => rest5}/HttpClientConfigurer.java (99%) rename documentation/src/test/resources/configuration/{http-client-configurer-java.properties => http-client-configurer-jdk.properties} (71%) create mode 100644 documentation/src/test/resources/configuration/http-client-configurer-rest5.properties diff --git a/backend/elasticsearch-client/jdk-rest-client/pom.xml b/backend/elasticsearch-client/jdk-rest-client/pom.xml new file mode 100644 index 00000000000..5649f48c430 --- /dev/null +++ b/backend/elasticsearch-client/jdk-rest-client/pom.xml @@ -0,0 +1,64 @@ + + + + 4.0.0 + + org.hibernate.search + hibernate-search-parent-public + 8.2.0-SNAPSHOT + ../../../build/parents/public + + hibernate-search-backend-elasticsearch-client-jdk + + Hibernate Search Backend - Elasticsearch client based on the JDK HTTP client + Hibernate Search Elasticsearch client based on the JDK HTTP client + + + + false + org.hibernate.search.backend.elasticsearch.client.jdk + + + + + org.hibernate.search + hibernate-search-engine + + + org.hibernate.search + hibernate-search-backend-elasticsearch + + + org.jboss.logging + jboss-logging + + + org.jboss.logging + jboss-logging-annotations + + + com.google.code.gson + gson + + + + + org.hibernate.search + hibernate-search-util-internal-test-common + test + + + + + + + org.moditect + moditect-maven-plugin + + + + diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/ElasticsearchHttpClientConfigurationContext.java b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/ElasticsearchHttpClientConfigurationContext.java new file mode 100644 index 00000000000..de5dc755042 --- /dev/null +++ b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/ElasticsearchHttpClientConfigurationContext.java @@ -0,0 +1,39 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.search.backend.elasticsearch.client.jdk; + + +import java.net.http.HttpClient; + +import org.hibernate.search.engine.cfg.ConfigurationPropertySource; +import org.hibernate.search.engine.environment.bean.BeanResolver; +import org.hibernate.search.util.common.annotation.Incubating; + +/** + * The context passed to {@link ElasticsearchHttpClientConfigurer}. + */ +@Incubating +public interface ElasticsearchHttpClientConfigurationContext { + + /** + * @return A {@link BeanResolver}. + */ + BeanResolver beanResolver(); + + /** + * @return A configuration property source, appropriately masked so that the factory + * doesn't need to care about Hibernate Search prefixes (hibernate.search.*, etc.). All the properties + * can be accessed at the root. + * CAUTION: the property key "type" is reserved for use by the engine. + */ + ConfigurationPropertySource configurationPropertySource(); + + /** + * @return A JDK HTTP client builder, to set the configuration. + * @see HttpClient.Builder + */ + HttpClient.Builder clientBuilder(); + +} diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/ElasticsearchHttpClientConfigurer.java b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/ElasticsearchHttpClientConfigurer.java new file mode 100644 index 00000000000..a103972b6f7 --- /dev/null +++ b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/ElasticsearchHttpClientConfigurer.java @@ -0,0 +1,40 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.search.backend.elasticsearch.client.jdk; + +import org.hibernate.search.util.common.annotation.Incubating; + +/** + * An extension point allowing fine tuning of the Apache HTTP Client used by the Elasticsearch integration. + *

+ * This enables in particular connecting to cloud services that require a particular authentication method, + * such as request signing on Amazon Web Services. + *

+ * The ElasticsearchHttpClientConfigurer implementation will be given access to the HTTP client builder + * on startup. + *

+ * Note that you don't have to configure the client unless you have specific needs: + * the default configuration should work just fine for an on-premise Elasticsearch server. + */ +@Incubating +public interface ElasticsearchHttpClientConfigurer { + + /** + * Configure the HTTP Client. + *

+ * This method is called once for every configurer, each time an Elasticsearch client is set up. + *

+ * Implementors should take care of only applying configuration if relevant: + * there may be multiple, conflicting configurers in the path, so implementors should first check + * (through a configuration property) whether they are needed or not before applying any modification. + * For example an authentication configurer could decide not to do anything if no username is provided, + * or if the configuration property {@code my.configurer.enabled} is {@code false}. + * + * @param context A configuration context giving access to the Apache HTTP client builder + * and configuration properties in particular. + */ + void configure(ElasticsearchHttpClientConfigurationContext context); + +} diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/ClientJdkElasticsearchBackendClientSettings.java b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/ClientJdkElasticsearchBackendClientSettings.java new file mode 100644 index 00000000000..506b9ad69af --- /dev/null +++ b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/ClientJdkElasticsearchBackendClientSettings.java @@ -0,0 +1,70 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.search.backend.elasticsearch.client.jdk.cfg; + +import org.hibernate.search.backend.elasticsearch.cfg.ElasticsearchBackendSettings; +import org.hibernate.search.backend.elasticsearch.client.jdk.ElasticsearchHttpClientConfigurer; +import org.hibernate.search.util.common.annotation.Incubating; + +/** + * Specific configuration properties for the Elasticsearch backend's rest client based on the Elasticsearch's low-level rest client. + *

+ * Constants in this class are to be appended to a prefix to form a property key; + * see {@link org.hibernate.search.engine.cfg.BackendSettings} for details. + * + * @author Gunnar Morling + */ +@Incubating +public final class ClientJdkElasticsearchBackendClientSettings { + + private ClientJdkElasticsearchBackendClientSettings() { + } + + /** + * The timeout when executing a request to an Elasticsearch server. + *

+ * This includes the time needed to establish a connection, send the request and read the response. + *

+ * Expects a positive Integer value in milliseconds, such as 60000, + * or a String that can be parsed into such Integer value. + *

+ * Defaults to no request timeout. + */ + public static final String REQUEST_TIMEOUT = "request_timeout"; + + /** + * The timeout when establishing a connection to an Elasticsearch server. + *

+ * Expects a positive Integer value in milliseconds, such as {@code 3000}, + * or a String that can be parsed into such Integer value. + *

+ * Defaults to {@link Defaults#CONNECTION_TIMEOUT}. + */ + public static final String CONNECTION_TIMEOUT = "connection_timeout"; + + /** + * A {@link ElasticsearchHttpClientConfigurer} that defines custom HTTP client configuration. + *

+ * It can be used for example to tune the SSL context to accept self-signed certificates. + * It allows overriding other HTTP client settings, such as {@link ElasticsearchBackendSettings#USERNAME}. + *

+ * Expects a reference to a bean of type {@link ElasticsearchHttpClientConfigurer}. + *

+ * Defaults to no value. + */ + public static final String CLIENT_CONFIGURER = "client.configurer"; + + /** + * Default values for the different settings if no values are given. + */ + public static final class Defaults { + + private Defaults() { + } + + public static final int READ_TIMEOUT = 30000; + public static final int CONNECTION_TIMEOUT = 1000; + } +} diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/spi/ClientJdkElasticsearchBackendClientSpiSettings.java b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/spi/ClientJdkElasticsearchBackendClientSpiSettings.java new file mode 100644 index 00000000000..b13b11449b3 --- /dev/null +++ b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/spi/ClientJdkElasticsearchBackendClientSpiSettings.java @@ -0,0 +1,57 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.search.backend.elasticsearch.client.jdk.cfg.spi; + +import org.hibernate.search.engine.cfg.EngineSettings; +import org.hibernate.search.util.common.annotation.Incubating; + +/** + * Configuration properties for the Elasticsearch backend that are considered SPI (and not API). + */ +@Incubating +public final class ClientJdkElasticsearchBackendClientSpiSettings { + + /** + * The prefix expected for the key of every Hibernate Search configuration property. + */ + public static final String PREFIX = EngineSettings.PREFIX + "backend."; + + /** + * An external Elasticsearch client instance that Hibernate Search should use for all requests to Elasticsearch. + *

+ * If this is set, Hibernate Search will not attempt to create its own Elasticsearch, + * and all other client-related configuration properties + * (hosts/uris, authentication, discovery, timeouts, max connections, configurer, ...) + * will be ignored. + *

+ * Expects a reference to a bean of type {@link RestJdkClient}. + *

+ * Defaults to nothing: if no client instance is provided, Hibernate Search will create its own. + *

+ * WARNING - Incubating API: the underlying client class may change without prior notice. + * + * @see org.hibernate.search.engine.cfg The core documentation of configuration properties, + * which includes a description of the "bean reference" properties and accepted values. + */ + public static final String CLIENT_INSTANCE = "client.instance"; + + private ClientJdkElasticsearchBackendClientSpiSettings() { + } + + /** + * Configuration property keys without the {@link #PREFIX prefix}. + */ + public static class Radicals { + + private Radicals() { + } + } + + public static final class Defaults { + + private Defaults() { + } + } +} diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/spi/NodeProvider.java b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/spi/NodeProvider.java new file mode 100644 index 00000000000..5cdbf01deec --- /dev/null +++ b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/spi/NodeProvider.java @@ -0,0 +1,243 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.search.backend.elasticsearch.client.jdk.cfg.spi; + +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicInteger; + +import org.hibernate.search.backend.elasticsearch.cfg.ElasticsearchBackendSettings; +import org.hibernate.search.backend.elasticsearch.logging.spi.ConfigurationLog; +import org.hibernate.search.util.common.annotation.Incubating; + +@Incubating +public class NodeProvider { + + public static NodeProvider fromOptionalStrings(Optional protocol, Optional> hostAndPortStrings, + Optional> uris, String pathPrefix) { + if ( !uris.isPresent() ) { + String protocolValue = + ( protocol.isPresent() ) ? protocol.get() : ElasticsearchBackendSettings.Defaults.PROTOCOL; + List hostAndPortValues = + ( hostAndPortStrings.isPresent() ) + ? hostAndPortStrings.get() + : ElasticsearchBackendSettings.Defaults.HOSTS; + return fromStrings( protocolValue, hostAndPortValues, pathPrefix ); + } + + if ( protocol.isPresent() ) { + throw ConfigurationLog.INSTANCE.uriAndProtocol( uris.get(), protocol.get() ); + } + + if ( hostAndPortStrings.isPresent() ) { + throw ConfigurationLog.INSTANCE.uriAndHosts( uris.get(), hostAndPortStrings.get() ); + } + + return fromStrings( uris.get(), pathPrefix ); + } + + private final AtomicInteger currentNode = new AtomicInteger( 0 ); + private final int numberOfNodes; + private final List serverNodes; + private final boolean httpsEnabled; + + public NodeProvider(List serverNodes, boolean httpsEnabled) { + this.serverNodes = serverNodes; + this.numberOfNodes = serverNodes.size(); + this.httpsEnabled = httpsEnabled; + // TODO: we can add a discovery of other nodes here later? + } + + public ServerNode nextNode() { + return serverNodes.get( currentNode.getAndUpdate( this::updateCounter ) ); + } + + private int updateCounter(int i) { + return ( i + 1 ) % numberOfNodes; + } + + private static NodeProvider fromStrings(String protocol, List hostAndPortStrings, String pathPrefix) { + if ( hostAndPortStrings.isEmpty() ) { + throw ConfigurationLog.INSTANCE.emptyListOfHosts(); + } + + List serverNodes = new ArrayList<>( hostAndPortStrings.size() ); + // Note: protocol and URI scheme are not the same thing, + // but for HTTP/HTTPS both the protocol and URI scheme are named HTTP/HTTPS. + String scheme = protocol.toLowerCase( Locale.ROOT ); + for ( int i = 0; i < hostAndPortStrings.size(); ++i ) { + serverNodes.add( createServerNode( scheme, hostAndPortStrings.get( i ), pathPrefix ) ); + } + return new NodeProvider( serverNodes, "https".equals( scheme ) ); + } + + private static ServerNode createServerNode(String scheme, String hostAndPort, String pathPrefix) { + if ( hostAndPort.indexOf( "://" ) >= 0 ) { + throw ConfigurationLog.INSTANCE.invalidHostAndPort( hostAndPort, null ); + } + String host; + int port = -1; + final int portIdx = hostAndPort.lastIndexOf( ':' ); + if ( portIdx < 0 ) { + host = hostAndPort; + } + else { + try { + port = Integer.parseInt( hostAndPort.substring( portIdx + 1 ) ); + } + catch (final NumberFormatException e) { + throw ConfigurationLog.INSTANCE.invalidHostAndPort( hostAndPort, e ); + } + host = hostAndPort.substring( 0, portIdx ); + } + return new ServerNode( scheme, host, pathPrefix, port ); + } + + private static NodeProvider fromStrings(List serverUrisStrings, String pathPrefix) { + if ( serverUrisStrings.isEmpty() ) { + throw ConfigurationLog.INSTANCE.emptyListOfUris(); + } + + List serverNodes = new ArrayList<>( serverUrisStrings.size() ); + Boolean https = null; + for ( int i = 0; i < serverUrisStrings.size(); ++i ) { + String uri = serverUrisStrings.get( i ); + try { + final int schemeIdx = uri.indexOf( "://" ); + if ( schemeIdx < 0 ) { + uri = "http://" + uri; + } + URI actual = URI.create( uri ); + String host = actual.getHost(); + if ( actual.getPort() != -1 ) { + host = host + ":" + actual.getPort(); + } + serverNodes.add( createServerNode( actual.getScheme(), host, pathPrefix ) ); + boolean currentHttps = "https".equals( actual.getScheme() ); + if ( https == null ) { + https = currentHttps; + } + else if ( currentHttps != https ) { + throw ConfigurationLog.INSTANCE.differentProtocolsOnUris( serverUrisStrings ); + } + } + catch (IllegalArgumentException e) { + throw ConfigurationLog.INSTANCE.invalidUri( uri, e.getMessage(), e ); + } + } + + return new NodeProvider( serverNodes, https ); + } + + public boolean isSslEnabled() { + return httpsEnabled; + } + + public static final class ServerNode { + private static final long RETRY_DELAY_MILLISECONDS = 1_000L; + private final String protocol; + private final String host; + private final String basePath; + private final int port; + private volatile Status status; + private volatile long retryAfterMillis; + private ServerNode next; + + public ServerNode(String protocol, String host, String basePath, int port) { + this.protocol = protocol; + this.host = host; + this.basePath = normalizeBasePath( basePath ); + this.port = port; + this.status = Status.ACTIVE; + this.retryAfterMillis = -1; + } + + private String normalizeBasePath(String basePath) { + if ( "".equals( basePath ) ) { + return ""; + } + else if ( basePath.endsWith( "/" ) ) { + basePath = basePath.substring( 0, basePath.length() - 1 ); + } + if ( !basePath.startsWith( "/" ) ) { + basePath = "/" + basePath; + } + return basePath; + } + + private String buildQueryString(Map parameters) { + if ( parameters == null || parameters.isEmpty() ) { + return ""; + } + + StringBuilder queryString = new StringBuilder(); + boolean first = true; + + for ( Map.Entry entry : parameters.entrySet() ) { + if ( !first ) { + queryString.append( "&" ); + } + + String encodedKey = URLEncoder.encode( entry.getKey(), StandardCharsets.UTF_8 ); + String encodedValue = URLEncoder.encode( entry.getValue(), StandardCharsets.UTF_8 ); + + queryString.append( encodedKey ).append( "=" ).append( encodedValue ); + first = false; + } + + return queryString.toString(); + } + + public URI createRequestURI(String path, Map parameters) { + if ( !path.isEmpty() && !path.startsWith( "/" ) ) { + throw new IllegalArgumentException( "Path must start with '/': " + path ); + } + String fullpath = basePath + path; + String queryString = buildQueryString( parameters ); + try { + return new URI( protocol, null, host, port, fullpath, queryString.isEmpty() ? null : queryString, null ); + } + catch (URISyntaxException e) { + throw new IllegalArgumentException( "Invalid URI: " + e.getMessage(), e ); + } + } + + public void failing() { + this.status = Status.FAILING; + this.retryAfterMillis = System.currentTimeMillis() + RETRY_DELAY_MILLISECONDS; + } + + private void setNext(ServerNode next) { + this.next = next; + } + + @Override + public boolean equals(Object o) { + if ( !( o instanceof ServerNode that ) ) { + return false; + } + return port == that.port + && Objects.equals( protocol, that.protocol ) && Objects.equals( host, that.host ) + && Objects.equals( basePath, that.basePath ); + } + + @Override + public int hashCode() { + return Objects.hash( protocol, host, basePath, port ); + } + } + + public enum Status { + ACTIVE, FAILING; + } +} diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/spi/RestJdkClient.java b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/spi/RestJdkClient.java new file mode 100644 index 00000000000..229ad52edd3 --- /dev/null +++ b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/spi/RestJdkClient.java @@ -0,0 +1,56 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.search.backend.elasticsearch.client.jdk.cfg.spi; + +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; + +import org.hibernate.search.util.common.annotation.Incubating; +import org.hibernate.search.util.common.impl.Closer; + +@Incubating +public class RestJdkClient implements AutoCloseable { + + private final NodeProvider nodeProvider; + + private HttpClient httpClient; + + public RestJdkClient(NodeProvider nodeProvider, HttpClient httpClient) { + this.nodeProvider = nodeProvider; + this.httpClient = httpClient; + } + + public NodeProvider.ServerNode nextNode() { + return nodeProvider.nextNode(); + } + + public CompletableFuture> sendAsync(HttpRequest request, + HttpResponse.BodyHandler responseBodyHandler) { + return httpClient.sendAsync( request, responseBodyHandler ); + } + + @Override + public void close() throws Exception { + if ( httpClient != null ) { + try ( Closer closer = new Closer<>() ) { + Optional executor = httpClient.executor(); + // May look a bit silly ... but close was only added in JDK 21: + if ( ( (Object) httpClient ) instanceof AutoCloseable closeable ) { + closer.push( AutoCloseable::close, closeable ); + } + if ( executor.isPresent() && executor.get() instanceof AutoCloseable closeable ) { + closer.push( AutoCloseable::close, closeable ); + } + } + finally { + httpClient = null; + } + } + } +} diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchClient.java b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchClient.java new file mode 100644 index 00000000000..e8c02baaca6 --- /dev/null +++ b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchClient.java @@ -0,0 +1,275 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.search.backend.elasticsearch.client.jdk.impl; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpHeaders; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.time.temporal.ChronoUnit; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; +import java.util.regex.Pattern; + +import org.hibernate.search.backend.elasticsearch.client.common.gson.spi.JsonLogHelper; +import org.hibernate.search.backend.elasticsearch.client.common.spi.ElasticsearchClientImplementor; +import org.hibernate.search.backend.elasticsearch.client.common.spi.ElasticsearchRequest; +import org.hibernate.search.backend.elasticsearch.client.common.spi.ElasticsearchResponse; +import org.hibernate.search.backend.elasticsearch.client.common.util.spi.ElasticsearchClientUtils; +import org.hibernate.search.backend.elasticsearch.client.jdk.cfg.spi.RestJdkClient; +import org.hibernate.search.backend.elasticsearch.logging.spi.ElasticsearchClientLog; +import org.hibernate.search.backend.elasticsearch.logging.spi.ElasticsearchRequestLog; +import org.hibernate.search.engine.common.execution.spi.SimpleScheduledExecutor; +import org.hibernate.search.engine.common.timing.Deadline; +import org.hibernate.search.engine.environment.bean.BeanHolder; +import org.hibernate.search.util.common.impl.Closer; +import org.hibernate.search.util.common.impl.Futures; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; + +public class ClientJdkElasticsearchClient implements ElasticsearchClientImplementor { + + private static final Pattern CHARSET_PATTERN = + Pattern.compile( "(?:;|^)\\s*charset\\s*=\\s*\"?([^\"\\s;]+)\"?", Pattern.CASE_INSENSITIVE ); + + private final BeanHolder restClientHolder; + + private final SimpleScheduledExecutor timeoutExecutorService; + + private final Optional requestTimeoutMs; + + private final Gson gson; + private final JsonLogHelper jsonLogHelper; + + private final List requestInterceptors; + + ClientJdkElasticsearchClient(BeanHolder restClientHolder, + SimpleScheduledExecutor timeoutExecutorService, + Optional requestTimeoutMs, + Gson gson, JsonLogHelper jsonLogHelper, List requestInterceptors + ) { + this.restClientHolder = restClientHolder; + this.timeoutExecutorService = timeoutExecutorService; + this.requestTimeoutMs = requestTimeoutMs; + this.gson = gson; + this.jsonLogHelper = jsonLogHelper; + this.requestInterceptors = requestInterceptors; + } + + @Override + public CompletableFuture submit(ElasticsearchRequest request) { + CompletableFuture result = Futures.create( () -> send( request ) ) + .thenApply( this::convertResponse ); + if ( ElasticsearchRequestLog.INSTANCE.isDebugEnabled() ) { + long startTime = System.nanoTime(); + result.thenAccept( response -> log( request, startTime, response ) ); + } + return result; + } + + @Override + @SuppressWarnings("unchecked") + public T unwrap(Class clientClass) { + if ( HttpClient.class.isAssignableFrom( clientClass ) ) { + return (T) restClientHolder.get(); + } + throw ElasticsearchClientLog.INSTANCE.clientUnwrappingWithUnknownType( clientClass, HttpClient.class ); + } + + private ElasticsearchResponse convertResponse(HttpResponse response) { + try { + return new ElasticsearchResponse( + response.request().uri().getHost(), + response.statusCode(), + null, + response.body() ); + } + catch (RuntimeException e) { + throw ElasticsearchClientLog.INSTANCE.failedToParseElasticsearchResponse( response.statusCode(), + null, e.getMessage(), e ); + } + } + + private static Charset getCharset(HttpHeaders headers) { + Optional contentType = headers.firstValue( "Content-Type" ); + if ( contentType.isPresent() ) { + var matcher = CHARSET_PATTERN.matcher( contentType.get() ); + if ( matcher.find() ) { + return Charset.forName( matcher.group( 1 ) ); + } + } + return StandardCharsets.UTF_8; + } + + private CompletableFuture> send(ElasticsearchRequest elasticsearchRequest) { + HttpRequest request; + try { + HttpRequest.BodyPublisher entity = ClientJdkGsonHttpEntity.toEntity( gson, elasticsearchRequest ); + request = toRequest( elasticsearchRequest, entity ); + } + catch (IOException | RuntimeException e) { + CompletableFuture> completableFuture = new CompletableFuture<>(); + completableFuture.completeExceptionally( e ); + return completableFuture; + } + + CompletableFuture> completableFuture = restClientHolder.get().sendAsync( + request, + new JsonObjectBodyHandler() + ); + + Deadline deadline = elasticsearchRequest.deadline(); + if ( deadline == null && requestTimeoutMs.isEmpty() ) { + // no need to schedule a client side timeout + return completableFuture; + } + + long currentTimeoutValue = + deadline == null ? Long.valueOf( requestTimeoutMs.get() ) : deadline.checkRemainingTimeMillis(); + + /* + * TODO HSEARCH-3590 maybe the callback should also cancel the request? + */ + ScheduledFuture timeout = timeoutExecutorService.schedule( + () -> { + if ( !completableFuture.isDone() ) { + RuntimeException cause = ElasticsearchClientLog.INSTANCE.requestTimedOut( + Duration.ofNanos( TimeUnit.MILLISECONDS.toNanos( currentTimeoutValue ) ), + elasticsearchRequest ); + completableFuture.completeExceptionally( + deadline != null ? deadline.forceTimeoutAndCreateException( cause ) : cause + ); + } + }, + currentTimeoutValue, TimeUnit.MILLISECONDS + ); + completableFuture.thenRun( () -> timeout.cancel( false ) ); + + return completableFuture; + } + + private HttpRequest toRequest(ElasticsearchRequest elasticsearchRequest, HttpRequest.BodyPublisher bodyPublisher) + throws IOException { + URI uri = toUri( elasticsearchRequest ); + HttpRequest.Builder request = HttpRequest.newBuilder( uri ) + .method( elasticsearchRequest.method(), bodyPublisher ); + setPerRequestSocketTimeout( elasticsearchRequest, request ); + if ( !ClientJdkGsonHttpEntity.isNoBodyPublisher( bodyPublisher ) ) { + request.header( "Content-Type", "application/json" ); + } + + HttpRequestInterceptorContext context = new HttpRequestInterceptorContext( elasticsearchRequest.method() ); + for ( HttpRequestInterceptor requestInterceptor : requestInterceptors ) { + requestInterceptor.process( request, bodyPublisher, context ); + } + + return request.build(); + } + + private URI toUri(ElasticsearchRequest elasticsearchRequest) { + return restClientHolder.get().nextNode().createRequestURI( elasticsearchRequest.path(), + elasticsearchRequest.parameters() ); + } + + private void setPerRequestSocketTimeout(ElasticsearchRequest elasticsearchRequest, HttpRequest.Builder request) { + Deadline deadline = elasticsearchRequest.deadline(); + if ( deadline == null ) { + return; + } + + long timeToHardTimeout = deadline.checkRemainingTimeMillis(); + + // set a per-request socket timeout + int generalRequestTimeoutMs = ( timeToHardTimeout <= Integer.MAX_VALUE ) ? Math.toIntExact( timeToHardTimeout ) : -1; + request.timeout( Duration.of( generalRequestTimeoutMs, ChronoUnit.MILLIS ) ); + } + + private void log(ElasticsearchRequest request, long start, ElasticsearchResponse response) { + boolean successCode = ElasticsearchClientUtils.isSuccessCode( response.statusCode() ); + if ( !ElasticsearchRequestLog.INSTANCE.isTraceEnabled() && successCode ) { + return; + } + long executionTimeNs = System.nanoTime() - start; + long executionTimeMs = TimeUnit.NANOSECONDS.toMillis( executionTimeNs ); + if ( successCode ) { + ElasticsearchRequestLog.INSTANCE.executedRequest( request.method(), response.hostAndPort(), request.path(), + request.parameters(), + request.bodyParts().size(), executionTimeMs, + response.statusCode(), response.statusMessage(), + jsonLogHelper.toString( request.bodyParts() ), + jsonLogHelper.toString( response.body() ) ); + } + else { + ElasticsearchRequestLog.INSTANCE.executedRequestWithFailure( request.method(), response.hostAndPort(), + request.path(), + request.parameters(), + request.bodyParts().size(), executionTimeMs, + response.statusCode(), response.statusMessage(), + jsonLogHelper.toString( request.bodyParts() ), + jsonLogHelper.toString( response.body() ) ); + } + } + + @Override + public void close() { + try ( Closer closer = new Closer<>() ) { + /* + * There's no point waiting for timeouts: we'll just expect the RestClient to cancel all + * currently running requests when closing. + */ + // The BeanHolder is responsible for calling close() on the client if necessary. + closer.push( BeanHolder::close, this.restClientHolder ); + } + catch (RuntimeException | IOException e) { + throw ElasticsearchClientLog.INSTANCE.unableToShutdownClient( e.getMessage(), e ); + } + } + + private class GsonJsonMapper implements Function { + private final Charset charset; + private final int statusCode; + + public GsonJsonMapper(Charset charset, int statusCode) { + this.charset = charset; + this.statusCode = statusCode; + } + + @Override + public JsonObject apply(InputStream inputStream) { + try ( inputStream; Reader reader = new InputStreamReader( inputStream, charset ) ) { + return gson.fromJson( reader, JsonObject.class ); + } + catch (IOException e) { + throw ElasticsearchClientLog.INSTANCE.failedToParseElasticsearchResponse( statusCode, null, e.getMessage(), e ); + } + } + } + + private class JsonObjectBodyHandler implements HttpResponse.BodyHandler { + + @Override + public HttpResponse.BodySubscriber apply(HttpResponse.ResponseInfo responseInfo) { + Charset charset = getCharset( responseInfo.headers() ); + + return HttpResponse.BodySubscribers.mapping( + HttpResponse.BodySubscribers.ofInputStream(), + new GsonJsonMapper( charset, responseInfo.statusCode() ) + ); + } + } +} diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchClientBeanConfigurer.java b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchClientBeanConfigurer.java new file mode 100644 index 00000000000..d391f45138f --- /dev/null +++ b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchClientBeanConfigurer.java @@ -0,0 +1,20 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.search.backend.elasticsearch.client.jdk.impl; + +import org.hibernate.search.backend.elasticsearch.client.common.spi.ElasticsearchClientFactory; +import org.hibernate.search.engine.environment.bean.BeanHolder; +import org.hibernate.search.engine.environment.bean.spi.BeanConfigurationContext; +import org.hibernate.search.engine.environment.bean.spi.BeanConfigurer; + +public class ClientJdkElasticsearchClientBeanConfigurer implements BeanConfigurer { + @Override + public void configure(BeanConfigurationContext context) { + context.define( + ElasticsearchClientFactory.class, "jdk-rest-client", + beanResolver -> BeanHolder.of( new ClientJdkElasticsearchClientFactory() ) + ); + } +} diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchClientFactory.java b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchClientFactory.java new file mode 100644 index 00000000000..d044e0fffc3 --- /dev/null +++ b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchClientFactory.java @@ -0,0 +1,261 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.search.backend.elasticsearch.client.jdk.impl; + +import java.net.Authenticator; +import java.net.PasswordAuthentication; +import java.net.http.HttpClient; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.cert.X509Certificate; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.Executors; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +import org.hibernate.search.backend.elasticsearch.cfg.ElasticsearchBackendSettings; +import org.hibernate.search.backend.elasticsearch.client.common.gson.spi.GsonProvider; +import org.hibernate.search.backend.elasticsearch.client.common.spi.ElasticsearchClientFactory; +import org.hibernate.search.backend.elasticsearch.client.common.spi.ElasticsearchClientImplementor; +import org.hibernate.search.backend.elasticsearch.client.common.spi.ElasticsearchRequestInterceptor; +import org.hibernate.search.backend.elasticsearch.client.common.spi.ElasticsearchRequestInterceptorProvider; +import org.hibernate.search.backend.elasticsearch.client.jdk.ElasticsearchHttpClientConfigurer; +import org.hibernate.search.backend.elasticsearch.client.jdk.cfg.ClientJdkElasticsearchBackendClientSettings; +import org.hibernate.search.backend.elasticsearch.client.jdk.cfg.spi.ClientJdkElasticsearchBackendClientSpiSettings; +import org.hibernate.search.backend.elasticsearch.client.jdk.cfg.spi.NodeProvider; +import org.hibernate.search.backend.elasticsearch.client.jdk.cfg.spi.RestJdkClient; +import org.hibernate.search.backend.elasticsearch.logging.spi.ConfigurationLog; +import org.hibernate.search.engine.cfg.ConfigurationPropertySource; +import org.hibernate.search.engine.cfg.spi.ConfigurationProperty; +import org.hibernate.search.engine.cfg.spi.OptionalConfigurationProperty; +import org.hibernate.search.engine.common.execution.spi.SimpleScheduledExecutor; +import org.hibernate.search.engine.environment.bean.BeanHolder; +import org.hibernate.search.engine.environment.bean.BeanReference; +import org.hibernate.search.engine.environment.bean.BeanResolver; +import org.hibernate.search.engine.environment.thread.spi.ThreadProvider; +import org.hibernate.search.util.common.impl.SuppressingCloser; + + +public class ClientJdkElasticsearchClientFactory implements ElasticsearchClientFactory { + + private static final OptionalConfigurationProperty> CLIENT_INSTANCE = + ConfigurationProperty.forKey( ClientJdkElasticsearchBackendClientSpiSettings.CLIENT_INSTANCE ) + .asBeanReference( RestJdkClient.class ) + .build(); + + private static final OptionalConfigurationProperty> HOSTS = + ConfigurationProperty.forKey( ElasticsearchBackendSettings.HOSTS ) + .asString().multivalued() + .build(); + + private static final OptionalConfigurationProperty PROTOCOL = + ConfigurationProperty.forKey( ElasticsearchBackendSettings.PROTOCOL ) + .asString() + .build(); + + private static final OptionalConfigurationProperty> URIS = + ConfigurationProperty.forKey( ElasticsearchBackendSettings.URIS ) + .asString().multivalued() + .build(); + + private static final ConfigurationProperty PATH_PREFIX = + ConfigurationProperty.forKey( ElasticsearchBackendSettings.PATH_PREFIX ) + .asString() + .withDefault( ElasticsearchBackendSettings.Defaults.PATH_PREFIX ) + .build(); + + private static final OptionalConfigurationProperty USERNAME = + ConfigurationProperty.forKey( ElasticsearchBackendSettings.USERNAME ) + .asString() + .build(); + + private static final OptionalConfigurationProperty PASSWORD = + ConfigurationProperty.forKey( ElasticsearchBackendSettings.PASSWORD ) + .asString() + .build(); + + private static final OptionalConfigurationProperty REQUEST_TIMEOUT = + ConfigurationProperty.forKey( ClientJdkElasticsearchBackendClientSettings.REQUEST_TIMEOUT ) + .asIntegerStrictlyPositive() + .build(); + + private static final ConfigurationProperty CONNECTION_TIMEOUT = + ConfigurationProperty.forKey( ClientJdkElasticsearchBackendClientSettings.CONNECTION_TIMEOUT ) + .asIntegerPositiveOrZeroOrNegative() + .withDefault( ClientJdkElasticsearchBackendClientSettings.Defaults.CONNECTION_TIMEOUT ) + .build(); + + private static final OptionalConfigurationProperty< + BeanReference> CLIENT_CONFIGURER = + ConfigurationProperty.forKey( ClientJdkElasticsearchBackendClientSettings.CLIENT_CONFIGURER ) + .asBeanReference( ElasticsearchHttpClientConfigurer.class ) + .build(); + + @Override + public ElasticsearchClientImplementor create(BeanResolver beanResolver, ConfigurationPropertySource propertySource, + ThreadProvider threadProvider, String threadNamePrefix, + SimpleScheduledExecutor timeoutExecutorService, + GsonProvider gsonProvider) { + Optional requestTimeoutMs = REQUEST_TIMEOUT.get( propertySource ); + + Optional> providedRestClientHolder = CLIENT_INSTANCE.getAndMap( + propertySource, beanResolver::resolve ); + + BeanHolder restClientHolder; + if ( providedRestClientHolder.isPresent() ) { + restClientHolder = providedRestClientHolder.get(); + } + else { + NodeProvider nodeProvider = NodeProvider.fromOptionalStrings( PROTOCOL.get( propertySource ), + HOSTS.get( propertySource ), URIS.get( propertySource ), PATH_PREFIX.get( propertySource ) ); + restClientHolder = createClient( beanResolver, propertySource, threadProvider, threadNamePrefix, nodeProvider ); + } + + return new ClientJdkElasticsearchClient( + restClientHolder, timeoutExecutorService, requestTimeoutMs, + gsonProvider.getGson(), gsonProvider.getLogHelper(), + createRequestInterceptors( beanResolver, propertySource ) + ); + } + + private static List createRequestInterceptors(BeanResolver beanResolver, + ConfigurationPropertySource propertySource) { + List interceptors = new ArrayList<>(); + List> requestInterceptorProviderReferences = + beanResolver.allConfiguredForRole( ElasticsearchRequestInterceptorProvider.class ); + try ( BeanHolder> requestInterceptorProvidersHodler = + beanResolver.resolve( requestInterceptorProviderReferences ) ) { + ClientJdkElasticsearchHttpClientConfigurationContext clientConfigurationContext = + new ClientJdkElasticsearchHttpClientConfigurationContext( beanResolver, propertySource, null ); + for ( ElasticsearchRequestInterceptorProvider interceptorProvider : requestInterceptorProvidersHodler.get() ) { + Optional requestInterceptor = + interceptorProvider.provide( clientConfigurationContext ); + if ( requestInterceptor.isPresent() ) { + interceptors.add( new ClientJdkHttpRequestInterceptor( requestInterceptor.get() ) ); + } + } + } + return interceptors; + } + + private BeanHolder createClient(BeanResolver beanResolver, + ConfigurationPropertySource propertySource, + ThreadProvider threadProvider, String threadNamePrefix, NodeProvider nodeProvider) { + HttpClient.Builder builder = HttpClient.newBuilder() + // NOTE: ES does not work ok with HTTP 2 if we don't send the content length and that can happen so let's stick to 1.1 for now ? + // (we end up with Caused by: java.io.IOException: Received RST_STREAM: Stream cancelled) + .version( HttpClient.Version.HTTP_1_1 ); + + Optional> customConfig = CLIENT_CONFIGURER + .getAndMap( propertySource, beanResolver::resolve ); + + RestJdkClient client = null; + List> httpClientConfigurerReferences = + beanResolver.allConfiguredForRole( ElasticsearchHttpClientConfigurer.class ); + try ( BeanHolder> httpClientConfigurersHolder = + beanResolver.resolve( httpClientConfigurerReferences ) ) { + customizeHttpClientConfig( + builder, + beanResolver, propertySource, + threadProvider, threadNamePrefix, + nodeProvider, httpClientConfigurersHolder.get(), + customConfig + ); + client = new RestJdkClient( nodeProvider, builder.build() ); + return BeanHolder.ofCloseable( client ); + } + catch (RuntimeException e) { + new SuppressingCloser( e ) + .push( client ); + throw e; + } + finally { + if ( customConfig.isPresent() ) { + // Assuming that #customizeHttpClientConfig has been already executed + // and therefore the bean has been already used. + customConfig.get().close(); + } + } + } + + private HttpClient.Builder customizeHttpClientConfig(HttpClient.Builder builder, + BeanResolver beanResolver, ConfigurationPropertySource propertySource, + ThreadProvider threadProvider, String threadNamePrefix, + NodeProvider nodeProvider, Iterable configurers, + Optional> customConfig) { + builder.executor( Executors.newCachedThreadPool( + threadProvider.createThreadFactory( threadNamePrefix + " - Transport thread" ) ) ); + + if ( !nodeProvider.isSslEnabled() ) { + SSLContext sslContext = null; + try { + sslContext = SSLContext.getInstance( "TLS" ); + sslContext.init( null, TRUST_ALL_CERTS, new SecureRandom() ); + builder.sslContext( sslContext ); + } + catch (NoSuchAlgorithmException | KeyManagementException e) { + throw new RuntimeException( e ); + } + } + + builder.connectTimeout( Duration.ofMillis( CONNECTION_TIMEOUT.get( propertySource ) ) ); + + + Optional username = USERNAME.get( propertySource ); + if ( username.isPresent() ) { + Optional password = PASSWORD.get( propertySource ).map( String::toCharArray ); + if ( password.isPresent() && !nodeProvider.isSslEnabled() ) { + ConfigurationLog.INSTANCE.usingPasswordOverHttp(); + } + builder.authenticator( new Authenticator() { + private final PasswordAuthentication passwordAuthentication = + new PasswordAuthentication( username.get(), password.orElseGet( () -> new char[0] ) ); + + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return passwordAuthentication; + } + } ); + } + + ClientJdkElasticsearchHttpClientConfigurationContext clientConfigurationContext = + new ClientJdkElasticsearchHttpClientConfigurationContext( beanResolver, propertySource, builder ); + + for ( ElasticsearchHttpClientConfigurer configurer : configurers ) { + configurer.configure( clientConfigurationContext ); + } + if ( customConfig.isPresent() ) { + BeanHolder customConfigBeanHolder = customConfig.get(); + customConfigBeanHolder.get().configure( clientConfigurationContext ); + } + + return builder; + } + + private static final TrustManager[] TRUST_ALL_CERTS = new TrustManager[] { + new X509TrustManager() { + + private static final X509Certificate[] X_509_CERTIFICATES = new X509Certificate[0]; + + public X509Certificate[] getAcceptedIssuers() { + return X_509_CERTIFICATES; + } + + public void checkClientTrusted(X509Certificate[] certs, String authType) { + // Do nothing: trust client certificates + } + + public void checkServerTrusted(X509Certificate[] certs, String authType) { + // Do nothing: trust server certificates + } + } + }; +} diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchHttpClientConfigurationContext.java b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchHttpClientConfigurationContext.java new file mode 100644 index 00000000000..52adeab9586 --- /dev/null +++ b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchHttpClientConfigurationContext.java @@ -0,0 +1,44 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.search.backend.elasticsearch.client.jdk.impl; + +import java.net.http.HttpClient; + +import org.hibernate.search.backend.elasticsearch.client.common.spi.ElasticsearchRequestInterceptorProviderContext; +import org.hibernate.search.backend.elasticsearch.client.jdk.ElasticsearchHttpClientConfigurationContext; +import org.hibernate.search.engine.cfg.ConfigurationPropertySource; +import org.hibernate.search.engine.environment.bean.BeanResolver; + +final class ClientJdkElasticsearchHttpClientConfigurationContext + implements ElasticsearchHttpClientConfigurationContext, ElasticsearchRequestInterceptorProviderContext { + private final BeanResolver beanResolver; + private final ConfigurationPropertySource configurationPropertySource; + private final HttpClient.Builder clientBuilder; + + ClientJdkElasticsearchHttpClientConfigurationContext( + BeanResolver beanResolver, + ConfigurationPropertySource configurationPropertySource, + HttpClient.Builder clientBuilder) { + this.beanResolver = beanResolver; + this.configurationPropertySource = configurationPropertySource; + this.clientBuilder = clientBuilder; + } + + @Override + public BeanResolver beanResolver() { + return beanResolver; + } + + @Override + public ConfigurationPropertySource configurationPropertySource() { + return configurationPropertySource; + } + + @Override + public HttpClient.Builder clientBuilder() { + return clientBuilder; + } + +} diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkGsonHttpEntity.java b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkGsonHttpEntity.java new file mode 100644 index 00000000000..7d0cdb3a648 --- /dev/null +++ b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkGsonHttpEntity.java @@ -0,0 +1,51 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.search.backend.elasticsearch.client.jdk.impl; + +import java.io.IOException; +import java.net.http.HttpRequest; +import java.nio.ByteBuffer; +import java.util.List; +import java.util.concurrent.Flow; + +import org.hibernate.search.backend.elasticsearch.client.common.gson.entity.spi.GsonHttpEntityContentProvider; +import org.hibernate.search.backend.elasticsearch.client.common.spi.ElasticsearchRequest; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; + +public class ClientJdkGsonHttpEntity extends GsonHttpEntityContentProvider implements HttpRequest.BodyPublisher { + + private static final HttpRequest.BodyPublisher NO_BODY_PUBLISHER = HttpRequest.BodyPublishers.noBody(); + + public static HttpRequest.BodyPublisher toEntity(Gson gson, ElasticsearchRequest request) throws IOException { + final List bodyParts = request.bodyParts(); + if ( bodyParts.isEmpty() ) { + return NO_BODY_PUBLISHER; + } + return new ClientJdkGsonHttpEntity( gson, bodyParts ); + } + + private final HttpRequest.BodyPublisher delegate; + + public ClientJdkGsonHttpEntity(Gson gson, List bodyParts) throws IOException { + super( gson, bodyParts ); + delegate = HttpRequest.BodyPublishers.ofInputStream( this::getContent ); + } + + @Override + public long contentLength() { + return getContentLength(); + } + + @Override + public void subscribe(Flow.Subscriber subscriber) { + delegate.subscribe( subscriber ); + } + + static boolean isNoBodyPublisher(HttpRequest.BodyPublisher bodyPublisher) { + return bodyPublisher == NO_BODY_PUBLISHER || bodyPublisher.contentLength() == 0; + } +} diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkHttpRequestInterceptor.java b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkHttpRequestInterceptor.java new file mode 100644 index 00000000000..7fa391fa3ec --- /dev/null +++ b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkHttpRequestInterceptor.java @@ -0,0 +1,124 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.search.backend.elasticsearch.client.jdk.impl; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URLDecoder; +import java.net.http.HttpRequest; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.hibernate.search.backend.elasticsearch.client.common.spi.ElasticsearchRequestInterceptor; +import org.hibernate.search.backend.elasticsearch.client.common.spi.ElasticsearchRequestInterceptorContext; + + +record ClientJdkHttpRequestInterceptor(ElasticsearchRequestInterceptor elasticsearchRequestInterceptor) + implements HttpRequestInterceptor { + + @Override + public void process(HttpRequest.Builder request, HttpRequest.BodyPublisher bodyPublisher, + HttpRequestInterceptorContext context) + throws IOException { + elasticsearchRequestInterceptor.intercept( + new ClientJavaRequestContext( request.copy().build(), request, bodyPublisher, context ) + ); + } + + private record ClientJavaRequestContext(HttpRequest request, HttpRequest.Builder original, + HttpRequest.BodyPublisher bodyPublisher, HttpRequestInterceptorContext context) + implements ElasticsearchRequestInterceptorContext { + + @Override + public boolean hasContent() { + return !ClientJdkGsonHttpEntity.isNoBodyPublisher( bodyPublisher ); + } + + @Override + public InputStream content() { + if ( bodyPublisher instanceof ClientJdkGsonHttpEntity publisher ) { + return publisher.getContent(); + } + return null; + } + + @Override + public String scheme() { + return request.uri().getScheme(); + } + + @Override + public String host() { + return request.uri().getHost(); + } + + @Override + public Integer port() { + return request.uri().getPort(); + } + + @Override + public String method() { + return context().method(); + } + + @Override + public String path() { + return request.uri().getPath(); + } + + @Override + public Map queryParameters() { + String query = request.uri().getQuery(); + if ( query == null || query.isEmpty() ) { + return Map.of(); + } + + Map map = new HashMap<>(); + + String[] params = query.split( "&" ); + + for ( String param : params ) { + String[] pair = param.split( "=", 2 ); + + if ( pair.length == 2 ) { + map.put( + URLDecoder.decode( pair[0], StandardCharsets.UTF_8 ), + URLDecoder.decode( pair[1], StandardCharsets.UTF_8 ) + ); + } + else { + map.put( URLDecoder.decode( pair[0], StandardCharsets.UTF_8 ), "" ); + } + } + + return map; + } + + @Override + public void overrideHeaders(Map> headers) { + for ( Map.Entry> header : headers.entrySet() ) { + String name = header.getKey(); + boolean first = true; + for ( String value : header.getValue() ) { + if ( first ) { + original.setHeader( name, value ); + first = false; + } + else { + original.header( name, value ); + } + } + } + } + + @Override + public String toString() { + return request.toString(); + } + } +} diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/HttpRequestInterceptor.java b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/HttpRequestInterceptor.java new file mode 100644 index 00000000000..7573d1eb408 --- /dev/null +++ b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/HttpRequestInterceptor.java @@ -0,0 +1,13 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.search.backend.elasticsearch.client.jdk.impl; + +import java.io.IOException; +import java.net.http.HttpRequest; + +interface HttpRequestInterceptor { + void process(HttpRequest.Builder request, HttpRequest.BodyPublisher bodyPublisher, HttpRequestInterceptorContext context) + throws IOException; +} diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/HttpRequestInterceptorContext.java b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/HttpRequestInterceptorContext.java new file mode 100644 index 00000000000..29fba99ee16 --- /dev/null +++ b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/HttpRequestInterceptorContext.java @@ -0,0 +1,8 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.search.backend.elasticsearch.client.jdk.impl; + +record HttpRequestInterceptorContext(String method) { +} diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/logging/impl/ElasticsearchClientLog.java b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/logging/impl/ElasticsearchClientLog.java new file mode 100644 index 00000000000..df6748e5294 --- /dev/null +++ b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/logging/impl/ElasticsearchClientLog.java @@ -0,0 +1,29 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.search.backend.elasticsearch.client.jdk.logging.impl; + +import java.lang.invoke.MethodHandles; + +import org.hibernate.search.util.common.logging.CategorizedLogger; +import org.hibernate.search.util.common.logging.impl.LoggerFactory; +import org.hibernate.search.util.common.logging.impl.MessageConstants; + +import org.jboss.logging.annotations.MessageLogger; + +@CategorizedLogger( + category = ElasticsearchClientLog.CATEGORY_NAME, + description = """ + Logs information on low-level Elasticsearch backend operations. + + + This may include warnings about misconfigured Elasticsearch REST clients or index operations. + """ +) +@MessageLogger(projectCode = MessageConstants.PROJECT_CODE) +public interface ElasticsearchClientLog { + String CATEGORY_NAME = "org.hibernate.search.elasticsearch.client"; + + ElasticsearchClientLog INSTANCE = LoggerFactory.make( ElasticsearchClientLog.class, CATEGORY_NAME, MethodHandles.lookup() ); + +} diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/package-info.java b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/package-info.java new file mode 100644 index 00000000000..3bf2cce274e --- /dev/null +++ b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/package-info.java @@ -0,0 +1 @@ +package org.hibernate.search.backend.elasticsearch.client.jdk; diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/resources/META-INF/services/org.hibernate.search.engine.environment.bean.spi.BeanConfigurer b/backend/elasticsearch-client/jdk-rest-client/src/main/resources/META-INF/services/org.hibernate.search.engine.environment.bean.spi.BeanConfigurer new file mode 100644 index 00000000000..9125dac4b1e --- /dev/null +++ b/backend/elasticsearch-client/jdk-rest-client/src/main/resources/META-INF/services/org.hibernate.search.engine.environment.bean.spi.BeanConfigurer @@ -0,0 +1 @@ +org.hibernate.search.backend.elasticsearch.client.jdk.impl.ClientJdkElasticsearchClientBeanConfigurer diff --git a/bom/platform-common/pom.xml b/bom/platform-common/pom.xml index 88d68d461b6..45b1949f844 100644 --- a/bom/platform-common/pom.xml +++ b/bom/platform-common/pom.xml @@ -86,6 +86,11 @@ hibernate-search-backend-elasticsearch-client-opensearch-rest ${project.version} + + org.hibernate.search + hibernate-search-backend-elasticsearch-client-jdk + ${project.version} + org.hibernate.search hibernate-search-mapper-pojo-base diff --git a/bom/public/pom.xml b/bom/public/pom.xml index f85cecd4650..4d811953184 100644 --- a/bom/public/pom.xml +++ b/bom/public/pom.xml @@ -52,6 +52,11 @@ hibernate-search-backend-elasticsearch-client-rest5 ${project.version} + + org.hibernate.search + hibernate-search-backend-elasticsearch-client-jdk + ${project.version} + org.hibernate.search hibernate-search-backend-elasticsearch-client-opensearch-rest diff --git a/build/jqassistant/rules/rules.xml b/build/jqassistant/rules/rules.xml index 142463b94dd..dbfe3d5113d 100644 --- a/build/jqassistant/rules/rules.xml +++ b/build/jqassistant/rules/rules.xml @@ -286,6 +286,7 @@ WHEN 'hibernate-search-backend-elasticsearch-client-rest4' THEN 'ClientRest4' WHEN 'hibernate-search-backend-elasticsearch-client-rest5' THEN 'ClientRest5' WHEN 'hibernate-search-backend-elasticsearch-client-opensearch-rest' THEN 'ClientOpenSearch' + WHEN 'hibernate-search-backend-elasticsearch-client-jdk' THEN 'ClientJdk' ELSE 'UNKNOWN-MODULE-SPECIFIC-KEYWORD-PLEASE-UPDATE-JQASSISTANT-RULES' END RETURN diff --git a/build/parents/build/pom.xml b/build/parents/build/pom.xml index 045b56ab6da..171cb438cc1 100644 --- a/build/parents/build/pom.xml +++ b/build/parents/build/pom.xml @@ -317,6 +317,11 @@ hibernate-search-backend-elasticsearch-client-opensearch-rest ${project.version} + + org.hibernate.search + hibernate-search-backend-elasticsearch-client-jdk + ${project.version} + org.hibernate.search hibernate-search-backend-elasticsearch-aws diff --git a/build/reports/pom.xml b/build/reports/pom.xml index fcbd3ac824a..66577663a25 100644 --- a/build/reports/pom.xml +++ b/build/reports/pom.xml @@ -62,6 +62,10 @@ org.hibernate.search hibernate-search-backend-elasticsearch-client-opensearch-rest + + org.hibernate.search + hibernate-search-backend-elasticsearch-client-jdk + org.hibernate.search hibernate-search-mapper-pojo-base diff --git a/distribution/pom.xml b/distribution/pom.xml index 704635af21f..f27fb53d001 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -105,6 +105,11 @@ hibernate-search-backend-elasticsearch-client-opensearch-rest compile + + org.hibernate.search + hibernate-search-backend-elasticsearch-client-jdk + compile + org.hibernate.search hibernate-search-v5migrationhelper-engine @@ -275,6 +280,7 @@ ${basedir}/../backend/elasticsearch-client/elasticsearch-rest4-client/src/main/java; ${basedir}/../backend/elasticsearch-client/elasticsearch-rest5-client/src/main/java; ${basedir}/../backend/elasticsearch-client/opensearch-rest-client/src/main/java; + ${basedir}/../backend/elasticsearch-client/jdk-rest-client/src/main/java; ${basedir}/../backend/elasticsearch-aws/src/main/java; ${basedir}/../backend/lucene/src/main/java; ${basedir}/../mapper/orm-outbox-polling/src/main/java; @@ -289,8 +295,9 @@ ${basedir}/../backend/elasticsearch/target/generated-sources/annotations; ${basedir}/../backend/elasticsearch-client/common/target/generated-sources/annotations; ${basedir}/../backend/elasticsearch-client/elasticsearch-rest4-client/target/generated-sources/annotations; - ${basedir}/../backend/elasticsearch-client/opensearch-rest-client/target/generated-sources/annotations; ${basedir}/../backend/elasticsearch-client/elasticsearch-rest5-client/target/generated-sources/annotations; + ${basedir}/../backend/elasticsearch-client/opensearch-rest-client/target/generated-sources/annotations; + ${basedir}/../backend/elasticsearch-client/jdk-rest-client/target/generated-sources/annotations; ${basedir}/../backend/elasticsearch-aws/target/generated-sources/annotations; ${basedir}/../backend/lucene/target/generated-sources/annotations; ${basedir}/../mapper/orm-outbox-polling/src/main/avro/generated; diff --git a/documentation/pom.xml b/documentation/pom.xml index eb88781db83..2c285bfadd3 100644 --- a/documentation/pom.xml +++ b/documentation/pom.xml @@ -26,10 +26,13 @@ ${failsafe.elasticsearch.rest5.reportsDirectory}/failsafe-summary.xml ${project.build.directory}/failsafe-reports/elasticsearch-opensearch ${failsafe.elasticsearch.opensearch.reportsDirectory}/failsafe-summary.xml + ${project.build.directory}/failsafe-reports/elasticsearch-jdk + ${failsafe.elasticsearch.jdk.reportsDirectory}/failsafe-summary.xml + ${project.build.directory}/asciidoctor/ ${project.build.directory}/hibernate-asciidoctor-theme/asciidoc @@ -82,6 +85,11 @@ hibernate-search-backend-elasticsearch-client-rest5 test + + org.hibernate.search + hibernate-search-backend-elasticsearch-client-jdk + test + ${project.groupId} hibernate-search-processor @@ -197,6 +205,7 @@ org.hibernate.search:hibernate-search-backend-elasticsearch-client-rest4 org.hibernate.search:hibernate-search-backend-elasticsearch-client-rest5 org.hibernate.search:hibernate-search-backend-elasticsearch-client-opensearch-rest + org.hibernate.search:hibernate-search-backend-elasticsearch-client-jdk lucene @@ -221,14 +230,16 @@ org.hibernate.search:hibernate-search-backend-lucene org.hibernate.search:hibernate-search-backend-elasticsearch-client-rest5 org.hibernate.search:hibernate-search-backend-elasticsearch-client-opensearch-rest + org.hibernate.search:hibernate-search-backend-elasticsearch-client-jdk elasticsearch **/Lucene*IT - **/client/java/*IT + **/client/rest5/*IT **/client/opensearch/*IT + **/client/jdk/*IT @@ -247,12 +258,13 @@ org.hibernate.search:hibernate-search-backend-lucene org.hibernate.search:hibernate-search-backend-elasticsearch-client-rest4 org.hibernate.search:hibernate-search-backend-elasticsearch-client-opensearch-rest + org.hibernate.search:hibernate-search-backend-elasticsearch-client-jdk elasticsearch - **/client/java/*IT + **/client/rest5/*IT @@ -271,6 +283,7 @@ org.hibernate.search:hibernate-search-backend-lucene org.hibernate.search:hibernate-search-backend-elasticsearch-client-rest4 org.hibernate.search:hibernate-search-backend-elasticsearch-client-rest5 + org.hibernate.search:hibernate-search-backend-elasticsearch-client-jdk elasticsearch @@ -280,6 +293,31 @@ + + it-elasticsearch-jdk + + integration-test + + + ${test.elasticsearch.skip} + ${failsafe.jvm.args.no-jacoco} @{failsafe.jvm.args.jacoco.elasticsearch.jdk} + ${surefire.executionIdentifier}-elasticsearch-jdk + ${failsafe.elasticsearch.jdk.reportsDirectory} + ${failsafe.elasticsearch.jdk.summaryFile} + + org.hibernate.search:hibernate-search-backend-lucene + org.hibernate.search:hibernate-search-backend-elasticsearch-client-rest4 + org.hibernate.search:hibernate-search-backend-elasticsearch-client-rest5 + org.hibernate.search:hibernate-search-backend-elasticsearch-client-opensearch-rest + + + elasticsearch + + + **/client/jdk/*IT + + + it-verify @@ -291,6 +329,7 @@ ${failsafe.elasticsearch.summaryFile} ${failsafe.elasticsearch.rest5.summaryFile} ${failsafe.elasticsearch.opensearch.summaryFile} + ${failsafe.elasticsearch.jdk.summaryFile} @@ -613,6 +652,7 @@ ${rootProject.empty.failsafe.summaryFile} ${rootProject.empty.failsafe.summaryFile} ${rootProject.empty.failsafe.summaryFile} + ${rootProject.empty.failsafe.summaryFile} diff --git a/documentation/src/main/asciidoc/public/reference/_backend-elasticsearch.adoc b/documentation/src/main/asciidoc/public/reference/_backend-elasticsearch.adoc index 03b9a9fc289..e4bb089f97f 100644 --- a/documentation/src/main/asciidoc/public/reference/_backend-elasticsearch.adoc +++ b/documentation/src/main/asciidoc/public/reference/_backend-elasticsearch.adoc @@ -503,7 +503,7 @@ for example `class:org.hibernate.search.documentation.backend.elasticsearch.clie ==== [source, java, indent=0, subs="+callouts"] ---- -include::{sourcedir}/org/hibernate/search/documentation/backend/elasticsearch/client/rest/HttpClientConfigurer.java[tags=include] +include::{sourcedir}/org/hibernate/search/documentation/backend/elasticsearch/client/rest4/HttpClientConfigurer.java[tags=include] ---- <1> The class has to implement the `ElasticsearchHttpClientConfigurer` interface. <2> The `configure` method provides the access to the `ElasticsearchHttpClientConfigurationContext`. @@ -546,7 +546,7 @@ for example `class:org.hibernate.search.documentation.backend.elasticsearch.clie ==== [source, java, indent=0, subs="+callouts"] ---- -include::{sourcedir}/org/hibernate/search/documentation/backend/elasticsearch/client/java/HttpClientConfigurer.java[tags=include] +include::{sourcedir}/org/hibernate/search/documentation/backend/elasticsearch/client/rest5/HttpClientConfigurer.java[tags=include] ---- <1> The class has to implement the `ElasticsearchHttpClientConfigurer` interface. <2> The `configure` method provides the access to the `ElasticsearchHttpClientConfigurationContext`. @@ -558,7 +558,7 @@ include::{sourcedir}/org/hibernate/search/documentation/backend/elasticsearch/cl ==== [source, xml, indent=0, subs="+callouts"] ---- -include::{resourcesdir}/configuration/http-client-configurer-java.properties[tags=include] +include::{resourcesdir}/configuration/http-client-configurer-rest5.properties[tags=include] ---- <1> Specify the HTTP client configurer. ==== @@ -589,7 +589,7 @@ for example `class:org.hibernate.search.documentation.backend.elasticsearch.clie ==== [source, java, indent=0, subs="+callouts"] ---- -include::{sourcedir}/org/hibernate/search/documentation/backend/elasticsearch/client/java/HttpClientConfigurer.java[tags=include] +include::{sourcedir}/org/hibernate/search/documentation/backend/elasticsearch/client/opensearch/HttpClientConfigurer.java[tags=include] ---- <1> The class has to implement the `ElasticsearchHttpClientConfigurer` interface. <2> The `configure` method provides the access to the `ElasticsearchHttpClientConfigurationContext`. diff --git a/documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/java/ElasticsearchHttpClientConfigurerIT.java b/documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/jdk/ElasticsearchHttpClientConfigurerIT.java similarity index 94% rename from documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/java/ElasticsearchHttpClientConfigurerIT.java rename to documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/jdk/ElasticsearchHttpClientConfigurerIT.java index 7c60c61dfcb..643c1243a47 100644 --- a/documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/java/ElasticsearchHttpClientConfigurerIT.java +++ b/documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/jdk/ElasticsearchHttpClientConfigurerIT.java @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.search.documentation.backend.elasticsearch.client.java; +package org.hibernate.search.documentation.backend.elasticsearch.client.jdk; import static org.assertj.core.api.Assertions.assertThat; @@ -33,7 +33,7 @@ void smoke() { assertThat( staticCounters.get( HttpClientConfigurer.INSTANCES ) ).isZero(); setupHelper.start() - .withProperties( "/configuration/http-client-configurer-java.properties" ) + .withProperties( "/configuration/http-client-configurer-jdk.properties" ) .setup( IndexedEntity.class ); assertThat( staticCounters.get( HttpClientConfigurer.INSTANCES ) ).isEqualTo( 1 ); diff --git a/documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/jdk/HttpClientConfigurer.java b/documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/jdk/HttpClientConfigurer.java new file mode 100644 index 00000000000..bc4e9b65dd6 --- /dev/null +++ b/documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/jdk/HttpClientConfigurer.java @@ -0,0 +1,34 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.search.documentation.backend.elasticsearch.client.jdk; + + +import java.net.http.HttpClient; +import java.time.Duration; + +import org.hibernate.search.backend.elasticsearch.client.jdk.ElasticsearchHttpClientConfigurationContext; +import org.hibernate.search.backend.elasticsearch.client.jdk.ElasticsearchHttpClientConfigurer; +import org.hibernate.search.util.impl.test.extension.StaticCounters; + + +// tag::include[] +public class HttpClientConfigurer implements ElasticsearchHttpClientConfigurer { // <1> + // end::include[] + static final StaticCounters.Key INSTANCES = StaticCounters.createKey(); + + public HttpClientConfigurer() { + StaticCounters.get().increment( INSTANCES ); + } + + @SuppressWarnings("unused") + // tag::include[] + + @Override + public void configure(ElasticsearchHttpClientConfigurationContext context) { // <2> + HttpClient.Builder builder = context.clientBuilder(); // <3> + builder.connectTimeout( Duration.ofSeconds( 2 ) ); // <4> + } +} +// end::include[] diff --git a/documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/rest/ElasticsearchHttpClientConfigurerIT.java b/documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/rest4/ElasticsearchHttpClientConfigurerIT.java similarity index 99% rename from documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/rest/ElasticsearchHttpClientConfigurerIT.java rename to documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/rest4/ElasticsearchHttpClientConfigurerIT.java index b1cefb90307..0a12f290196 100644 --- a/documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/rest/ElasticsearchHttpClientConfigurerIT.java +++ b/documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/rest4/ElasticsearchHttpClientConfigurerIT.java @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.search.documentation.backend.elasticsearch.client.rest; +package org.hibernate.search.documentation.backend.elasticsearch.client.rest4; import static org.assertj.core.api.Assertions.assertThat; diff --git a/documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/rest/HttpClientConfigurer.java b/documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/rest4/HttpClientConfigurer.java similarity index 98% rename from documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/rest/HttpClientConfigurer.java rename to documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/rest4/HttpClientConfigurer.java index ed27e585b33..0d0d8f2430a 100644 --- a/documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/rest/HttpClientConfigurer.java +++ b/documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/rest4/HttpClientConfigurer.java @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.search.documentation.backend.elasticsearch.client.rest; +package org.hibernate.search.documentation.backend.elasticsearch.client.rest4; import org.hibernate.search.backend.elasticsearch.client.rest4.ElasticsearchHttpClientConfigurationContext; import org.hibernate.search.backend.elasticsearch.client.rest4.ElasticsearchHttpClientConfigurer; diff --git a/documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/rest5/ElasticsearchHttpClientConfigurerIT.java b/documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/rest5/ElasticsearchHttpClientConfigurerIT.java new file mode 100644 index 00000000000..c286513a5a1 --- /dev/null +++ b/documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/rest5/ElasticsearchHttpClientConfigurerIT.java @@ -0,0 +1,64 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.search.documentation.backend.elasticsearch.client.rest5; + +import static org.assertj.core.api.Assertions.assertThat; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; + +import org.hibernate.search.documentation.testsupport.BackendConfigurations; +import org.hibernate.search.documentation.testsupport.DocumentationSetupHelper; +import org.hibernate.search.mapper.pojo.mapping.definition.annotation.Indexed; +import org.hibernate.search.mapper.pojo.mapping.definition.annotation.KeywordField; +import org.hibernate.search.util.impl.test.extension.StaticCounters; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +class ElasticsearchHttpClientConfigurerIT { + + @RegisterExtension + public DocumentationSetupHelper setupHelper = DocumentationSetupHelper.withSingleBackend( + BackendConfigurations.simple() ); + + @RegisterExtension + public StaticCounters staticCounters = StaticCounters.create(); + + @Test + void smoke() { + assertThat( staticCounters.get( HttpClientConfigurer.INSTANCES ) ).isZero(); + + setupHelper.start() + .withProperties( "/configuration/http-client-configurer-rest5.properties" ) + .setup( IndexedEntity.class ); + + assertThat( staticCounters.get( HttpClientConfigurer.INSTANCES ) ).isEqualTo( 1 ); + } + + @Entity(name = IndexedEntity.NAME) + @Indexed + static class IndexedEntity { + + static final String NAME = "indexed"; + + @Id + @GeneratedValue + private Integer id; + + @KeywordField + private String text; + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + } + +} diff --git a/documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/java/HttpClientConfigurer.java b/documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/rest5/HttpClientConfigurer.java similarity index 99% rename from documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/java/HttpClientConfigurer.java rename to documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/rest5/HttpClientConfigurer.java index f4c1ea55972..15f27ea27ae 100644 --- a/documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/java/HttpClientConfigurer.java +++ b/documentation/src/test/java/org/hibernate/search/documentation/backend/elasticsearch/client/rest5/HttpClientConfigurer.java @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.search.documentation.backend.elasticsearch.client.java; +package org.hibernate.search.documentation.backend.elasticsearch.client.rest5; import org.hibernate.search.backend.elasticsearch.client.rest5.ElasticsearchHttpClientConfigurationContext; import org.hibernate.search.backend.elasticsearch.client.rest5.ElasticsearchHttpClientConfigurer; diff --git a/documentation/src/test/resources/configuration/http-client-configurer-java.properties b/documentation/src/test/resources/configuration/http-client-configurer-jdk.properties similarity index 71% rename from documentation/src/test/resources/configuration/http-client-configurer-java.properties rename to documentation/src/test/resources/configuration/http-client-configurer-jdk.properties index a1d0816c717..6ebf3db372a 100644 --- a/documentation/src/test/resources/configuration/http-client-configurer-java.properties +++ b/documentation/src/test/resources/configuration/http-client-configurer-jdk.properties @@ -3,5 +3,5 @@ # tag::include[] # <1> -hibernate.search.backend.client.configurer = class:org.hibernate.search.documentation.backend.elasticsearch.client.java.HttpClientConfigurer +hibernate.search.backend.client.configurer = class:org.hibernate.search.documentation.backend.elasticsearch.client.jdk.HttpClientConfigurer # end::include[] diff --git a/documentation/src/test/resources/configuration/http-client-configurer-rest5.properties b/documentation/src/test/resources/configuration/http-client-configurer-rest5.properties new file mode 100644 index 00000000000..9c19ecc5264 --- /dev/null +++ b/documentation/src/test/resources/configuration/http-client-configurer-rest5.properties @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright Red Hat Inc. and Hibernate Authors + +# tag::include[] +# <1> +hibernate.search.backend.client.configurer = class:org.hibernate.search.documentation.backend.elasticsearch.client.rest5.HttpClientConfigurer +# end::include[] diff --git a/documentation/src/test/resources/configuration/http-client-configurer.properties b/documentation/src/test/resources/configuration/http-client-configurer.properties index 39254336939..cbbd123eb95 100644 --- a/documentation/src/test/resources/configuration/http-client-configurer.properties +++ b/documentation/src/test/resources/configuration/http-client-configurer.properties @@ -3,5 +3,5 @@ # tag::include[] # <1> -hibernate.search.backend.client.configurer = class:org.hibernate.search.documentation.backend.elasticsearch.client.rest.HttpClientConfigurer +hibernate.search.backend.client.configurer = class:org.hibernate.search.documentation.backend.elasticsearch.client.rest4.HttpClientConfigurer # end::include[] diff --git a/integrationtest/backend/elasticsearch/pom.xml b/integrationtest/backend/elasticsearch/pom.xml index 0bcbb60d786..6789c89bcea 100644 --- a/integrationtest/backend/elasticsearch/pom.xml +++ b/integrationtest/backend/elasticsearch/pom.xml @@ -27,6 +27,10 @@ ${failsafe.client.elasticsearch.rest5.reportsDirectory}/failsafe-summary.xml + ${project.build.directory}/failsafe-reports/elasticsearch-jdk + ${failsafe.client.jdk.reportsDirectory}/failsafe-summary.xml + + ${test.mockito.agent.jvm.args} @@ -50,6 +54,10 @@ org.hibernate.search hibernate-search-backend-elasticsearch-client-rest4 + + org.hibernate.search + hibernate-search-backend-elasticsearch-client-jdk + org.hibernate.search @@ -105,6 +113,7 @@ org.hibernate.search:hibernate-search-backend-elasticsearch-client-opensearch-rest org.hibernate.search:hibernate-search-backend-elasticsearch-client-rest5 + org.hibernate.search:hibernate-search-backend-elasticsearch-client-jdk org.hibernate.search.integrationtest.backend.elasticsearch.client.ClientRest5ElasticsearchClientFactoryIT @@ -130,6 +139,7 @@ org.hibernate.search:hibernate-search-backend-elasticsearch-client-rest5 + org.hibernate.search:hibernate-search-backend-elasticsearch-client-jdk org.hibernate.search.integrationtest.backend.elasticsearch.client.ClientRest5ElasticsearchClientFactoryIT @@ -154,11 +164,40 @@ org.hibernate.search:hibernate-search-backend-elasticsearch-client-rest4 org.hibernate.search:hibernate-search-backend-elasticsearch-client-opensearch-rest + org.hibernate.search:hibernate-search-backend-elasticsearch-client-jdk + + + org.hibernate.search.integrationtest.backend.elasticsearch.client.ClientRest4ElasticsearchClientFactoryIT + org.hibernate.search.integrationtest.backend.elasticsearch.client.ClientOpenSearchElasticsearchClientFactoryIT + org.hibernate.search.integrationtest.backend.elasticsearch.ClientRest4ElasticsearchExtensionIT + org.hibernate.search.integrationtest.backend.elasticsearch.ClientOpenSearchElasticsearchExtensionIT + + + + + it-jdk-client + + integration-test + verify + + + false + ${test.elasticsearch.skip} + ${surefire.executionIdentifier}-jdk + ${failsafe.client.jdk.reportsDirectory} + ${failsafe.client.jdk.summaryFile} + ${failsafe.jvm.args.no-jacoco} @{failsafe.jvm.args.jacoco.client.jdk} + + org.hibernate.search:hibernate-search-backend-elasticsearch-client-rest4 + org.hibernate.search:hibernate-search-backend-elasticsearch-client-rest5 + org.hibernate.search:hibernate-search-backend-elasticsearch-client-opensearch-rest org.hibernate.search.integrationtest.backend.elasticsearch.client.ClientRest4ElasticsearchClientFactoryIT + org.hibernate.search.integrationtest.backend.elasticsearch.client.ClientRest5ElasticsearchClientFactoryIT org.hibernate.search.integrationtest.backend.elasticsearch.client.ClientOpenSearchElasticsearchClientFactoryIT org.hibernate.search.integrationtest.backend.elasticsearch.ClientRest4ElasticsearchExtensionIT + org.hibernate.search.integrationtest.backend.elasticsearch.ClientRest5ElasticsearchExtensionIT org.hibernate.search.integrationtest.backend.elasticsearch.ClientOpenSearchElasticsearchExtensionIT @@ -234,6 +273,17 @@ ${project.build.directory}/${jacoco.environment.sub-directory}/opensearch/jacoco.exec + + jacoco-prepare-agent-integration-jdk + initialize + + prepare-agent-integration + + + failsafe.jvm.args.jacoco.client.jdk + ${project.build.directory}/${jacoco.environment.sub-directory}/jdk/jacoco.exec + + diff --git a/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/bootstrap/ElasticsearchBootstrapFailureIT.java b/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/bootstrap/ElasticsearchBootstrapFailureIT.java index d6c56ed14ae..32312e3a6b8 100644 --- a/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/bootstrap/ElasticsearchBootstrapFailureIT.java +++ b/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/bootstrap/ElasticsearchBootstrapFailureIT.java @@ -55,8 +55,8 @@ void cannotConnect() { .defaultBackendContext() .failure( "Unable to detect the Elasticsearch version running on the cluster", - "Elasticsearch request failed", - "Connection refused" + "Elasticsearch request failed" + // , "Connection refused" ) ); } diff --git a/lucene-next/documentation/pom.xml b/lucene-next/documentation/pom.xml index dcd1c7a004b..b88e0954b20 100644 --- a/lucene-next/documentation/pom.xml +++ b/lucene-next/documentation/pom.xml @@ -66,6 +66,11 @@ hibernate-search-backend-elasticsearch-client-rest4 test + + org.hibernate.search + hibernate-search-backend-elasticsearch-client-jdk + test + ${project.groupId} hibernate-search-util-internal-integrationtest-mapper-orm @@ -180,6 +185,7 @@ org.hibernate.search:hibernate-search-backend-elasticsearch-client-rest4 org.hibernate.search:hibernate-search-backend-elasticsearch-client-rest5 org.hibernate.search:hibernate-search-backend-elasticsearch-client-opensearch-rest + org.hibernate.search:hibernate-search-backend-elasticsearch-client-jdk lucene diff --git a/pom.xml b/pom.xml index f913a9ed25c..40acba5bc27 100644 --- a/pom.xml +++ b/pom.xml @@ -177,6 +177,7 @@ backend/elasticsearch-client/elasticsearch-rest4-client backend/elasticsearch-client/elasticsearch-rest5-client backend/elasticsearch-client/opensearch-rest-client + backend/elasticsearch-client/jdk-rest-client mapper/pojo-base mapper/pojo-standalone mapper/orm From 8429125e88c0646820f060678c07dbbb64a806ca Mon Sep 17 00:00:00 2001 From: marko-bekhta Date: Wed, 19 Nov 2025 14:45:50 +0100 Subject: [PATCH 2/4] HSEARCH-5482 Mention the JDK client in the docs --- .../ElasticsearchHttpClientConfigurer.java | 4 +- ...JdkElasticsearchBackendClientSettings.java | 1 - .../client/jdk/cfg/spi/NodeProvider.java | 15 ---- .../impl/ClientJdkHttpRequestInterceptor.java | 11 +++ .../src/main/asciidoc/migration/index.adoc | 1 + .../_all.adoc | 3 + .../_apache_based.adoc | 24 +++++++ .../reference/_backend-elasticsearch.adoc | 69 +++++++++++++++++-- 8 files changed, 106 insertions(+), 22 deletions(-) create mode 100644 documentation/src/main/asciidoc/public/components/elasticsearch-client-compatibility/_apache_based.adoc diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/ElasticsearchHttpClientConfigurer.java b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/ElasticsearchHttpClientConfigurer.java index a103972b6f7..cd405d3ec7b 100644 --- a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/ElasticsearchHttpClientConfigurer.java +++ b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/ElasticsearchHttpClientConfigurer.java @@ -7,7 +7,7 @@ import org.hibernate.search.util.common.annotation.Incubating; /** - * An extension point allowing fine tuning of the Apache HTTP Client used by the Elasticsearch integration. + * An extension point allowing fine-tuning of the JDK HTTP Client used by the Elasticsearch integration. *

* This enables in particular connecting to cloud services that require a particular authentication method, * such as request signing on Amazon Web Services. @@ -32,7 +32,7 @@ public interface ElasticsearchHttpClientConfigurer { * For example an authentication configurer could decide not to do anything if no username is provided, * or if the configuration property {@code my.configurer.enabled} is {@code false}. * - * @param context A configuration context giving access to the Apache HTTP client builder + * @param context A configuration context giving access to the JDK HTTP client builder * and configuration properties in particular. */ void configure(ElasticsearchHttpClientConfigurationContext context); diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/ClientJdkElasticsearchBackendClientSettings.java b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/ClientJdkElasticsearchBackendClientSettings.java index 506b9ad69af..f4d2fb1eb75 100644 --- a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/ClientJdkElasticsearchBackendClientSettings.java +++ b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/ClientJdkElasticsearchBackendClientSettings.java @@ -64,7 +64,6 @@ public static final class Defaults { private Defaults() { } - public static final int READ_TIMEOUT = 30000; public static final int CONNECTION_TIMEOUT = 1000; } } diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/spi/NodeProvider.java b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/spi/NodeProvider.java index 5cdbf01deec..e00996385e0 100644 --- a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/spi/NodeProvider.java +++ b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/spi/NodeProvider.java @@ -144,22 +144,16 @@ public boolean isSslEnabled() { } public static final class ServerNode { - private static final long RETRY_DELAY_MILLISECONDS = 1_000L; private final String protocol; private final String host; private final String basePath; private final int port; - private volatile Status status; - private volatile long retryAfterMillis; - private ServerNode next; public ServerNode(String protocol, String host, String basePath, int port) { this.protocol = protocol; this.host = host; this.basePath = normalizeBasePath( basePath ); this.port = port; - this.status = Status.ACTIVE; - this.retryAfterMillis = -1; } private String normalizeBasePath(String basePath) { @@ -212,15 +206,6 @@ public URI createRequestURI(String path, Map parameters) { } } - public void failing() { - this.status = Status.FAILING; - this.retryAfterMillis = System.currentTimeMillis() + RETRY_DELAY_MILLISECONDS; - } - - private void setNext(ServerNode next) { - this.next = next; - } - @Override public boolean equals(Object o) { if ( !( o instanceof ServerNode that ) ) { diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkHttpRequestInterceptor.java b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkHttpRequestInterceptor.java index 7fa391fa3ec..05cced7dd16 100644 --- a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkHttpRequestInterceptor.java +++ b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkHttpRequestInterceptor.java @@ -11,7 +11,9 @@ import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; +import java.util.Set; import org.hibernate.search.backend.elasticsearch.client.common.spi.ElasticsearchRequestInterceptor; import org.hibernate.search.backend.elasticsearch.client.common.spi.ElasticsearchRequestInterceptorContext; @@ -20,6 +22,11 @@ record ClientJdkHttpRequestInterceptor(ElasticsearchRequestInterceptor elasticsearchRequestInterceptor) implements HttpRequestInterceptor { + // https://docs.oracle.com/en/java/javase/25/docs/api/java.net.http/module-summary.html + // + // Host header is one of the restricted ^ so we skip it here: + private static final Set HEADERS_TO_IGNORE = Set.of( "host" ); + @Override public void process(HttpRequest.Builder request, HttpRequest.BodyPublisher bodyPublisher, HttpRequestInterceptorContext context) @@ -103,6 +110,10 @@ public Map queryParameters() { public void overrideHeaders(Map> headers) { for ( Map.Entry> header : headers.entrySet() ) { String name = header.getKey(); + // To prevent java.lang.IllegalArgumentException: restricted header name: "Header-name" + if ( HEADERS_TO_IGNORE.contains( name.toLowerCase( Locale.ROOT ) ) ) { + continue; + } boolean first = true; for ( String value : header.getValue() ) { if ( first ) { diff --git a/documentation/src/main/asciidoc/migration/index.adoc b/documentation/src/main/asciidoc/migration/index.adoc index 0da686a3d4a..ad29bbaa9f4 100644 --- a/documentation/src/main/asciidoc/migration/index.adoc +++ b/documentation/src/main/asciidoc/migration/index.adoc @@ -61,6 +61,7 @@ Currently available options are: * `org.hibernate.search:hibernate-search-backend-elasticsearch-client-rest4` backed by `org.elasticsearch.client:elasticsearch-rest-client` * `org.hibernate.search:hibernate-search-backend-elasticsearch-client-rest5` backed by `co.elastic.clients:elasticsearch-rest5-client` * `org.hibernate.search:hibernate-search-backend-elasticsearch-client-opensearch-rest` backed by `org.opensearch.client:opensearch-rest-client` +* `org.hibernate.search:hibernate-search-backend-elasticsearch-client-jdk` backed by `java.net.http.HttpClient` [[data-format]] == Data format and schema diff --git a/documentation/src/main/asciidoc/public/components/elasticsearch-client-compatibility/_all.adoc b/documentation/src/main/asciidoc/public/components/elasticsearch-client-compatibility/_all.adoc index 4eb21392087..eaa4cc2ac37 100644 --- a/documentation/src/main/asciidoc/public/components/elasticsearch-client-compatibility/_all.adoc +++ b/documentation/src/main/asciidoc/public/components/elasticsearch-client-compatibility/_all.adoc @@ -17,5 +17,8 @@ Configuration properties from this section are applicable to the following clien |<> ^| ✔ +|<> +^| ✔ {jdk-client-warn} + |=== ==== diff --git a/documentation/src/main/asciidoc/public/components/elasticsearch-client-compatibility/_apache_based.adoc b/documentation/src/main/asciidoc/public/components/elasticsearch-client-compatibility/_apache_based.adoc new file mode 100644 index 00000000000..6cd196f209e --- /dev/null +++ b/documentation/src/main/asciidoc/public/components/elasticsearch-client-compatibility/_apache_based.adoc @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Red Hat Inc. and Hibernate Authors +[NOTE] +==== +Configuration properties from this section are applicable to the following clients: + +[cols="3,2",options="header"] +|=== +|Client |Configuration property applicability + +|<> +^| ✔ + +|<> +^| ✔ + +|<> +^| ✔ + +|<> +^| ❌ {jdk-client-warn} + +|=== +==== diff --git a/documentation/src/main/asciidoc/public/reference/_backend-elasticsearch.adoc b/documentation/src/main/asciidoc/public/reference/_backend-elasticsearch.adoc index e4bb089f97f..5105f629645 100644 --- a/documentation/src/main/asciidoc/public/reference/_backend-elasticsearch.adoc +++ b/documentation/src/main/asciidoc/public/reference/_backend-elasticsearch.adoc @@ -170,6 +170,7 @@ which may change in future versions of Hibernate Search. You should explicitly define the REST client in the application dependencies, if it matters which one the Elasticsearch backend will pick. +:jdk-client-warn: === Available clients [[backend-elasticsearch-configuration-client-elasticsearch-client-rest4]] @@ -208,6 +209,23 @@ Underlying HTTP Client::: Apache HTTP Client 5 This Elasticsearch backend REST client is based on the OpenSearch low level client (`org.opensearch.client:opensearch-rest-client`). +[[backend-elasticsearch-configuration-client-elasticsearch-client-jdk]] +==== Simple REST client based on the JDKs `HttpClient` + +include::../components/_incubating-warning.adoc[] + +Coordinates:: +GroupID::: `org.hibernate.search` +ArtifactID::: `hibernate-search-backend-elasticsearch-client-jdk` +Underlying HTTP Client::: JDKs Http Client (`java.net.http.HttpClient`) + +This Elasticsearch backend REST client is based on the Http client that is part of the JDKs `java.net` API. +Mostly intended for very basic use cases, and may lack some features, +e.g. automatic node discovery, compared to the other clients. + +NOTE: JDKs Http client allows configuration though the system properties. +Consult the list of available properties for your JDK version, e.g. https://docs.oracle.com/en/java/javase/25/docs/api/java.net.http/module-summary.html[JDK 25] + [[backend-elasticsearch-configuration-hosts]] === Target hosts @@ -297,7 +315,7 @@ Expects a boolean value. The default for this property is `false`. * `discovery.refresh_interval` defines the interval between two executions of the automatic discovery. Expects a positive integer, in seconds. The default for this property is `10`. -include::../components/elasticsearch-client-compatibility/_all.adoc[] +include::../components/elasticsearch-client-compatibility/_apache_based.adoc[] [[backend-elasticsearch-authentication-http]] === HTTP authentication @@ -395,6 +413,7 @@ include::../components/elasticsearch-client-compatibility/_all.adoc[] [[backend-elasticsearch-configuration-connection-tuning]] === [[_connection_tuning]] Connection tuning +:jdk-client-warn: (Read timeout is not supported) Timeouts:: + [source, properties] @@ -418,6 +437,7 @@ These properties expect a positive < + include::../components/elasticsearch-client-compatibility/_all.adoc[] +:jdk-client-warn: (Configurable through JDKs Http client system properties) Connection pool:: + [source, properties] @@ -453,8 +473,9 @@ To prevent that from happening consider having the maximum number of connections ==== + -include::../components/elasticsearch-client-compatibility/_all.adoc[] +include::../components/elasticsearch-client-compatibility/_apache_based.adoc[] +:jdk-client-warn: "(Configurable through JDKs Http client system properties)" Keep Alive:: + [source, properties] @@ -472,7 +493,7 @@ the duration from the `Keep-Alive` header or the value of this property (if set) If this property is not set, only the `Keep-Alive` header is considered, and if it's absent, idle connections will be kept forever. + -include::../components/elasticsearch-client-compatibility/_all.adoc[] +include::../components/elasticsearch-client-compatibility/_apache_based.adoc[] [[backend-elasticsearch-configuration-http-client]] === [[_custom_http_client_configurations]] Custom HTTP client configurations @@ -485,7 +506,7 @@ See the following sections to learn how each of the clients can be configured. [[backend-elasticsearch-configuration-http-client-elasticsearch-rest]] === Elasticsearch low level client It is possible to directly configure the underlying Apache HTTP 4 client of the -<> +<> using an instance of `org.apache.http.impl.nio.client.HttpAsyncClientBuilder`. With this API you can add interceptors, change the keep alive, the max connections, @@ -611,6 +632,46 @@ include::{resourcesdir}/configuration/http-client-configurer-opensearch.properti Any setting defined by a custom http client configurer will override any other setting defined by Hibernate Search. ==== +[[backend-elasticsearch-configuration-http-client-elasticsearch-jdk]] +=== JDK `HttpClient` based REST client +It is possible to directly configure the underlying +<> +using an instance of `java.net.http.HttpClient.Builder`. + +Configuring the HTTP client directly requires two steps: + +. Define a class that implements the `org.hibernate.search.backend.elasticsearch.client.jdk.ElasticsearchHttpClientConfigurer` interface. +. Configure Hibernate Search to use that implementation by setting the configuration property +`hibernate.search.backend.client.configurer` +to a <> pointing to the implementation, +for example `class:org.hibernate.search.documentation.backend.elasticsearch.client.jdk.HttpClientConfigurer`. + +.Implementing and using a `ElasticsearchHttpClientConfigurer` +==== +[source, java, indent=0, subs="+callouts"] +---- +include::{sourcedir}/org/hibernate/search/documentation/backend/elasticsearch/client/jdk/HttpClientConfigurer.java[tags=include] +---- +<1> The class has to implement the `ElasticsearchHttpClientConfigurer` interface. +<2> The `configure` method provides the access to the `ElasticsearchHttpClientConfigurationContext`. +<3> From the context it is possible to get the `HttpClient.Builder`. +<4> Finally, you can use the builder to configure the client with your custom settings. +==== + +.Define a custom http client configurer in the properties +==== +[source, xml, indent=0, subs="+callouts"] +---- +include::{resourcesdir}/configuration/http-client-configurer-jdk.properties[tags=include] +---- +<1> Specify the HTTP client configurer. +==== + +[NOTE] +==== +Any setting defined by a custom http client configurer will override any other setting defined by Hibernate Search. +==== + [[backend-elasticsearch-configuration-version]] == [[backend-elasticsearch-configuration-dialect]] Version compatibility From 4d62f8d00100eb4289e97efcf6cfafc1dc400d33 Mon Sep 17 00:00:00 2001 From: marko-bekhta Date: Fri, 21 Nov 2025 11:23:35 +0100 Subject: [PATCH 3/4] HSEARCH-5482 Hide the REST JDK client in the impl package and allow passing a reference to the HttpClient instead --- ...ElasticsearchBackendClientSpiSettings.java | 12 ++++---- .../impl/ClientJdkElasticsearchClient.java | 1 - .../ClientJdkElasticsearchClientFactory.java | 28 ++++++++----------- .../jdk/{cfg/spi => impl}/NodeProvider.java | 2 +- .../jdk/{cfg/spi => impl}/RestJdkClient.java | 2 +- 5 files changed, 21 insertions(+), 24 deletions(-) rename backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/{cfg/spi => impl}/NodeProvider.java (99%) rename backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/{cfg/spi => impl}/RestJdkClient.java (95%) diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/spi/ClientJdkElasticsearchBackendClientSpiSettings.java b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/spi/ClientJdkElasticsearchBackendClientSpiSettings.java index b13b11449b3..f779481e02c 100644 --- a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/spi/ClientJdkElasticsearchBackendClientSpiSettings.java +++ b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/spi/ClientJdkElasticsearchBackendClientSpiSettings.java @@ -19,14 +19,16 @@ public final class ClientJdkElasticsearchBackendClientSpiSettings { public static final String PREFIX = EngineSettings.PREFIX + "backend."; /** - * An external Elasticsearch client instance that Hibernate Search should use for all requests to Elasticsearch. + * An external HTTP client instance that Hibernate Search should use for all requests to Elasticsearch. *

- * If this is set, Hibernate Search will not attempt to create its own Elasticsearch, - * and all other client-related configuration properties - * (hosts/uris, authentication, discovery, timeouts, max connections, configurer, ...) + * If this is set, Hibernate Search will not attempt to create its own {@link java.net.http.HttpClient}, + * and all client-related configuration properties (authentication, timeouts, configurer, ...) * will be ignored. *

- * Expects a reference to a bean of type {@link RestJdkClient}. + * Hibernate Search will still apply some configuration properties (e.g. hosts/uris) + * that are not handled by the {@link java.net.http.HttpClient} itself. + *

+ * Expects a reference to a bean of type {@link java.net.http.HttpClient}. *

* Defaults to nothing: if no client instance is provided, Hibernate Search will create its own. *

diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchClient.java b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchClient.java index e8c02baaca6..922c5df286d 100644 --- a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchClient.java +++ b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchClient.java @@ -30,7 +30,6 @@ import org.hibernate.search.backend.elasticsearch.client.common.spi.ElasticsearchRequest; import org.hibernate.search.backend.elasticsearch.client.common.spi.ElasticsearchResponse; import org.hibernate.search.backend.elasticsearch.client.common.util.spi.ElasticsearchClientUtils; -import org.hibernate.search.backend.elasticsearch.client.jdk.cfg.spi.RestJdkClient; import org.hibernate.search.backend.elasticsearch.logging.spi.ElasticsearchClientLog; import org.hibernate.search.backend.elasticsearch.logging.spi.ElasticsearchRequestLog; import org.hibernate.search.engine.common.execution.spi.SimpleScheduledExecutor; diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchClientFactory.java b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchClientFactory.java index d044e0fffc3..b381122c94a 100644 --- a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchClientFactory.java +++ b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchClientFactory.java @@ -30,8 +30,6 @@ import org.hibernate.search.backend.elasticsearch.client.jdk.ElasticsearchHttpClientConfigurer; import org.hibernate.search.backend.elasticsearch.client.jdk.cfg.ClientJdkElasticsearchBackendClientSettings; import org.hibernate.search.backend.elasticsearch.client.jdk.cfg.spi.ClientJdkElasticsearchBackendClientSpiSettings; -import org.hibernate.search.backend.elasticsearch.client.jdk.cfg.spi.NodeProvider; -import org.hibernate.search.backend.elasticsearch.client.jdk.cfg.spi.RestJdkClient; import org.hibernate.search.backend.elasticsearch.logging.spi.ConfigurationLog; import org.hibernate.search.engine.cfg.ConfigurationPropertySource; import org.hibernate.search.engine.cfg.spi.ConfigurationProperty; @@ -46,9 +44,9 @@ public class ClientJdkElasticsearchClientFactory implements ElasticsearchClientFactory { - private static final OptionalConfigurationProperty> CLIENT_INSTANCE = + private static final OptionalConfigurationProperty> CLIENT_INSTANCE = ConfigurationProperty.forKey( ClientJdkElasticsearchBackendClientSpiSettings.CLIENT_INSTANCE ) - .asBeanReference( RestJdkClient.class ) + .asBeanReference( HttpClient.class ) .build(); private static final OptionalConfigurationProperty> HOSTS = @@ -106,18 +104,10 @@ public ElasticsearchClientImplementor create(BeanResolver beanResolver, Configur GsonProvider gsonProvider) { Optional requestTimeoutMs = REQUEST_TIMEOUT.get( propertySource ); - Optional> providedRestClientHolder = CLIENT_INSTANCE.getAndMap( - propertySource, beanResolver::resolve ); - - BeanHolder restClientHolder; - if ( providedRestClientHolder.isPresent() ) { - restClientHolder = providedRestClientHolder.get(); - } - else { - NodeProvider nodeProvider = NodeProvider.fromOptionalStrings( PROTOCOL.get( propertySource ), - HOSTS.get( propertySource ), URIS.get( propertySource ), PATH_PREFIX.get( propertySource ) ); - restClientHolder = createClient( beanResolver, propertySource, threadProvider, threadNamePrefix, nodeProvider ); - } + NodeProvider nodeProvider = NodeProvider.fromOptionalStrings( PROTOCOL.get( propertySource ), + HOSTS.get( propertySource ), URIS.get( propertySource ), PATH_PREFIX.get( propertySource ) ); + BeanHolder restClientHolder = + createClient( beanResolver, propertySource, threadProvider, threadNamePrefix, nodeProvider ); return new ClientJdkElasticsearchClient( restClientHolder, timeoutExecutorService, requestTimeoutMs, @@ -149,6 +139,12 @@ private static List createRequestInterceptors(BeanResolv private BeanHolder createClient(BeanResolver beanResolver, ConfigurationPropertySource propertySource, ThreadProvider threadProvider, String threadNamePrefix, NodeProvider nodeProvider) { + Optional> providedHttpClientHolder = CLIENT_INSTANCE.getAndMap( + propertySource, beanResolver::resolve ); + if ( providedHttpClientHolder.isPresent() ) { + return BeanHolder.ofCloseable( new RestJdkClient( nodeProvider, providedHttpClientHolder.get().get() ) ); + } + HttpClient.Builder builder = HttpClient.newBuilder() // NOTE: ES does not work ok with HTTP 2 if we don't send the content length and that can happen so let's stick to 1.1 for now ? // (we end up with Caused by: java.io.IOException: Received RST_STREAM: Stream cancelled) diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/spi/NodeProvider.java b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/NodeProvider.java similarity index 99% rename from backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/spi/NodeProvider.java rename to backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/NodeProvider.java index e00996385e0..e9022af29c2 100644 --- a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/spi/NodeProvider.java +++ b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/NodeProvider.java @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.search.backend.elasticsearch.client.jdk.cfg.spi; +package org.hibernate.search.backend.elasticsearch.client.jdk.impl; import java.net.URI; import java.net.URISyntaxException; diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/spi/RestJdkClient.java b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/RestJdkClient.java similarity index 95% rename from backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/spi/RestJdkClient.java rename to backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/RestJdkClient.java index 229ad52edd3..6349ee54e94 100644 --- a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/spi/RestJdkClient.java +++ b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/RestJdkClient.java @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.search.backend.elasticsearch.client.jdk.cfg.spi; +package org.hibernate.search.backend.elasticsearch.client.jdk.impl; import java.net.http.HttpClient; import java.net.http.HttpRequest; From b9bee13ff8350b8052efbeaf3eb2f59dce1d9e66 Mon Sep 17 00:00:00 2001 From: marko-bekhta Date: Fri, 21 Nov 2025 16:18:13 +0100 Subject: [PATCH 4/4] HSEARCH-5482 Move JDK client into Elasticsearch backend --- .../jdk-rest-client/pom.xml | 64 ------------------- ...tJdkElasticsearchClientBeanConfigurer.java | 20 ------ .../logging/impl/ElasticsearchClientLog.java | 29 --------- .../client/jdk/package-info.java | 1 - ...engine.environment.bean.spi.BeanConfigurer | 1 - .../spi/ElasticsearchClientFactory.java | 3 + .../impl/ClientJdkElasticsearchClient.java | 2 +- .../ClientJdkElasticsearchClientFactory.java | 2 +- ...csearchHttpClientConfigurationContext.java | 2 +- .../client}/impl/ClientJdkGsonHttpEntity.java | 2 +- .../impl/ClientJdkHttpRequestInterceptor.java | 2 +- .../ElasticsearchClientBeanConfigurer.java | 4 ++ .../client}/impl/HttpRequestInterceptor.java | 2 +- .../impl/HttpRequestInterceptorContext.java | 2 +- .../client}/impl/NodeProvider.java | 2 +- .../client}/impl/RestJdkClient.java | 2 +- ...csearchHttpClientConfigurationContext.java | 0 .../ElasticsearchHttpClientConfigurer.java | 0 ...JdkElasticsearchBackendClientSettings.java | 0 ...ElasticsearchBackendClientSpiSettings.java | 0 .../impl/ElasticsearchBackendFactory.java | 45 +++++++++---- bom/platform-common/pom.xml | 5 -- bom/public/pom.xml | 5 -- build/jqassistant/rules/rules.xml | 1 - build/parents/build/pom.xml | 5 -- build/reports/pom.xml | 4 -- distribution/pom.xml | 5 -- documentation/pom.xml | 10 +-- .../src/main/asciidoc/migration/index.adoc | 2 +- integrationtest/backend/elasticsearch/pom.xml | 10 +-- .../bootstrap/ElasticsearchBootstrapIT.java | 14 ++-- .../ElasticsearchFieldAttributesIT.java | 2 +- .../mapping/ElasticsearchFieldTypesIT.java | 2 +- .../ElasticsearchTypeNameMappingSchemaIT.java | 2 +- .../query/ElasticsearchSearchQueryIT.java | 2 +- ...searchSearchQueryRequestTransformerIT.java | 2 +- .../ElasticsearchTckBackendSetupStrategy.java | 24 +++++++ .../work/ElasticsearchIndexingIT.java | 2 +- lucene-next/documentation/pom.xml | 6 -- pom.xml | 1 - .../extension/BackendConfiguration.java | 25 ++++++++ 41 files changed, 115 insertions(+), 199 deletions(-) delete mode 100644 backend/elasticsearch-client/jdk-rest-client/pom.xml delete mode 100644 backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchClientBeanConfigurer.java delete mode 100644 backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/logging/impl/ElasticsearchClientLog.java delete mode 100644 backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/package-info.java delete mode 100644 backend/elasticsearch-client/jdk-rest-client/src/main/resources/META-INF/services/org.hibernate.search.engine.environment.bean.spi.BeanConfigurer rename backend/{elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk => elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client}/impl/ClientJdkElasticsearchClient.java (99%) rename backend/{elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk => elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client}/impl/ClientJdkElasticsearchClientFactory.java (99%) rename backend/{elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk => elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client}/impl/ClientJdkElasticsearchHttpClientConfigurationContext.java (95%) rename backend/{elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk => elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client}/impl/ClientJdkGsonHttpEntity.java (96%) rename backend/{elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk => elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client}/impl/ClientJdkHttpRequestInterceptor.java (98%) rename backend/{elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk => elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client}/impl/HttpRequestInterceptor.java (83%) rename backend/{elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk => elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client}/impl/HttpRequestInterceptorContext.java (68%) rename backend/{elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk => elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client}/impl/NodeProvider.java (99%) rename backend/{elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk => elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client}/impl/RestJdkClient.java (95%) rename backend/{elasticsearch-client/jdk-rest-client => elasticsearch}/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/ElasticsearchHttpClientConfigurationContext.java (100%) rename backend/{elasticsearch-client/jdk-rest-client => elasticsearch}/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/ElasticsearchHttpClientConfigurer.java (100%) rename backend/{elasticsearch-client/jdk-rest-client => elasticsearch}/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/ClientJdkElasticsearchBackendClientSettings.java (100%) rename backend/{elasticsearch-client/jdk-rest-client => elasticsearch}/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/spi/ClientJdkElasticsearchBackendClientSpiSettings.java (100%) diff --git a/backend/elasticsearch-client/jdk-rest-client/pom.xml b/backend/elasticsearch-client/jdk-rest-client/pom.xml deleted file mode 100644 index 5649f48c430..00000000000 --- a/backend/elasticsearch-client/jdk-rest-client/pom.xml +++ /dev/null @@ -1,64 +0,0 @@ - - - - 4.0.0 - - org.hibernate.search - hibernate-search-parent-public - 8.2.0-SNAPSHOT - ../../../build/parents/public - - hibernate-search-backend-elasticsearch-client-jdk - - Hibernate Search Backend - Elasticsearch client based on the JDK HTTP client - Hibernate Search Elasticsearch client based on the JDK HTTP client - - - - false - org.hibernate.search.backend.elasticsearch.client.jdk - - - - - org.hibernate.search - hibernate-search-engine - - - org.hibernate.search - hibernate-search-backend-elasticsearch - - - org.jboss.logging - jboss-logging - - - org.jboss.logging - jboss-logging-annotations - - - com.google.code.gson - gson - - - - - org.hibernate.search - hibernate-search-util-internal-test-common - test - - - - - - - org.moditect - moditect-maven-plugin - - - - diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchClientBeanConfigurer.java b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchClientBeanConfigurer.java deleted file mode 100644 index d391f45138f..00000000000 --- a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchClientBeanConfigurer.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.search.backend.elasticsearch.client.jdk.impl; - -import org.hibernate.search.backend.elasticsearch.client.common.spi.ElasticsearchClientFactory; -import org.hibernate.search.engine.environment.bean.BeanHolder; -import org.hibernate.search.engine.environment.bean.spi.BeanConfigurationContext; -import org.hibernate.search.engine.environment.bean.spi.BeanConfigurer; - -public class ClientJdkElasticsearchClientBeanConfigurer implements BeanConfigurer { - @Override - public void configure(BeanConfigurationContext context) { - context.define( - ElasticsearchClientFactory.class, "jdk-rest-client", - beanResolver -> BeanHolder.of( new ClientJdkElasticsearchClientFactory() ) - ); - } -} diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/logging/impl/ElasticsearchClientLog.java b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/logging/impl/ElasticsearchClientLog.java deleted file mode 100644 index df6748e5294..00000000000 --- a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/logging/impl/ElasticsearchClientLog.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.search.backend.elasticsearch.client.jdk.logging.impl; - -import java.lang.invoke.MethodHandles; - -import org.hibernate.search.util.common.logging.CategorizedLogger; -import org.hibernate.search.util.common.logging.impl.LoggerFactory; -import org.hibernate.search.util.common.logging.impl.MessageConstants; - -import org.jboss.logging.annotations.MessageLogger; - -@CategorizedLogger( - category = ElasticsearchClientLog.CATEGORY_NAME, - description = """ - Logs information on low-level Elasticsearch backend operations. - + - This may include warnings about misconfigured Elasticsearch REST clients or index operations. - """ -) -@MessageLogger(projectCode = MessageConstants.PROJECT_CODE) -public interface ElasticsearchClientLog { - String CATEGORY_NAME = "org.hibernate.search.elasticsearch.client"; - - ElasticsearchClientLog INSTANCE = LoggerFactory.make( ElasticsearchClientLog.class, CATEGORY_NAME, MethodHandles.lookup() ); - -} diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/package-info.java b/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/package-info.java deleted file mode 100644 index 3bf2cce274e..00000000000 --- a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/package-info.java +++ /dev/null @@ -1 +0,0 @@ -package org.hibernate.search.backend.elasticsearch.client.jdk; diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/resources/META-INF/services/org.hibernate.search.engine.environment.bean.spi.BeanConfigurer b/backend/elasticsearch-client/jdk-rest-client/src/main/resources/META-INF/services/org.hibernate.search.engine.environment.bean.spi.BeanConfigurer deleted file mode 100644 index 9125dac4b1e..00000000000 --- a/backend/elasticsearch-client/jdk-rest-client/src/main/resources/META-INF/services/org.hibernate.search.engine.environment.bean.spi.BeanConfigurer +++ /dev/null @@ -1 +0,0 @@ -org.hibernate.search.backend.elasticsearch.client.jdk.impl.ClientJdkElasticsearchClientBeanConfigurer diff --git a/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/common/spi/ElasticsearchClientFactory.java b/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/common/spi/ElasticsearchClientFactory.java index f68d477b8a9..fa40ce27940 100644 --- a/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/common/spi/ElasticsearchClientFactory.java +++ b/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/common/spi/ElasticsearchClientFactory.java @@ -19,6 +19,9 @@ public interface ElasticsearchClientFactory { @Incubating String DEFAULT_BEAN_NAME = "default"; + @Incubating + String SIMPLE_JDK_CLIENT_BEAN_NAME = "jdk-rest-client"; + ElasticsearchClientImplementor create(BeanResolver beanResolver, ConfigurationPropertySource propertySource, ThreadProvider threadProvider, String threadNamePrefix, diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchClient.java b/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/impl/ClientJdkElasticsearchClient.java similarity index 99% rename from backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchClient.java rename to backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/impl/ClientJdkElasticsearchClient.java index 922c5df286d..fe76c888249 100644 --- a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchClient.java +++ b/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/impl/ClientJdkElasticsearchClient.java @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.search.backend.elasticsearch.client.jdk.impl; +package org.hibernate.search.backend.elasticsearch.client.impl; import java.io.IOException; import java.io.InputStream; diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchClientFactory.java b/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/impl/ClientJdkElasticsearchClientFactory.java similarity index 99% rename from backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchClientFactory.java rename to backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/impl/ClientJdkElasticsearchClientFactory.java index b381122c94a..16ad0901afc 100644 --- a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchClientFactory.java +++ b/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/impl/ClientJdkElasticsearchClientFactory.java @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.search.backend.elasticsearch.client.jdk.impl; +package org.hibernate.search.backend.elasticsearch.client.impl; import java.net.Authenticator; import java.net.PasswordAuthentication; diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchHttpClientConfigurationContext.java b/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/impl/ClientJdkElasticsearchHttpClientConfigurationContext.java similarity index 95% rename from backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchHttpClientConfigurationContext.java rename to backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/impl/ClientJdkElasticsearchHttpClientConfigurationContext.java index 52adeab9586..931441d0217 100644 --- a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkElasticsearchHttpClientConfigurationContext.java +++ b/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/impl/ClientJdkElasticsearchHttpClientConfigurationContext.java @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.search.backend.elasticsearch.client.jdk.impl; +package org.hibernate.search.backend.elasticsearch.client.impl; import java.net.http.HttpClient; diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkGsonHttpEntity.java b/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/impl/ClientJdkGsonHttpEntity.java similarity index 96% rename from backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkGsonHttpEntity.java rename to backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/impl/ClientJdkGsonHttpEntity.java index 7d0cdb3a648..b7b59be0fff 100644 --- a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkGsonHttpEntity.java +++ b/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/impl/ClientJdkGsonHttpEntity.java @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.search.backend.elasticsearch.client.jdk.impl; +package org.hibernate.search.backend.elasticsearch.client.impl; import java.io.IOException; import java.net.http.HttpRequest; diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkHttpRequestInterceptor.java b/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/impl/ClientJdkHttpRequestInterceptor.java similarity index 98% rename from backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkHttpRequestInterceptor.java rename to backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/impl/ClientJdkHttpRequestInterceptor.java index 05cced7dd16..e6bf3d47e81 100644 --- a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/ClientJdkHttpRequestInterceptor.java +++ b/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/impl/ClientJdkHttpRequestInterceptor.java @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.search.backend.elasticsearch.client.jdk.impl; +package org.hibernate.search.backend.elasticsearch.client.impl; import java.io.IOException; import java.io.InputStream; diff --git a/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/impl/ElasticsearchClientBeanConfigurer.java b/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/impl/ElasticsearchClientBeanConfigurer.java index 0b3fb7fba70..dee2b1c129e 100644 --- a/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/impl/ElasticsearchClientBeanConfigurer.java +++ b/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/impl/ElasticsearchClientBeanConfigurer.java @@ -16,5 +16,9 @@ public void configure(BeanConfigurationContext context) { ElasticsearchClientFactory.class, ElasticsearchClientFactory.DEFAULT_BEAN_NAME, beanResolver -> BeanHolder.of( new ClientRest4ElasticsearchClientFactory() ) ); + context.define( + ElasticsearchClientFactory.class, ElasticsearchClientFactory.SIMPLE_JDK_CLIENT_BEAN_NAME, + beanResolver -> BeanHolder.of( new ClientJdkElasticsearchClientFactory() ) + ); } } diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/HttpRequestInterceptor.java b/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/impl/HttpRequestInterceptor.java similarity index 83% rename from backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/HttpRequestInterceptor.java rename to backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/impl/HttpRequestInterceptor.java index 7573d1eb408..818b36ec30d 100644 --- a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/HttpRequestInterceptor.java +++ b/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/impl/HttpRequestInterceptor.java @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.search.backend.elasticsearch.client.jdk.impl; +package org.hibernate.search.backend.elasticsearch.client.impl; import java.io.IOException; import java.net.http.HttpRequest; diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/HttpRequestInterceptorContext.java b/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/impl/HttpRequestInterceptorContext.java similarity index 68% rename from backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/HttpRequestInterceptorContext.java rename to backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/impl/HttpRequestInterceptorContext.java index 29fba99ee16..64bd39bf768 100644 --- a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/HttpRequestInterceptorContext.java +++ b/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/impl/HttpRequestInterceptorContext.java @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.search.backend.elasticsearch.client.jdk.impl; +package org.hibernate.search.backend.elasticsearch.client.impl; record HttpRequestInterceptorContext(String method) { } diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/NodeProvider.java b/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/impl/NodeProvider.java similarity index 99% rename from backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/NodeProvider.java rename to backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/impl/NodeProvider.java index e9022af29c2..3354b9ad277 100644 --- a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/NodeProvider.java +++ b/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/impl/NodeProvider.java @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.search.backend.elasticsearch.client.jdk.impl; +package org.hibernate.search.backend.elasticsearch.client.impl; import java.net.URI; import java.net.URISyntaxException; diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/RestJdkClient.java b/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/impl/RestJdkClient.java similarity index 95% rename from backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/RestJdkClient.java rename to backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/impl/RestJdkClient.java index 6349ee54e94..917b48ba008 100644 --- a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/impl/RestJdkClient.java +++ b/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/impl/RestJdkClient.java @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.search.backend.elasticsearch.client.jdk.impl; +package org.hibernate.search.backend.elasticsearch.client.impl; import java.net.http.HttpClient; import java.net.http.HttpRequest; diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/ElasticsearchHttpClientConfigurationContext.java b/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/ElasticsearchHttpClientConfigurationContext.java similarity index 100% rename from backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/ElasticsearchHttpClientConfigurationContext.java rename to backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/ElasticsearchHttpClientConfigurationContext.java diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/ElasticsearchHttpClientConfigurer.java b/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/ElasticsearchHttpClientConfigurer.java similarity index 100% rename from backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/ElasticsearchHttpClientConfigurer.java rename to backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/ElasticsearchHttpClientConfigurer.java diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/ClientJdkElasticsearchBackendClientSettings.java b/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/ClientJdkElasticsearchBackendClientSettings.java similarity index 100% rename from backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/ClientJdkElasticsearchBackendClientSettings.java rename to backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/ClientJdkElasticsearchBackendClientSettings.java diff --git a/backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/spi/ClientJdkElasticsearchBackendClientSpiSettings.java b/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/spi/ClientJdkElasticsearchBackendClientSpiSettings.java similarity index 100% rename from backend/elasticsearch-client/jdk-rest-client/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/spi/ClientJdkElasticsearchBackendClientSpiSettings.java rename to backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/client/jdk/cfg/spi/ClientJdkElasticsearchBackendClientSpiSettings.java diff --git a/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/impl/ElasticsearchBackendFactory.java b/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/impl/ElasticsearchBackendFactory.java index f2891520c8a..abb58ace98e 100644 --- a/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/impl/ElasticsearchBackendFactory.java +++ b/backend/elasticsearch/src/main/java/org/hibernate/search/backend/elasticsearch/impl/ElasticsearchBackendFactory.java @@ -4,9 +4,12 @@ */ package org.hibernate.search.backend.elasticsearch.impl; +import java.util.HashSet; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Optional; +import java.util.Set; import org.hibernate.search.backend.elasticsearch.ElasticsearchVersion; import org.hibernate.search.backend.elasticsearch.cfg.ElasticsearchBackendSettings; @@ -58,7 +61,7 @@ public class ElasticsearchBackendFactory implements BackendFactory { .build(); private static final OptionalConfigurationProperty> CLIENT_FACTORY = - ConfigurationProperty.forKey( ElasticsearchBackendSpiSettings.CLIENT_FACTORY ) + ConfigurationProperty.forKey( ElasticsearchBackendSpiSettings.Radicals.CLIENT_FACTORY ) .asBeanReference( ElasticsearchClientFactory.class ) .build(); @@ -95,7 +98,7 @@ public BackendImplementor create(EventContext eventContext, BackendBuildContext clientFactoryHolder = customClientFactoryHolderOptional.get(); } else { - // otherwise let's find all client factories and pick + // otherwise let's find all client factories and pick one of them: List> clientFactoryReferences = beanResolver.allConfiguredForRole( ElasticsearchClientFactory.class ); if ( clientFactoryReferences.isEmpty() ) { @@ -105,18 +108,34 @@ public BackendImplementor create(EventContext eventContext, BackendBuildContext else if ( clientFactoryReferences.size() == 1 ) { clientFactoryHolder = clientFactoryReferences.get( 0 ).resolve( beanResolver ); } - // if there are 2 of them, maybe one is the "default" one, if so -- use the other one - else if ( clientFactoryReferences.size() == 2 ) { - var defaultFactoryReference = beanResolver.namedConfiguredForRole( ElasticsearchClientFactory.class ) - .get( ElasticsearchClientFactory.DEFAULT_BEAN_NAME ); - - var first = clientFactoryReferences.get( 0 ); - var second = clientFactoryReferences.get( 1 ); - if ( first == defaultFactoryReference ) { - clientFactoryHolder = second.resolve( beanResolver ); + // if there are more of them, maybe one is the "default" and the other one is JDK based, if so -- use the 3rd one + else { + Map> namedFactoryReferences = + beanResolver.namedConfiguredForRole( ElasticsearchClientFactory.class ); + if ( clientFactoryReferences.size() == 2 + && namedFactoryReferences.containsKey( ElasticsearchClientFactory.DEFAULT_BEAN_NAME ) + && namedFactoryReferences.containsKey( ElasticsearchClientFactory.SIMPLE_JDK_CLIENT_BEAN_NAME ) ) { + clientFactoryHolder = namedFactoryReferences.get( ElasticsearchClientFactory.DEFAULT_BEAN_NAME ) + .resolve( beanResolver ); } - else if ( second == defaultFactoryReference ) { - clientFactoryHolder = first.resolve( beanResolver ); + else { + Set> skippable = new HashSet<>( 2 ); + skippable.add( namedFactoryReferences.get( ElasticsearchClientFactory.DEFAULT_BEAN_NAME ) ); + skippable.add( namedFactoryReferences.get( ElasticsearchClientFactory.SIMPLE_JDK_CLIENT_BEAN_NAME ) ); + for ( BeanReference factoryReference : clientFactoryReferences ) { + if ( skippable.contains( factoryReference ) ) { + continue; + } + if ( clientFactoryHolder == null ) { + clientFactoryHolder = factoryReference.resolve( beanResolver ); + } + else { + throw ConfigurationLog.INSTANCE.backendClientFactoryMultipleConfigured( + clientFactoryReferences.stream().map( ref -> ref.resolve( beanResolver ) ).toList(), + eventContext + ); + } + } } } if ( clientFactoryHolder == null ) { diff --git a/bom/platform-common/pom.xml b/bom/platform-common/pom.xml index 45b1949f844..88d68d461b6 100644 --- a/bom/platform-common/pom.xml +++ b/bom/platform-common/pom.xml @@ -86,11 +86,6 @@ hibernate-search-backend-elasticsearch-client-opensearch-rest ${project.version} - - org.hibernate.search - hibernate-search-backend-elasticsearch-client-jdk - ${project.version} - org.hibernate.search hibernate-search-mapper-pojo-base diff --git a/bom/public/pom.xml b/bom/public/pom.xml index 4d811953184..f85cecd4650 100644 --- a/bom/public/pom.xml +++ b/bom/public/pom.xml @@ -52,11 +52,6 @@ hibernate-search-backend-elasticsearch-client-rest5 ${project.version} - - org.hibernate.search - hibernate-search-backend-elasticsearch-client-jdk - ${project.version} - org.hibernate.search hibernate-search-backend-elasticsearch-client-opensearch-rest diff --git a/build/jqassistant/rules/rules.xml b/build/jqassistant/rules/rules.xml index dbfe3d5113d..142463b94dd 100644 --- a/build/jqassistant/rules/rules.xml +++ b/build/jqassistant/rules/rules.xml @@ -286,7 +286,6 @@ WHEN 'hibernate-search-backend-elasticsearch-client-rest4' THEN 'ClientRest4' WHEN 'hibernate-search-backend-elasticsearch-client-rest5' THEN 'ClientRest5' WHEN 'hibernate-search-backend-elasticsearch-client-opensearch-rest' THEN 'ClientOpenSearch' - WHEN 'hibernate-search-backend-elasticsearch-client-jdk' THEN 'ClientJdk' ELSE 'UNKNOWN-MODULE-SPECIFIC-KEYWORD-PLEASE-UPDATE-JQASSISTANT-RULES' END RETURN diff --git a/build/parents/build/pom.xml b/build/parents/build/pom.xml index 171cb438cc1..045b56ab6da 100644 --- a/build/parents/build/pom.xml +++ b/build/parents/build/pom.xml @@ -317,11 +317,6 @@ hibernate-search-backend-elasticsearch-client-opensearch-rest ${project.version} - - org.hibernate.search - hibernate-search-backend-elasticsearch-client-jdk - ${project.version} - org.hibernate.search hibernate-search-backend-elasticsearch-aws diff --git a/build/reports/pom.xml b/build/reports/pom.xml index 66577663a25..fcbd3ac824a 100644 --- a/build/reports/pom.xml +++ b/build/reports/pom.xml @@ -62,10 +62,6 @@ org.hibernate.search hibernate-search-backend-elasticsearch-client-opensearch-rest - - org.hibernate.search - hibernate-search-backend-elasticsearch-client-jdk - org.hibernate.search hibernate-search-mapper-pojo-base diff --git a/distribution/pom.xml b/distribution/pom.xml index f27fb53d001..695c0383e4b 100644 --- a/distribution/pom.xml +++ b/distribution/pom.xml @@ -105,11 +105,6 @@ hibernate-search-backend-elasticsearch-client-opensearch-rest compile - - org.hibernate.search - hibernate-search-backend-elasticsearch-client-jdk - compile - org.hibernate.search hibernate-search-v5migrationhelper-engine diff --git a/documentation/pom.xml b/documentation/pom.xml index 2c285bfadd3..8b5676a8490 100644 --- a/documentation/pom.xml +++ b/documentation/pom.xml @@ -85,11 +85,6 @@ hibernate-search-backend-elasticsearch-client-rest5 test - - org.hibernate.search - hibernate-search-backend-elasticsearch-client-jdk - test - ${project.groupId} hibernate-search-processor @@ -205,7 +200,6 @@ org.hibernate.search:hibernate-search-backend-elasticsearch-client-rest4 org.hibernate.search:hibernate-search-backend-elasticsearch-client-rest5 org.hibernate.search:hibernate-search-backend-elasticsearch-client-opensearch-rest - org.hibernate.search:hibernate-search-backend-elasticsearch-client-jdk lucene @@ -230,7 +224,6 @@ org.hibernate.search:hibernate-search-backend-lucene org.hibernate.search:hibernate-search-backend-elasticsearch-client-rest5 org.hibernate.search:hibernate-search-backend-elasticsearch-client-opensearch-rest - org.hibernate.search:hibernate-search-backend-elasticsearch-client-jdk elasticsearch @@ -258,7 +251,6 @@ org.hibernate.search:hibernate-search-backend-lucene org.hibernate.search:hibernate-search-backend-elasticsearch-client-rest4 org.hibernate.search:hibernate-search-backend-elasticsearch-client-opensearch-rest - org.hibernate.search:hibernate-search-backend-elasticsearch-client-jdk elasticsearch @@ -283,7 +275,6 @@ org.hibernate.search:hibernate-search-backend-lucene org.hibernate.search:hibernate-search-backend-elasticsearch-client-rest4 org.hibernate.search:hibernate-search-backend-elasticsearch-client-rest5 - org.hibernate.search:hibernate-search-backend-elasticsearch-client-jdk elasticsearch @@ -312,6 +303,7 @@ elasticsearch + jdk-rest-client **/client/jdk/*IT diff --git a/documentation/src/main/asciidoc/migration/index.adoc b/documentation/src/main/asciidoc/migration/index.adoc index ad29bbaa9f4..1c8b9903198 100644 --- a/documentation/src/main/asciidoc/migration/index.adoc +++ b/documentation/src/main/asciidoc/migration/index.adoc @@ -61,7 +61,7 @@ Currently available options are: * `org.hibernate.search:hibernate-search-backend-elasticsearch-client-rest4` backed by `org.elasticsearch.client:elasticsearch-rest-client` * `org.hibernate.search:hibernate-search-backend-elasticsearch-client-rest5` backed by `co.elastic.clients:elasticsearch-rest5-client` * `org.hibernate.search:hibernate-search-backend-elasticsearch-client-opensearch-rest` backed by `org.opensearch.client:opensearch-rest-client` -* `org.hibernate.search:hibernate-search-backend-elasticsearch-client-jdk` backed by `java.net.http.HttpClient` +// * `org.hibernate.search:hibernate-search-backend-elasticsearch-client-jdk` backed by `java.net.http.HttpClient` [[data-format]] == Data format and schema diff --git a/integrationtest/backend/elasticsearch/pom.xml b/integrationtest/backend/elasticsearch/pom.xml index 6789c89bcea..fa79eaf12db 100644 --- a/integrationtest/backend/elasticsearch/pom.xml +++ b/integrationtest/backend/elasticsearch/pom.xml @@ -54,10 +54,6 @@ org.hibernate.search hibernate-search-backend-elasticsearch-client-rest4 - - org.hibernate.search - hibernate-search-backend-elasticsearch-client-jdk - org.hibernate.search @@ -113,7 +109,6 @@ org.hibernate.search:hibernate-search-backend-elasticsearch-client-opensearch-rest org.hibernate.search:hibernate-search-backend-elasticsearch-client-rest5 - org.hibernate.search:hibernate-search-backend-elasticsearch-client-jdk org.hibernate.search.integrationtest.backend.elasticsearch.client.ClientRest5ElasticsearchClientFactoryIT @@ -139,7 +134,6 @@ org.hibernate.search:hibernate-search-backend-elasticsearch-client-rest5 - org.hibernate.search:hibernate-search-backend-elasticsearch-client-jdk org.hibernate.search.integrationtest.backend.elasticsearch.client.ClientRest5ElasticsearchClientFactoryIT @@ -164,7 +158,6 @@ org.hibernate.search:hibernate-search-backend-elasticsearch-client-rest4 org.hibernate.search:hibernate-search-backend-elasticsearch-client-opensearch-rest - org.hibernate.search:hibernate-search-backend-elasticsearch-client-jdk org.hibernate.search.integrationtest.backend.elasticsearch.client.ClientRest4ElasticsearchClientFactoryIT @@ -187,6 +180,9 @@ ${failsafe.client.jdk.reportsDirectory} ${failsafe.client.jdk.summaryFile} ${failsafe.jvm.args.no-jacoco} @{failsafe.jvm.args.jacoco.client.jdk} + + jdk-rest-client + org.hibernate.search:hibernate-search-backend-elasticsearch-client-rest4 org.hibernate.search:hibernate-search-backend-elasticsearch-client-rest5 diff --git a/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/bootstrap/ElasticsearchBootstrapIT.java b/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/bootstrap/ElasticsearchBootstrapIT.java index f5c2d15233e..516054fa35d 100644 --- a/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/bootstrap/ElasticsearchBootstrapIT.java +++ b/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/bootstrap/ElasticsearchBootstrapIT.java @@ -62,7 +62,7 @@ void explicitModelDialect() { ElasticsearchBackendSettings.VERSION, ElasticsearchTestDialect.getActualVersion().toString() ) .withBackendProperty( - ElasticsearchBackendSpiSettings.CLIENT_FACTORY, + ElasticsearchBackendSpiSettings.Radicals.CLIENT_FACTORY, elasticsearchClientSpy.factoryReference() ) .withSchemaManagement( StubMappingSchemaManagementStrategy.DROP_ON_SHUTDOWN_ONLY ) @@ -104,7 +104,7 @@ void noVersionCheck_missingVersion() { ElasticsearchBackendSettings.VERSION_CHECK_ENABLED, false ) .withBackendProperty( - ElasticsearchBackendSpiSettings.CLIENT_FACTORY, + ElasticsearchBackendSpiSettings.Radicals.CLIENT_FACTORY, elasticsearchClientSpy.factoryReference() ) .withSchemaManagement( StubMappingSchemaManagementStrategy.DROP_ON_SHUTDOWN_ONLY ) @@ -146,7 +146,7 @@ void noVersionCheck_incompleteVersion() { ElasticsearchBackendSettings.VERSION, versionWithMajorOnly ) .withBackendProperty( - ElasticsearchBackendSpiSettings.CLIENT_FACTORY, + ElasticsearchBackendSpiSettings.Radicals.CLIENT_FACTORY, elasticsearchClientSpy.factoryReference() ) .withSchemaManagement( StubMappingSchemaManagementStrategy.DROP_ON_SHUTDOWN_ONLY ) @@ -192,7 +192,7 @@ void noVersionCheck_completeVersion() { ElasticsearchBackendSettings.VERSION, configuredVersion ) .withBackendProperty( - ElasticsearchBackendSpiSettings.CLIENT_FACTORY, + ElasticsearchBackendSpiSettings.Radicals.CLIENT_FACTORY, elasticsearchClientSpy.factoryReference() ) .withSchemaManagement( StubMappingSchemaManagementStrategy.DROP_ON_SHUTDOWN_ONLY ) @@ -243,7 +243,7 @@ void noVersionCheck_versionOverrideOnStart_incompatibleVersion() { ElasticsearchBackendSettings.VERSION, configuredVersionOnBackendCreation ) .withBackendProperty( - ElasticsearchBackendSpiSettings.CLIENT_FACTORY, + ElasticsearchBackendSpiSettings.Radicals.CLIENT_FACTORY, elasticsearchClientSpy.factoryReference() ) .withSchemaManagement( StubMappingSchemaManagementStrategy.DROP_ON_SHUTDOWN_ONLY ) @@ -296,7 +296,7 @@ void noVersionCheck_versionOverrideOnStart_compatibleVersion() { ElasticsearchBackendSettings.VERSION, versionWithMajorOnly ) .withBackendProperty( - ElasticsearchBackendSpiSettings.CLIENT_FACTORY, + ElasticsearchBackendSpiSettings.Radicals.CLIENT_FACTORY, elasticsearchClientSpy.factoryReference() ) .withSchemaManagement( StubMappingSchemaManagementStrategy.DROP_ON_SHUTDOWN_ONLY ) @@ -341,7 +341,7 @@ void noVersionCheck_customSettingsAndMapping() { SearchSetupHelper.PartialSetup partialSetup = setupHelper.start() .withBackendProperty( ElasticsearchBackendSettings.VERSION, configuredVersion ) - .withBackendProperty( ElasticsearchBackendSpiSettings.CLIENT_FACTORY, + .withBackendProperty( ElasticsearchBackendSpiSettings.Radicals.CLIENT_FACTORY, elasticsearchClientSpy.factoryReference() ) .withBackendProperty( ElasticsearchIndexSettings.SCHEMA_MANAGEMENT_SETTINGS_FILE, "bootstrap-it/custom-settings.json" ) diff --git a/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/mapping/ElasticsearchFieldAttributesIT.java b/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/mapping/ElasticsearchFieldAttributesIT.java index 8f7f9bc94e1..ebee12353da 100644 --- a/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/mapping/ElasticsearchFieldAttributesIT.java +++ b/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/mapping/ElasticsearchFieldAttributesIT.java @@ -110,7 +110,7 @@ private void matchMapping(Consumer mapping, JsonObject prope ); setupHelper.start() - .withBackendProperty( ElasticsearchBackendSpiSettings.CLIENT_FACTORY, clientSpy.factoryReference() ) + .withBackendProperty( ElasticsearchBackendSpiSettings.Radicals.CLIENT_FACTORY, clientSpy.factoryReference() ) .withIndex( index ) .setup(); diff --git a/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/mapping/ElasticsearchFieldTypesIT.java b/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/mapping/ElasticsearchFieldTypesIT.java index 76f759b78f7..d96ec260678 100644 --- a/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/mapping/ElasticsearchFieldTypesIT.java +++ b/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/mapping/ElasticsearchFieldTypesIT.java @@ -62,7 +62,7 @@ void test() { setupHelper.start() .withBackendProperty( - ElasticsearchBackendSpiSettings.CLIENT_FACTORY, clientSpy.factoryReference() + ElasticsearchBackendSpiSettings.Radicals.CLIENT_FACTORY, clientSpy.factoryReference() ) .withIndex( index ) .setup(); diff --git a/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/mapping/ElasticsearchTypeNameMappingSchemaIT.java b/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/mapping/ElasticsearchTypeNameMappingSchemaIT.java index 6691dc84bfa..3251e68da1c 100644 --- a/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/mapping/ElasticsearchTypeNameMappingSchemaIT.java +++ b/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/mapping/ElasticsearchTypeNameMappingSchemaIT.java @@ -75,7 +75,7 @@ void schema(String strategyName, JsonObject expectedMappingContent) { setupHelper.start() .withBackendProperty( - ElasticsearchBackendSpiSettings.CLIENT_FACTORY, clientSpy.factoryReference() + ElasticsearchBackendSpiSettings.Radicals.CLIENT_FACTORY, clientSpy.factoryReference() ) .withBackendProperty( // Don't contribute any analysis definitions, it messes with our assertions diff --git a/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/search/query/ElasticsearchSearchQueryIT.java b/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/search/query/ElasticsearchSearchQueryIT.java index df03220623f..b125162e139 100644 --- a/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/search/query/ElasticsearchSearchQueryIT.java +++ b/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/search/query/ElasticsearchSearchQueryIT.java @@ -58,7 +58,7 @@ public static List params() { public void init(Object layoutStrategy, URLEncodedString readName) { setupHelper.start() .withBackendProperty( - ElasticsearchBackendSpiSettings.CLIENT_FACTORY, clientSpy.factoryReference() + ElasticsearchBackendSpiSettings.Radicals.CLIENT_FACTORY, clientSpy.factoryReference() ) .withBackendProperty( ElasticsearchBackendSettings.LAYOUT_STRATEGY, layoutStrategy diff --git a/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/search/query/ElasticsearchSearchQueryRequestTransformerIT.java b/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/search/query/ElasticsearchSearchQueryRequestTransformerIT.java index 33d435fad6c..68087a46842 100644 --- a/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/search/query/ElasticsearchSearchQueryRequestTransformerIT.java +++ b/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/search/query/ElasticsearchSearchQueryRequestTransformerIT.java @@ -53,7 +53,7 @@ class ElasticsearchSearchQueryRequestTransformerIT { void setup() { setupHelper.start() .withBackendProperty( - ElasticsearchBackendSpiSettings.CLIENT_FACTORY, clientSpy.factoryReference() + ElasticsearchBackendSpiSettings.Radicals.CLIENT_FACTORY, clientSpy.factoryReference() ) .withIndexes( mainIndex, otherIndex ) .setup(); diff --git a/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/testsupport/util/ElasticsearchTckBackendSetupStrategy.java b/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/testsupport/util/ElasticsearchTckBackendSetupStrategy.java index ab5f613f89c..a84333b0317 100644 --- a/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/testsupport/util/ElasticsearchTckBackendSetupStrategy.java +++ b/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/testsupport/util/ElasticsearchTckBackendSetupStrategy.java @@ -4,6 +4,7 @@ */ package org.hibernate.search.integrationtest.backend.elasticsearch.testsupport.util; +import org.hibernate.search.backend.elasticsearch.cfg.spi.ElasticsearchBackendSpiSettings; import org.hibernate.search.engine.environment.bean.BeanReference; import org.hibernate.search.integrationtest.backend.elasticsearch.testsupport.configuration.DefaultITAnalysisConfigurer; import org.hibernate.search.integrationtest.backend.tck.testsupport.util.TckBackendAccessor; @@ -13,10 +14,33 @@ import org.hibernate.search.util.impl.integrationtest.common.TestConfigurationProvider; class ElasticsearchTckBackendSetupStrategy extends TckBackendSetupStrategy { + private static final String ELASTICSEARCH_BACKEND_CLIENT_TYPE_PROPERTY_KEY = + "org.hibernate.search.integrationtest.backend.elasticsearch.client.type"; + private static final String ELASTICSEARCH_BACKEND_CLIENT_TYPE; + + // Uncomment one of the following lines to set the backend type when running tests from the IDE + public static final String IDE_ELASTICSEARCH_BACKEND_CLIENT_TYPE = null; + // public static final String IDE_ELASTICSEARCH_BACKEND_CLIENT_TYPE = "default"; + // public static final String IDE_ELASTICSEARCH_BACKEND_CLIENT_TYPE = "jdk-rest-client"; + // public static final String IDE_ELASTICSEARCH_BACKEND_CLIENT_TYPE = "opensearch-rest-client"; + // public static final String IDE_ELASTICSEARCH_BACKEND_CLIENT_TYPE = "elasticsearch-rest5"; + + static { + String property = System.getProperty( ELASTICSEARCH_BACKEND_CLIENT_TYPE_PROPERTY_KEY ); + if ( property == null ) { + ELASTICSEARCH_BACKEND_CLIENT_TYPE = IDE_ELASTICSEARCH_BACKEND_CLIENT_TYPE; + } + else { + ELASTICSEARCH_BACKEND_CLIENT_TYPE = property; + } + } ElasticsearchTckBackendSetupStrategy() { super( new ElasticsearchBackendConfiguration() ); setProperty( "analysis.configurer", BeanReference.ofInstance( new DefaultITAnalysisConfigurer() ) ); + if ( ELASTICSEARCH_BACKEND_CLIENT_TYPE != null ) { + setProperty( ElasticsearchBackendSpiSettings.Radicals.CLIENT_FACTORY, ELASTICSEARCH_BACKEND_CLIENT_TYPE ); + } } @Override diff --git a/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/work/ElasticsearchIndexingIT.java b/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/work/ElasticsearchIndexingIT.java index d45cc714ad3..cd7b40df0cc 100644 --- a/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/work/ElasticsearchIndexingIT.java +++ b/integrationtest/backend/elasticsearch/src/test/java/org/hibernate/search/integrationtest/backend/elasticsearch/work/ElasticsearchIndexingIT.java @@ -61,7 +61,7 @@ public static List params() { public void init(Object layoutStrategy, URLEncodedString writeName) { setupHelper.start() .withBackendProperty( - ElasticsearchBackendSpiSettings.CLIENT_FACTORY, clientSpy.factoryReference() + ElasticsearchBackendSpiSettings.Radicals.CLIENT_FACTORY, clientSpy.factoryReference() ) .withBackendProperty( ElasticsearchBackendSettings.LAYOUT_STRATEGY, layoutStrategy diff --git a/lucene-next/documentation/pom.xml b/lucene-next/documentation/pom.xml index b88e0954b20..dcd1c7a004b 100644 --- a/lucene-next/documentation/pom.xml +++ b/lucene-next/documentation/pom.xml @@ -66,11 +66,6 @@ hibernate-search-backend-elasticsearch-client-rest4 test - - org.hibernate.search - hibernate-search-backend-elasticsearch-client-jdk - test - ${project.groupId} hibernate-search-util-internal-integrationtest-mapper-orm @@ -185,7 +180,6 @@ org.hibernate.search:hibernate-search-backend-elasticsearch-client-rest4 org.hibernate.search:hibernate-search-backend-elasticsearch-client-rest5 org.hibernate.search:hibernate-search-backend-elasticsearch-client-opensearch-rest - org.hibernate.search:hibernate-search-backend-elasticsearch-client-jdk lucene diff --git a/pom.xml b/pom.xml index 40acba5bc27..f913a9ed25c 100644 --- a/pom.xml +++ b/pom.xml @@ -177,7 +177,6 @@ backend/elasticsearch-client/elasticsearch-rest4-client backend/elasticsearch-client/elasticsearch-rest5-client backend/elasticsearch-client/opensearch-rest-client - backend/elasticsearch-client/jdk-rest-client mapper/pojo-base mapper/pojo-standalone mapper/orm diff --git a/util/internal/integrationtest/common/src/main/java/org/hibernate/search/util/impl/integrationtest/common/extension/BackendConfiguration.java b/util/internal/integrationtest/common/src/main/java/org/hibernate/search/util/impl/integrationtest/common/extension/BackendConfiguration.java index 8b0d043c802..97b4321c9e6 100644 --- a/util/internal/integrationtest/common/src/main/java/org/hibernate/search/util/impl/integrationtest/common/extension/BackendConfiguration.java +++ b/util/internal/integrationtest/common/src/main/java/org/hibernate/search/util/impl/integrationtest/common/extension/BackendConfiguration.java @@ -15,12 +15,22 @@ public abstract class BackendConfiguration { private static final String BACKEND_TYPE_PROPERTY_KEY = "org.hibernate.search.integrationtest.backend.type"; + private static final String ELASTICSEARCH_BACKEND_CLIENT_TYPE_PROPERTY_KEY = + "org.hibernate.search.integrationtest.backend.elasticsearch.client.type"; // Uncomment one of the following lines to set the backend type when running tests from the IDE public static final String IDE_BACKEND_TYPE = "lucene"; // public static final String IDE_BACKEND_TYPE = "elasticsearch"; + // Uncomment one of the following lines to set the backend type when running tests from the IDE + public static final String IDE_ELASTICSEARCH_BACKEND_CLIENT_TYPE = null; + // public static final String IDE_ELASTICSEARCH_BACKEND_CLIENT_TYPE = "default"; + // public static final String IDE_ELASTICSEARCH_BACKEND_CLIENT_TYPE = "jdk-rest-client"; + // public static final String IDE_ELASTICSEARCH_BACKEND_CLIENT_TYPE = "opensearch-rest-client"; + // public static final String IDE_ELASTICSEARCH_BACKEND_CLIENT_TYPE = "elasticsearch-rest5"; + public static final String BACKEND_TYPE; + public static final String ELASTICSEARCH_BACKEND_CLIENT_TYPE; public static final boolean IS_IDE; static { String property = System.getProperty( BACKEND_TYPE_PROPERTY_KEY ); @@ -38,6 +48,18 @@ public abstract class BackendConfiguration { BACKEND_TYPE = property; IS_IDE = false; } + if ( isElasticsearch() ) { + property = System.getProperty( ELASTICSEARCH_BACKEND_CLIENT_TYPE_PROPERTY_KEY ); + if ( property == null ) { + ELASTICSEARCH_BACKEND_CLIENT_TYPE = IDE_ELASTICSEARCH_BACKEND_CLIENT_TYPE; + } + else { + ELASTICSEARCH_BACKEND_CLIENT_TYPE = property; + } + } + else { + ELASTICSEARCH_BACKEND_CLIENT_TYPE = null; + } } public static boolean isElasticsearch() { @@ -62,6 +84,9 @@ public final Map backendProperties(TestConfigurationProvider con // More than one backend type in the classpath, we have to set it explicitly. rawBackendProperties.put( BackendSettings.TYPE, BACKEND_TYPE ); } + if ( ELASTICSEARCH_BACKEND_CLIENT_TYPE != null ) { + rawBackendProperties.put( "client_factory", ELASTICSEARCH_BACKEND_CLIENT_TYPE ); + } return configurationProvider.interpolateProperties( rawBackendProperties ); }