diff --git a/docs/reference/transport/rest5-client/config/basic_authentication.md b/docs/reference/transport/rest5-client/config/basic_authentication.md index 077fbee17..2e8f99756 100644 --- a/docs/reference/transport/rest5-client/config/basic_authentication.md +++ b/docs/reference/transport/rest5-client/config/basic_authentication.md @@ -16,7 +16,7 @@ Rest5ClientBuilder restClient = Rest5Client ``` -Preemptive Authentication can be disabled, which means that every request will be sent without authorization headers to see if it is accepted and, upon receiving an HTTP 401 response, it will resend the exact same request with the basic authentication header. If you wish to do this, then you can do so by disabling it via the `HttpAsyncClientBuilder`: +Preemptive Authentication can be disabled, which means that every request will be sent without authorization headers to see if it is accepted and, upon receiving an HTTP 401 response, it will resend the exact same request with the basic authentication header. If you wish to do this, then you can do so by disabling it via the `HttpClientConfigCallback`: % :::{include-code} src={{doc-tests-src}}/rest5_client/RestClientDocumentation.java tag=rest-client-config-disable-preemptive-auth ```java @@ -24,13 +24,9 @@ HttpHost host = new HttpHost("http", "localhost", 9200); var creds = Base64.getEncoder().encodeToString("user:test-user-password".getBytes()); -CloseableHttpAsyncClient httpclient = HttpAsyncClients.custom() - .disableAuthCaching() // <1> - .build(); - Rest5ClientBuilder restClient = Rest5Client .builder(new HttpHost("https", "localhost", 9200)) - .setHttpClient(httpclient) + .setHttpClientConfigCallback(HttpAsyncClientBuilder::disableAuthCaching) .setDefaultHeaders(new Header[]{ new BasicHeader("Authorization", "Basic " + creds) }); diff --git a/docs/reference/transport/rest5-client/config/number_of_threads.md b/docs/reference/transport/rest5-client/config/number_of_threads.md index a5be90de1..8825e6448 100644 --- a/docs/reference/transport/rest5-client/config/number_of_threads.md +++ b/docs/reference/transport/rest5-client/config/number_of_threads.md @@ -5,13 +5,11 @@ The Apache Http Async Client starts by default one dispatcher thread, and a numb % :::{include-code} src={{doc-tests-src}}/rest5_client/RestClientDocumentation.java tag=rest-client-config-threads ```java -CloseableHttpAsyncClient httpclient = HttpAsyncClients.custom() - .setIOReactorConfig( - IOReactorConfig.custom().setIoThreadCount(1).build() - ) - .build(); - Rest5ClientBuilder builder = Rest5Client .builder(new HttpHost("localhost", 9200)) - .setHttpClient(httpclient); + .setHttpClientConfigCallback(c -> c + .setIOReactorConfig(IOReactorConfig.custom() + .setIoThreadCount(1).build() + ) + ); ``` diff --git a/docs/reference/transport/rest5-client/config/timeouts.md b/docs/reference/transport/rest5-client/config/timeouts.md index 5b43b9b19..4151dfcee 100644 --- a/docs/reference/transport/rest5-client/config/timeouts.md +++ b/docs/reference/transport/rest5-client/config/timeouts.md @@ -1,23 +1,20 @@ # Timeouts -Configuring requests timeouts can be done by providing an instance of `RequestConfigCallback` while building the `RestClient` through its builder. The interface has one method that receives an instance of [`org.apache.http.client.config.RequestConfig.Builder`](https://hc.apache.org/httpcomponents-client-4.5.x/current/httpclient/apidocs/org/apache/http/client/config/RequestConfig.Builder.html) as an argument and has the same return type. The request config builder can be modified and then returned. In the following example we increase the connect timeout (defaults to 1 second) and the socket timeout (defaults to 30 seconds). +Configuring requests timeouts can be done by using the `setRequestConfigCallback` method while building the `RestClient`. In the following example we increase the connect timeout (defaults to 30 second) and the response timeout (defaults to 0, which is infinite). % :::{include-code} src={{doc-tests-src}}/rest5_client/RestClientDocumentation.java tag=rest-client-config-timeouts ```java -RequestConfig.Builder requestConfigBuilder = RequestConfig.custom() - .setConnectTimeout(Timeout.of(5000, TimeUnit.MILLISECONDS)); - -CloseableHttpAsyncClient httpclient = HttpAsyncClients.custom() - .setDefaultRequestConfig(requestConfigBuilder.build()) - .build(); - Rest5ClientBuilder builder = Rest5Client .builder(new HttpHost("localhost", 9200)) - .setHttpClient(httpclient); + .setRequestConfigCallback(r -> r + .setConnectTimeout(Timeout.of(5000, TimeUnit.MILLISECONDS)) + .setResponseTimeout(Timeout.of(30000, TimeUnit.MILLISECONDS)) + .build() + ); ``` -Timeouts also can be set per request with RequestOptions, which overrides RestClient customizeRequestConfig. +Timeouts also can be set per request with RequestOptions, which overrides RestClient's builder. The RequestOptions can then be set in the Rest5ClientTransport constructor. % :::{include-code} src={{doc-tests-src}}/rest5_client/RestClientDocumentation.java tag=rest-client-config-request-options-timeouts ```java @@ -29,5 +26,8 @@ RequestConfig requestConfig = RequestConfig.custom() RequestOptions options = RequestOptions.DEFAULT.toBuilder() .setRequestConfig(requestConfig) .build(); + +ElasticsearchTransport transport = new Rest5ClientTransport( + restClient, new JacksonJsonpMapper(), options); ``` diff --git a/java-client/src/main/java/co/elastic/clients/transport/rest5_client/low_level/Rest5ClientBuilder.java b/java-client/src/main/java/co/elastic/clients/transport/rest5_client/low_level/Rest5ClientBuilder.java index b4d5f573e..e093efe78 100644 --- a/java-client/src/main/java/co/elastic/clients/transport/rest5_client/low_level/Rest5ClientBuilder.java +++ b/java-client/src/main/java/co/elastic/clients/transport/rest5_client/low_level/Rest5ClientBuilder.java @@ -46,6 +46,7 @@ import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Consumer; import static co.elastic.clients.transport.rest5_client.low_level.LanguageRuntimeVersions.getRuntimeMetadata; @@ -75,6 +76,10 @@ public final class Rest5ClientBuilder { private final List nodes; private CloseableHttpAsyncClient httpClient; + private Consumer httpClientConfigCallback; + private Consumer requestConfigCallback; + private Consumer connectionConfigCallback; + private Consumer connectionManagerCallback; private Header[] defaultHeaders = EMPTY_HEADERS; private Rest5Client.FailureListener failureListener; private SSLContext sslContext; @@ -320,6 +325,58 @@ public Rest5ClientBuilder setMetaHeaderEnabled(boolean metadataEnabled) { return this; } + /** + * Allows to customize the {@link CloseableHttpAsyncClient} being created and used by the + * {@link Rest5Client}. + * Commonly used to customize {@link HttpAsyncClientBuilder} without losing any other useful default + * value that the {@link Rest5ClientBuilder} internally sets. + * @throws NullPointerException if {@code httpClientConfigCallback} is {@code null}. + */ + public Rest5ClientBuilder setHttpClientConfigCallback(Consumer httpClientConfigCallback) { + Objects.requireNonNull(httpClientConfigCallback, "httpClientConfigCallback must not be null"); + this.httpClientConfigCallback = httpClientConfigCallback; + return this; + } + + /** + * Allows to customize the {@link RequestConfig} created by the {@link Rest5Client} + * and used by the {@link CloseableHttpAsyncClient}. + * Commonly used to customize {@link RequestConfig} without losing any other useful default + * value that the {@link Rest5ClientBuilder} internally sets. + * @throws NullPointerException if {@code requestConfigCallback} is {@code null}. + */ + public Rest5ClientBuilder setRequestConfigCallback(Consumer requestConfigCallback) { + Objects.requireNonNull(requestConfigCallback, "requestConfigCallback must not be null"); + this.requestConfigCallback = requestConfigCallback; + return this; + } + + /** + * Allows to customize the {@link ConnectionConfig} created by the {@link Rest5Client} + * and used by the {@link CloseableHttpAsyncClient}. + * Commonly used to customize {@link ConnectionConfig} without losing any other useful default + * value that the {@link Rest5ClientBuilder} internally sets. + * @throws NullPointerException if {@code connectionConfigCallback} is {@code null}. + */ + public Rest5ClientBuilder setConnectionConfigCallback(Consumer connectionConfigCallback) { + Objects.requireNonNull(connectionConfigCallback, "connectionConfigCallback must not be null"); + this.connectionConfigCallback = connectionConfigCallback; + return this; + } + + /** + * Allows to customize the {@link PoolingAsyncClientConnectionManager} created by the {@link Rest5Client} + * and used by the {@link CloseableHttpAsyncClient}. + * Commonly used to customize {@link PoolingAsyncClientConnectionManager} without losing any other useful default + * value that the {@link Rest5ClientBuilder} internally sets. + * @throws NullPointerException if {@code connectionManagerCallback} is {@code null}. + */ + public Rest5ClientBuilder setConnectionManagerCallback(Consumer connectionManagerCallback) { + Objects.requireNonNull(connectionManagerCallback, "connectionManagerCallback must not be null"); + this.connectionManagerCallback = connectionManagerCallback; + return this; + } + /** * Creates a new {@link Rest5Client} based on the provided configuration. */ @@ -369,31 +426,40 @@ private CloseableHttpAsyncClient createHttpClient() { return this.httpClient; } // otherwise, creating a default instance of CloseableHttpAsyncClient - // default timeouts are all 3 mins - RequestConfig requestConfigBuilder = RequestConfig.custom() + + // default timeouts are all 3 mins, replacing those + RequestConfig.Builder requestConfigBuilder = RequestConfig.custom() .setConnectionRequestTimeout(Timeout.of(DEFAULT_SOCKET_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) - .setResponseTimeout(Timeout.of(DEFAULT_RESPONSE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) - .build(); + .setResponseTimeout(Timeout.of(DEFAULT_RESPONSE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)); + + if (requestConfigCallback != null) { + requestConfigCallback.accept(requestConfigBuilder); + } try { SSLContext sslContext = this.sslContext != null ? this.sslContext : SSLContext.getDefault(); - ConnectionConfig connectionConfig = ConnectionConfig.custom() - .setConnectTimeout(Timeout.of(DEFAULT_CONNECT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) - .build(); + ConnectionConfig.Builder connectionConfigBuilder = ConnectionConfig.custom() + .setConnectTimeout(Timeout.of(DEFAULT_CONNECT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)); + if (connectionConfigCallback != null) { + connectionConfigCallback.accept(connectionConfigBuilder); + } - PoolingAsyncClientConnectionManager defaultConnectionManager = + PoolingAsyncClientConnectionManagerBuilder connectionManagerBuilder = PoolingAsyncClientConnectionManagerBuilder.create() - .setDefaultConnectionConfig(connectionConfig) + .setDefaultConnectionConfig(connectionConfigBuilder.build()) .setMaxConnPerRoute(DEFAULT_MAX_CONN_PER_ROUTE) .setMaxConnTotal(DEFAULT_MAX_CONN_TOTAL) - .setTlsStrategy(new BasicClientTlsStrategy(sslContext)) - .build(); + .setTlsStrategy(new BasicClientTlsStrategy(sslContext)); + + if (connectionManagerCallback != null) { + connectionManagerCallback.accept(connectionManagerBuilder); + } HttpAsyncClientBuilder httpClientBuilder = HttpAsyncClientBuilder.create() - .setDefaultRequestConfig(requestConfigBuilder) - .setConnectionManager(defaultConnectionManager) + .setDefaultRequestConfig(requestConfigBuilder.build()) + .setConnectionManager(connectionManagerBuilder.build()) .setUserAgent(USER_AGENT_HEADER_VALUE) .setTargetAuthenticationStrategy(new DefaultAuthenticationStrategy()) .setThreadFactory(new RestClientThreadFactory()); @@ -407,6 +473,9 @@ private CloseableHttpAsyncClient createHttpClient() { if (this.routePlanner != null) { httpClientBuilder.setRoutePlanner(this.routePlanner); } + if (httpClientConfigCallback != null) { + httpClientConfigCallback.accept(httpClientBuilder); + } return httpClientBuilder.build(); } catch (NoSuchAlgorithmException e) { diff --git a/java-client/src/test/java/co/elastic/clients/documentation/rest5_client/RestClientDocumentation.java b/java-client/src/test/java/co/elastic/clients/documentation/rest5_client/RestClientDocumentation.java index fb8756033..9e539b2d2 100644 --- a/java-client/src/test/java/co/elastic/clients/documentation/rest5_client/RestClientDocumentation.java +++ b/java-client/src/test/java/co/elastic/clients/documentation/rest5_client/RestClientDocumentation.java @@ -30,8 +30,7 @@ import co.elastic.clients.transport.rest5_client.low_level.Rest5Client; import co.elastic.clients.transport.rest5_client.low_level.Rest5ClientBuilder; import org.apache.hc.client5.http.config.RequestConfig; -import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient; -import org.apache.hc.client5.http.impl.async.HttpAsyncClients; +import org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder; import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager; import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder; import org.apache.hc.core5.http.ContentType; @@ -183,13 +182,11 @@ public void onFailure(Node node) { .setMaxConnPerRoute(5) .build(); - CloseableHttpAsyncClient httpclient = HttpAsyncClients.custom() - .setConnectionManager(connectionManager) - .build(); - Rest5ClientBuilder builder = Rest5Client .builder(new HttpHost("http", "localhost", 9200)) - .setHttpClient(httpclient); + .setHttpClientConfigCallback(c -> c + .setConnectionManager(connectionManager) + ); //end::rest-client-init-request-config-callback } @@ -319,13 +316,10 @@ public void commonConfiguration() throws Exception { RequestConfig.Builder requestConfigBuilder = RequestConfig.custom() .setConnectTimeout(Timeout.of(5000, TimeUnit.MILLISECONDS)); - CloseableHttpAsyncClient httpclient = HttpAsyncClients.custom() - .setDefaultRequestConfig(requestConfigBuilder.build()) - .build(); - Rest5ClientBuilder builder = Rest5Client .builder(new HttpHost("localhost", 9200)) - .setHttpClient(httpclient); + .setHttpClientConfigCallback(c -> c + .setDefaultRequestConfig(requestConfigBuilder.build())); //end::rest-client-config-timeouts } { @@ -342,15 +336,12 @@ public void commonConfiguration() throws Exception { } { //tag::rest-client-config-threads - CloseableHttpAsyncClient httpclient = HttpAsyncClients.custom() - .setIOReactorConfig( - IOReactorConfig.custom().setIoThreadCount(1).build() - ) - .build(); Rest5ClientBuilder builder = Rest5Client .builder(new HttpHost("localhost", 9200)) - .setHttpClient(httpclient); + .setHttpClientConfigCallback(c -> c + .setIOReactorConfig(IOReactorConfig.custom().setIoThreadCount(1).build() + )); //end::rest-client-config-threads } { @@ -372,13 +363,9 @@ public void commonConfiguration() throws Exception { var creds = Base64.getEncoder().encodeToString("user:test-user-password".getBytes()); - CloseableHttpAsyncClient httpclient = HttpAsyncClients.custom() - .disableAuthCaching() // <1> - .build(); - Rest5ClientBuilder restClient = Rest5Client .builder(new HttpHost("https", "localhost", 9200)) - .setHttpClient(httpclient) + .setHttpClientConfigCallback(HttpAsyncClientBuilder::disableAuthCaching) // <1> .setDefaultHeaders(new Header[]{ new BasicHeader("Authorization", "Basic " + creds) });