diff --git a/java-client/src/main/java/co/elastic/clients/transport/rest5_client/low_level/Rest5Client.java b/java-client/src/main/java/co/elastic/clients/transport/rest5_client/low_level/Rest5Client.java index 790004e87..6823b7c00 100644 --- a/java-client/src/main/java/co/elastic/clients/transport/rest5_client/low_level/Rest5Client.java +++ b/java-client/src/main/java/co/elastic/clients/transport/rest5_client/low_level/Rest5Client.java @@ -155,11 +155,7 @@ public class Rest5Client implements Closeable { * Creates a new builder instance and sets the hosts that the client will send requests to. */ public static Rest5ClientBuilder builder(URI... uris) { - if (uris == null || uris.length == 0) { - throw new IllegalArgumentException("uris must not be null nor empty"); - } - List nodes = Arrays.stream(uris).map(u -> new Node(HttpHost.create(u))).toList(); - return new Rest5ClientBuilder(nodes); + return builder(Arrays.asList(uris)); } /** @@ -170,13 +166,27 @@ public static Rest5ClientBuilder builder(List uris) { if (uris == null || uris.isEmpty()) { throw new IllegalArgumentException("uris must not be null nor empty"); } + String prefix = uris.get(0).getPath(); + List nodes = uris.stream().map(u -> { if (!u.isAbsolute()) { throw new IllegalArgumentException("Expecting an absolute url: [" + u + "]"); } + if (!Objects.equals(u.getPath(), prefix)) { + throw new IllegalArgumentException( + "All hosts must have the same URL path (" + + uris.get(0) + " and " + u + ")" + ); + } return new Node(HttpHost.create(u)); }).toList(); - return new Rest5ClientBuilder(nodes); + + Rest5ClientBuilder result = new Rest5ClientBuilder(nodes); + + if (prefix != null && !prefix.isEmpty()) { + result.setPathPrefix(prefix); + } + return result; } /** diff --git a/java-client/src/main/java/co/elastic/clients/transport/rest_client/RestClientTransport.java b/java-client/src/main/java/co/elastic/clients/transport/rest_client/RestClientTransport.java index 4ace1d0ed..0bf6178e5 100644 --- a/java-client/src/main/java/co/elastic/clients/transport/rest_client/RestClientTransport.java +++ b/java-client/src/main/java/co/elastic/clients/transport/rest_client/RestClientTransport.java @@ -31,6 +31,7 @@ import javax.annotation.Nullable; import java.util.Base64; +import java.util.Objects; public class RestClientTransport extends ElasticsearchTransportBase { @@ -61,9 +62,25 @@ public RestClientTransport(RestClient restClient, JsonpMapper jsonpMapper, RestC private static RestClient buildRestClient(ElasticsearchTransportConfig config) { RestClientBuilder restClientBuilder = RestClient.builder(config.hosts().stream() - .map(h -> HttpHost.create(h.toString())).toArray(HttpHost[]::new) + .map(h -> new HttpHost(h.getHost(), h.getPort(), h.getScheme())).toArray(HttpHost[]::new) ); + String prefix = config.hosts().get(0).getPath(); + if (config.hosts().size() > 1) { + for (var host : config.hosts()) { + if (!Objects.equals(host.getPath(), prefix)) { + throw new IllegalArgumentException( + "All hosts must have the same URL path (" + + config.hosts().get(0) + " and " + host + ")" + ); + } + } + } + + if (prefix != null && !prefix.isEmpty()) { + restClientBuilder.setPathPrefix(prefix); + } + if (config.username() != null && config.password() != null) { var cred = Base64.getEncoder().encodeToString((config.username() + ":" + config.password()).getBytes()); restClientBuilder.setDefaultHeaders(new org.apache.http.Header[]{ diff --git a/java-client/src/test/java/co/elastic/clients/elasticsearch/ElasticsearchTestClient.java b/java-client/src/test/java/co/elastic/clients/elasticsearch/ElasticsearchTestClient.java index 87461bc93..4fdee676c 100644 --- a/java-client/src/test/java/co/elastic/clients/elasticsearch/ElasticsearchTestClient.java +++ b/java-client/src/test/java/co/elastic/clients/elasticsearch/ElasticsearchTestClient.java @@ -73,4 +73,9 @@ public static ElasticsearchClient createClient(HttpServer server, @Nullable Json var address = server.getAddress(); return createClient("http://" + address.getHostString() + ":" + address.getPort(), mapper, null); } + + public static Function transportFactory() { + System.out.println("Using a " + flavor + " client"); + return flavor.transportFactory(); + } } diff --git a/java-client/src/test/java/co/elastic/clients/transport/ElasticsearchTransportConfigTest.java b/java-client/src/test/java/co/elastic/clients/transport/ElasticsearchTransportConfigTest.java index 18e1b7852..d4a3f48e0 100644 --- a/java-client/src/test/java/co/elastic/clients/transport/ElasticsearchTransportConfigTest.java +++ b/java-client/src/test/java/co/elastic/clients/transport/ElasticsearchTransportConfigTest.java @@ -20,14 +20,22 @@ package co.elastic.clients.transport; import co.elastic.clients.elasticsearch.ElasticsearchClient; +import co.elastic.clients.elasticsearch.ElasticsearchTestClient; +import co.elastic.clients.elasticsearch.indices.GetAliasResponse; import co.elastic.clients.transport.rest5_client.Rest5ClientOptions; import co.elastic.clients.transport.rest5_client.Rest5ClientTransport; import co.elastic.clients.transport.rest_client.RestClientOptions; import co.elastic.clients.transport.rest_client.RestClientTransport; +import com.sun.net.httpserver.HttpServer; import org.elasticsearch.client.RequestOptions; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.nio.charset.StandardCharsets; + public class ElasticsearchTransportConfigTest extends Assertions { @Test @@ -132,4 +140,45 @@ public void checkDefaultConfig() throws Exception { assertInstanceOf(Rest5ClientTransport.class, transport); } } + + @Test + public void testPathPrefix() throws IOException { + HttpServer server = com.sun.net.httpserver.HttpServer.create(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), 0); + + server.createContext("/path-prefix/_alias", exchange -> { + exchange.getResponseHeaders().set("X-Elastic-Product", "Elasticsearch"); + exchange.getResponseHeaders().set("Content-Type", "application/json"); + exchange.sendResponseHeaders(200, 0); + + exchange.getResponseBody().write("{\"foo\":{\"aliases\":{}}}".getBytes(StandardCharsets.UTF_8)); + exchange.close(); + }); + + server.start(); + + var address = server.getAddress(); + var url = "http://" + address.getHostName() + ":" + address.getPort() + "/path-prefix"; + + // No trailing slash + try(var esClient = ElasticsearchClient.of(b -> b + .host(url) + .transportFactory(ElasticsearchTestClient.transportFactory()) + )) { + GetAliasResponse alias = esClient.indices().getAlias(); + assertEquals(1, alias.aliases().size()); + assertNotNull(alias.aliases().get("foo")); + } + + // Trailing slash + try(var esClient = ElasticsearchClient.of(b -> b + .host(url + "/") + .transportFactory(ElasticsearchTestClient.transportFactory()) + )) { + GetAliasResponse alias = esClient.indices().getAlias(); + assertEquals(1, alias.aliases().size()); + assertNotNull(alias.aliases().get("foo")); + } + + server.stop(0); + } }