Skip to content

Commit 2c4e974

Browse files
authored
Reintroduce httpclientbuilder callback (#1037)
* add config callback to rest5 builder * modern java, updated docs * checkstyle * more callbacks
1 parent c6d8d81 commit 2c4e974

File tree

5 files changed

+109
-59
lines changed

5 files changed

+109
-59
lines changed

docs/reference/transport/rest5-client/config/basic_authentication.md

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,17 @@ Rest5ClientBuilder restClient = Rest5Client
1616

1717
```
1818

19-
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`:
19+
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`:
2020

2121
% :::{include-code} src={{doc-tests-src}}/rest5_client/RestClientDocumentation.java tag=rest-client-config-disable-preemptive-auth
2222
```java
2323
HttpHost host = new HttpHost("http", "localhost", 9200);
2424

2525
var creds = Base64.getEncoder().encodeToString("user:test-user-password".getBytes());
2626

27-
CloseableHttpAsyncClient httpclient = HttpAsyncClients.custom()
28-
.disableAuthCaching() // <1>
29-
.build();
30-
3127
Rest5ClientBuilder restClient = Rest5Client
3228
.builder(new HttpHost("https", "localhost", 9200))
33-
.setHttpClient(httpclient)
29+
.setHttpClientConfigCallback(HttpAsyncClientBuilder::disableAuthCaching)
3430
.setDefaultHeaders(new Header[]{
3531
new BasicHeader("Authorization", "Basic " + creds)
3632
});

docs/reference/transport/rest5-client/config/number_of_threads.md

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,11 @@ The Apache Http Async Client starts by default one dispatcher thread, and a numb
55

66
% :::{include-code} src={{doc-tests-src}}/rest5_client/RestClientDocumentation.java tag=rest-client-config-threads
77
```java
8-
CloseableHttpAsyncClient httpclient = HttpAsyncClients.custom()
9-
.setIOReactorConfig(
10-
IOReactorConfig.custom().setIoThreadCount(1).build()
11-
)
12-
.build();
13-
148
Rest5ClientBuilder builder = Rest5Client
159
.builder(new HttpHost("localhost", 9200))
16-
.setHttpClient(httpclient);
10+
.setHttpClientConfigCallback(c -> c
11+
.setIOReactorConfig(IOReactorConfig.custom()
12+
.setIoThreadCount(1).build()
13+
)
14+
);
1715
```
Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,20 @@
11

22
# Timeouts
33

4-
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).
4+
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).
55

66
% :::{include-code} src={{doc-tests-src}}/rest5_client/RestClientDocumentation.java tag=rest-client-config-timeouts
77
```java
8-
RequestConfig.Builder requestConfigBuilder = RequestConfig.custom()
9-
.setConnectTimeout(Timeout.of(5000, TimeUnit.MILLISECONDS));
10-
11-
CloseableHttpAsyncClient httpclient = HttpAsyncClients.custom()
12-
.setDefaultRequestConfig(requestConfigBuilder.build())
13-
.build();
14-
158
Rest5ClientBuilder builder = Rest5Client
169
.builder(new HttpHost("localhost", 9200))
17-
.setHttpClient(httpclient);
10+
.setRequestConfigCallback(r -> r
11+
.setConnectTimeout(Timeout.of(5000, TimeUnit.MILLISECONDS))
12+
.setResponseTimeout(Timeout.of(30000, TimeUnit.MILLISECONDS))
13+
.build()
14+
);
1815
```
1916

20-
Timeouts also can be set per request with RequestOptions, which overrides RestClient customizeRequestConfig.
17+
Timeouts also can be set per request with RequestOptions, which overrides RestClient's builder. The RequestOptions can then be set in the Rest5ClientTransport constructor.
2118

2219
% :::{include-code} src={{doc-tests-src}}/rest5_client/RestClientDocumentation.java tag=rest-client-config-request-options-timeouts
2320
```java
@@ -29,5 +26,8 @@ RequestConfig requestConfig = RequestConfig.custom()
2926
RequestOptions options = RequestOptions.DEFAULT.toBuilder()
3027
.setRequestConfig(requestConfig)
3128
.build();
29+
30+
ElasticsearchTransport transport = new Rest5ClientTransport(
31+
restClient, new JacksonJsonpMapper(), options);
3232
```
3333

java-client/src/main/java/co/elastic/clients/transport/rest5_client/low_level/Rest5ClientBuilder.java

Lines changed: 82 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import java.util.concurrent.ThreadFactory;
4747
import java.util.concurrent.TimeUnit;
4848
import java.util.concurrent.atomic.AtomicLong;
49+
import java.util.function.Consumer;
4950

5051
import static co.elastic.clients.transport.rest5_client.low_level.LanguageRuntimeVersions.getRuntimeMetadata;
5152

@@ -75,6 +76,10 @@ public final class Rest5ClientBuilder {
7576

7677
private final List<Node> nodes;
7778
private CloseableHttpAsyncClient httpClient;
79+
private Consumer<HttpAsyncClientBuilder> httpClientConfigCallback;
80+
private Consumer<RequestConfig.Builder> requestConfigCallback;
81+
private Consumer<ConnectionConfig.Builder> connectionConfigCallback;
82+
private Consumer<PoolingAsyncClientConnectionManagerBuilder> connectionManagerCallback;
7883
private Header[] defaultHeaders = EMPTY_HEADERS;
7984
private Rest5Client.FailureListener failureListener;
8085
private SSLContext sslContext;
@@ -320,6 +325,58 @@ public Rest5ClientBuilder setMetaHeaderEnabled(boolean metadataEnabled) {
320325
return this;
321326
}
322327

328+
/**
329+
* Allows to customize the {@link CloseableHttpAsyncClient} being created and used by the
330+
* {@link Rest5Client}.
331+
* Commonly used to customize {@link HttpAsyncClientBuilder} without losing any other useful default
332+
* value that the {@link Rest5ClientBuilder} internally sets.
333+
* @throws NullPointerException if {@code httpClientConfigCallback} is {@code null}.
334+
*/
335+
public Rest5ClientBuilder setHttpClientConfigCallback(Consumer<HttpAsyncClientBuilder> httpClientConfigCallback) {
336+
Objects.requireNonNull(httpClientConfigCallback, "httpClientConfigCallback must not be null");
337+
this.httpClientConfigCallback = httpClientConfigCallback;
338+
return this;
339+
}
340+
341+
/**
342+
* Allows to customize the {@link RequestConfig} created by the {@link Rest5Client}
343+
* and used by the {@link CloseableHttpAsyncClient}.
344+
* Commonly used to customize {@link RequestConfig} without losing any other useful default
345+
* value that the {@link Rest5ClientBuilder} internally sets.
346+
* @throws NullPointerException if {@code requestConfigCallback} is {@code null}.
347+
*/
348+
public Rest5ClientBuilder setRequestConfigCallback(Consumer<RequestConfig.Builder> requestConfigCallback) {
349+
Objects.requireNonNull(requestConfigCallback, "requestConfigCallback must not be null");
350+
this.requestConfigCallback = requestConfigCallback;
351+
return this;
352+
}
353+
354+
/**
355+
* Allows to customize the {@link ConnectionConfig} created by the {@link Rest5Client}
356+
* and used by the {@link CloseableHttpAsyncClient}.
357+
* Commonly used to customize {@link ConnectionConfig} without losing any other useful default
358+
* value that the {@link Rest5ClientBuilder} internally sets.
359+
* @throws NullPointerException if {@code connectionConfigCallback} is {@code null}.
360+
*/
361+
public Rest5ClientBuilder setConnectionConfigCallback(Consumer<ConnectionConfig.Builder> connectionConfigCallback) {
362+
Objects.requireNonNull(connectionConfigCallback, "connectionConfigCallback must not be null");
363+
this.connectionConfigCallback = connectionConfigCallback;
364+
return this;
365+
}
366+
367+
/**
368+
* Allows to customize the {@link PoolingAsyncClientConnectionManager} created by the {@link Rest5Client}
369+
* and used by the {@link CloseableHttpAsyncClient}.
370+
* Commonly used to customize {@link PoolingAsyncClientConnectionManager} without losing any other useful default
371+
* value that the {@link Rest5ClientBuilder} internally sets.
372+
* @throws NullPointerException if {@code connectionManagerCallback} is {@code null}.
373+
*/
374+
public Rest5ClientBuilder setConnectionManagerCallback(Consumer<PoolingAsyncClientConnectionManagerBuilder> connectionManagerCallback) {
375+
Objects.requireNonNull(connectionManagerCallback, "connectionManagerCallback must not be null");
376+
this.connectionManagerCallback = connectionManagerCallback;
377+
return this;
378+
}
379+
323380
/**
324381
* Creates a new {@link Rest5Client} based on the provided configuration.
325382
*/
@@ -369,31 +426,40 @@ private CloseableHttpAsyncClient createHttpClient() {
369426
return this.httpClient;
370427
}
371428
// otherwise, creating a default instance of CloseableHttpAsyncClient
372-
// default timeouts are all 3 mins
373-
RequestConfig requestConfigBuilder = RequestConfig.custom()
429+
430+
// default timeouts are all 3 mins, replacing those
431+
RequestConfig.Builder requestConfigBuilder = RequestConfig.custom()
374432
.setConnectionRequestTimeout(Timeout.of(DEFAULT_SOCKET_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS))
375-
.setResponseTimeout(Timeout.of(DEFAULT_RESPONSE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS))
376-
.build();
433+
.setResponseTimeout(Timeout.of(DEFAULT_RESPONSE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
434+
435+
if (requestConfigCallback != null) {
436+
requestConfigCallback.accept(requestConfigBuilder);
437+
}
377438

378439
try {
379440

380441
SSLContext sslContext = this.sslContext != null ? this.sslContext : SSLContext.getDefault();
381442

382-
ConnectionConfig connectionConfig = ConnectionConfig.custom()
383-
.setConnectTimeout(Timeout.of(DEFAULT_CONNECT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS))
384-
.build();
443+
ConnectionConfig.Builder connectionConfigBuilder = ConnectionConfig.custom()
444+
.setConnectTimeout(Timeout.of(DEFAULT_CONNECT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
445+
if (connectionConfigCallback != null) {
446+
connectionConfigCallback.accept(connectionConfigBuilder);
447+
}
385448

386-
PoolingAsyncClientConnectionManager defaultConnectionManager =
449+
PoolingAsyncClientConnectionManagerBuilder connectionManagerBuilder =
387450
PoolingAsyncClientConnectionManagerBuilder.create()
388-
.setDefaultConnectionConfig(connectionConfig)
451+
.setDefaultConnectionConfig(connectionConfigBuilder.build())
389452
.setMaxConnPerRoute(DEFAULT_MAX_CONN_PER_ROUTE)
390453
.setMaxConnTotal(DEFAULT_MAX_CONN_TOTAL)
391-
.setTlsStrategy(new BasicClientTlsStrategy(sslContext))
392-
.build();
454+
.setTlsStrategy(new BasicClientTlsStrategy(sslContext));
455+
456+
if (connectionManagerCallback != null) {
457+
connectionManagerCallback.accept(connectionManagerBuilder);
458+
}
393459

394460
HttpAsyncClientBuilder httpClientBuilder = HttpAsyncClientBuilder.create()
395-
.setDefaultRequestConfig(requestConfigBuilder)
396-
.setConnectionManager(defaultConnectionManager)
461+
.setDefaultRequestConfig(requestConfigBuilder.build())
462+
.setConnectionManager(connectionManagerBuilder.build())
397463
.setUserAgent(USER_AGENT_HEADER_VALUE)
398464
.setTargetAuthenticationStrategy(new DefaultAuthenticationStrategy())
399465
.setThreadFactory(new RestClientThreadFactory());
@@ -407,6 +473,9 @@ private CloseableHttpAsyncClient createHttpClient() {
407473
if (this.routePlanner != null) {
408474
httpClientBuilder.setRoutePlanner(this.routePlanner);
409475
}
476+
if (httpClientConfigCallback != null) {
477+
httpClientConfigCallback.accept(httpClientBuilder);
478+
}
410479

411480
return httpClientBuilder.build();
412481
} catch (NoSuchAlgorithmException e) {

java-client/src/test/java/co/elastic/clients/documentation/rest5_client/RestClientDocumentation.java

Lines changed: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,7 @@
3030
import co.elastic.clients.transport.rest5_client.low_level.Rest5Client;
3131
import co.elastic.clients.transport.rest5_client.low_level.Rest5ClientBuilder;
3232
import org.apache.hc.client5.http.config.RequestConfig;
33-
import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
34-
import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
33+
import org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder;
3534
import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager;
3635
import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
3736
import org.apache.hc.core5.http.ContentType;
@@ -183,13 +182,11 @@ public void onFailure(Node node) {
183182
.setMaxConnPerRoute(5)
184183
.build();
185184

186-
CloseableHttpAsyncClient httpclient = HttpAsyncClients.custom()
187-
.setConnectionManager(connectionManager)
188-
.build();
189-
190185
Rest5ClientBuilder builder = Rest5Client
191186
.builder(new HttpHost("http", "localhost", 9200))
192-
.setHttpClient(httpclient);
187+
.setHttpClientConfigCallback(c -> c
188+
.setConnectionManager(connectionManager)
189+
);
193190
//end::rest-client-init-request-config-callback
194191
}
195192

@@ -319,13 +316,10 @@ public void commonConfiguration() throws Exception {
319316
RequestConfig.Builder requestConfigBuilder = RequestConfig.custom()
320317
.setConnectTimeout(Timeout.of(5000, TimeUnit.MILLISECONDS));
321318

322-
CloseableHttpAsyncClient httpclient = HttpAsyncClients.custom()
323-
.setDefaultRequestConfig(requestConfigBuilder.build())
324-
.build();
325-
326319
Rest5ClientBuilder builder = Rest5Client
327320
.builder(new HttpHost("localhost", 9200))
328-
.setHttpClient(httpclient);
321+
.setHttpClientConfigCallback(c -> c
322+
.setDefaultRequestConfig(requestConfigBuilder.build()));
329323
//end::rest-client-config-timeouts
330324
}
331325
{
@@ -342,15 +336,12 @@ public void commonConfiguration() throws Exception {
342336
}
343337
{
344338
//tag::rest-client-config-threads
345-
CloseableHttpAsyncClient httpclient = HttpAsyncClients.custom()
346-
.setIOReactorConfig(
347-
IOReactorConfig.custom().setIoThreadCount(1).build()
348-
)
349-
.build();
350339

351340
Rest5ClientBuilder builder = Rest5Client
352341
.builder(new HttpHost("localhost", 9200))
353-
.setHttpClient(httpclient);
342+
.setHttpClientConfigCallback(c -> c
343+
.setIOReactorConfig(IOReactorConfig.custom().setIoThreadCount(1).build()
344+
));
354345
//end::rest-client-config-threads
355346
}
356347
{
@@ -372,13 +363,9 @@ public void commonConfiguration() throws Exception {
372363

373364
var creds = Base64.getEncoder().encodeToString("user:test-user-password".getBytes());
374365

375-
CloseableHttpAsyncClient httpclient = HttpAsyncClients.custom()
376-
.disableAuthCaching() // <1>
377-
.build();
378-
379366
Rest5ClientBuilder restClient = Rest5Client
380367
.builder(new HttpHost("https", "localhost", 9200))
381-
.setHttpClient(httpclient)
368+
.setHttpClientConfigCallback(HttpAsyncClientBuilder::disableAuthCaching) // <1>
382369
.setDefaultHeaders(new Header[]{
383370
new BasicHeader("Authorization", "Basic " + creds)
384371
});

0 commit comments

Comments
 (0)