Skip to content

Commit 366ede8

Browse files
authored
improving how httpclients can be configured (fabric8io#4490)
* fix fabric8io#4472: refined withRequestConfig so that a new client is not created * fix fabric8io#4471: kubernetesclientbuilder method for the httpclient.builder * fix fabric8io#4471: still need to apply config even with default factory
1 parent 0394a0e commit 366ede8

File tree

33 files changed

+582
-463
lines changed

33 files changed

+582
-463
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
* Fix #4426: [java-generator] Encode an `AnyType` instead of an Object if `x-kubernetes-preserve-unknown-fields` is present and the type is null.
1717

1818
#### Improvements
19+
* Fix #4471: Adding KubernetesClientBuilder.withHttpClientBuilderConsumer to further customize the HttpClient for any implementation.
1920
* Fix #4348: Introduce specific annotations for the generators
2021
* Refactor #4441: refactoring `TokenRefreshInterceptor`
2122
* Fix #4365: The Watch retry logic will handle more cases, as well as perform an exceptional close for events that are not properly handled. Informers can directly provide those exceptional outcomes via the SharedIndexInformer.stopped CompletableFuture.

httpclient-jdk/src/main/java/io/fabric8/kubernetes/client/jdkhttp/JdkHttpClientBuilderImpl.java

Lines changed: 10 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -18,25 +18,17 @@
1818

1919
import io.fabric8.kubernetes.client.http.BasicBuilder;
2020
import io.fabric8.kubernetes.client.http.HttpClient;
21-
import io.fabric8.kubernetes.client.http.HttpClient.Builder;
2221
import io.fabric8.kubernetes.client.http.HttpHeaders;
2322
import io.fabric8.kubernetes.client.http.Interceptor;
23+
import io.fabric8.kubernetes.client.http.StandardHttpClientBuilder;
2424
import io.fabric8.kubernetes.client.http.TlsVersion;
25-
import io.fabric8.kubernetes.client.internal.SSLUtils;
2625

27-
import java.net.InetSocketAddress;
2826
import java.net.ProxySelector;
2927
import java.net.http.HttpClient.Redirect;
3028
import java.net.http.HttpClient.Version;
31-
import java.time.Duration;
3229
import java.util.Arrays;
33-
import java.util.LinkedHashMap;
34-
import java.util.concurrent.TimeUnit;
3530

36-
import javax.net.ssl.KeyManager;
37-
import javax.net.ssl.SSLContext;
3831
import javax.net.ssl.SSLParameters;
39-
import javax.net.ssl.TrustManager;
4032

4133
/**
4234
* TODO: if there is another implementation that does not support client builder copying, then this needs to be abstracted -
@@ -48,28 +40,17 @@
4840
*
4941
*/
5042

51-
class JdkHttpClientBuilderImpl implements Builder {
43+
class JdkHttpClientBuilderImpl
44+
extends StandardHttpClientBuilder<JdkHttpClientImpl, JdkHttpClientFactory, JdkHttpClientBuilderImpl> {
5245

53-
LinkedHashMap<String, Interceptor> interceptors = new LinkedHashMap<>();
54-
Duration connectTimeout;
55-
Duration readTimeout;
56-
private SSLContext sslContext;
57-
JdkHttpClientFactory clientFactory;
58-
private String proxyAuthorization;
59-
private InetSocketAddress proxyAddress;
60-
private boolean followRedirects;
61-
private boolean preferHttp11;
62-
private TlsVersion[] tlsVersions;
63-
private java.net.http.HttpClient httpClient;
64-
65-
JdkHttpClientBuilderImpl(JdkHttpClientFactory factory) {
66-
this.clientFactory = factory;
46+
public JdkHttpClientBuilderImpl(JdkHttpClientFactory factory) {
47+
super(factory);
6748
}
6849

6950
@Override
7051
public HttpClient build() {
71-
if (httpClient != null) {
72-
return new JdkHttpClientImpl(this, httpClient);
52+
if (client != null) {
53+
return new JdkHttpClientImpl(this, client.getHttpClient(), this.requestConfig);
7354
}
7455
java.net.http.HttpClient.Builder builder = clientFactory.createNewHttpClientBuilder();
7556
if (connectTimeout != null) {
@@ -104,101 +85,12 @@ public void before(BasicBuilder builder, HttpHeaders headers) {
10485
Arrays.asList(tlsVersions).stream().map(TlsVersion::javaName).toArray(String[]::new)));
10586
}
10687
clientFactory.additionalConfig(builder);
107-
return new JdkHttpClientImpl(this, builder.build());
108-
}
109-
110-
@Override
111-
public JdkHttpClientBuilderImpl readTimeout(long readTimeout, TimeUnit unit) {
112-
if (readTimeout == 0) {
113-
this.readTimeout = null;
114-
} else {
115-
this.readTimeout = Duration.ofNanos(unit.toNanos(readTimeout));
116-
}
117-
return this;
118-
}
119-
120-
@Override
121-
public Builder connectTimeout(long connectTimeout, TimeUnit unit) {
122-
this.connectTimeout = Duration.ofNanos(unit.toNanos(connectTimeout));
123-
return this;
124-
}
125-
126-
@Override
127-
public Builder forStreaming() {
128-
// nothing to do
129-
return this;
130-
}
131-
132-
@Override
133-
public Builder writeTimeout(long timeout, TimeUnit timeoutUnit) {
134-
// nothing to do
135-
return this;
136-
}
137-
138-
@Override
139-
public Builder addOrReplaceInterceptor(String name, Interceptor interceptor) {
140-
if (interceptor == null) {
141-
interceptors.remove(name);
142-
} else {
143-
interceptors.put(name, interceptor);
144-
}
145-
return this;
88+
return new JdkHttpClientImpl(this, builder.build(), null);
14689
}
14790

14891
@Override
149-
public Builder authenticatorNone() {
150-
return this;
151-
}
152-
153-
@Override
154-
public Builder sslContext(KeyManager[] keyManagers, TrustManager[] trustManagers) {
155-
this.sslContext = SSLUtils.sslContext(keyManagers, trustManagers);
156-
return this;
157-
}
158-
159-
@Override
160-
public Builder followAllRedirects() {
161-
this.followRedirects = true;
162-
return this;
163-
}
164-
165-
@Override
166-
public Builder proxyAddress(InetSocketAddress proxyAddress) {
167-
this.proxyAddress = proxyAddress;
168-
return this;
169-
}
170-
171-
@Override
172-
public Builder proxyAuthorization(String credentials) {
173-
this.proxyAuthorization = credentials;
174-
return this;
175-
}
176-
177-
@Override
178-
public Builder preferHttp11() {
179-
this.preferHttp11 = true;
180-
return this;
181-
}
182-
183-
@Override
184-
public Builder tlsVersions(TlsVersion... tlsVersions) {
185-
this.tlsVersions = tlsVersions;
186-
return this;
187-
}
188-
189-
public JdkHttpClientBuilderImpl copy(java.net.http.HttpClient httpClient) {
190-
JdkHttpClientBuilderImpl copy = new JdkHttpClientBuilderImpl(this.clientFactory);
191-
copy.connectTimeout = this.connectTimeout;
192-
copy.readTimeout = this.readTimeout;
193-
copy.sslContext = this.sslContext;
194-
copy.interceptors = new LinkedHashMap<>(this.interceptors);
195-
copy.proxyAddress = this.proxyAddress;
196-
copy.proxyAuthorization = this.proxyAuthorization;
197-
copy.tlsVersions = this.tlsVersions;
198-
copy.preferHttp11 = this.preferHttp11;
199-
copy.followRedirects = this.followRedirects;
200-
copy.httpClient = httpClient;
201-
return copy;
92+
protected JdkHttpClientBuilderImpl newInstance(JdkHttpClientFactory clientFactory) {
93+
return new JdkHttpClientBuilderImpl(clientFactory);
20294
}
20395

20496
}

httpclient-jdk/src/main/java/io/fabric8/kubernetes/client/jdkhttp/JdkHttpClientFactory.java

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
import io.fabric8.kubernetes.client.Config;
2020
import io.fabric8.kubernetes.client.http.HttpClient;
21-
import io.fabric8.kubernetes.client.utils.HttpClientUtils;
2221
import io.fabric8.kubernetes.client.utils.Utils;
2322

2423
import java.util.concurrent.Executor;
@@ -46,15 +45,6 @@ public void shutdownNow() {
4645

4746
}
4847

49-
@Override
50-
public HttpClient createHttpClient(Config config) {
51-
JdkHttpClientBuilderImpl builderWrapper = newBuilder();
52-
53-
HttpClientUtils.applyCommonConfiguration(config, builderWrapper, this);
54-
55-
return builderWrapper.build();
56-
}
57-
5848
@Override
5949
public JdkHttpClientBuilderImpl newBuilder() {
6050
return new JdkHttpClientBuilderImpl(this);

httpclient-jdk/src/main/java/io/fabric8/kubernetes/client/jdkhttp/JdkHttpClientImpl.java

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package io.fabric8.kubernetes.client.jdkhttp;
1818

19+
import io.fabric8.kubernetes.client.Config;
1920
import io.fabric8.kubernetes.client.http.HttpClient;
2021
import io.fabric8.kubernetes.client.http.HttpRequest;
2122
import io.fabric8.kubernetes.client.http.HttpResponse;
@@ -214,25 +215,27 @@ public HandlerAndAsyncBody(BodyHandler<T> handler, AsyncBody asyncBody) {
214215

215216
private JdkHttpClientBuilderImpl builder;
216217
private java.net.http.HttpClient httpClient;
218+
private Config config;
217219

218-
public JdkHttpClientImpl(JdkHttpClientBuilderImpl builderImpl, java.net.http.HttpClient httpClient) {
220+
public JdkHttpClientImpl(JdkHttpClientBuilderImpl builderImpl, java.net.http.HttpClient httpClient, Config config) {
219221
this.builder = builderImpl;
220222
this.httpClient = httpClient;
223+
this.config = config;
221224
}
222225

223226
@Override
224227
public void close() {
225228
if (this.httpClient == null) {
226229
return;
227230
}
228-
builder.clientFactory.closeHttpClient(this);
231+
builder.getClientFactory().closeHttpClient(this);
229232
// help with default cleanup, which is based upon garbarge collection
230233
this.httpClient = null;
231234
}
232235

233236
@Override
234237
public DerivedClientBuilder newBuilder() {
235-
return this.builder.copy(getHttpClient());
238+
return this.builder.copy(this);
236239
}
237240

238241
@Override
@@ -286,8 +289,8 @@ public <T> CompletableFuture<AsyncResponse<T>> sendAsync(HttpRequest request,
286289
Supplier<HandlerAndAsyncBody<T>> handlerAndAsyncBodySupplier) {
287290
JdkHttpRequestImpl jdkRequest = (JdkHttpRequestImpl) request;
288291
JdkHttpRequestImpl.BuilderImpl builderImpl = jdkRequest.newBuilder();
289-
for (Interceptor interceptor : builder.interceptors.values()) {
290-
interceptor.before(builderImpl, jdkRequest);
292+
for (Interceptor interceptor : builder.getInterceptors().values()) {
293+
Interceptor.useConfig(interceptor, config).before(builderImpl, jdkRequest);
291294
jdkRequest = builderImpl.build();
292295
}
293296

@@ -296,19 +299,20 @@ public <T> CompletableFuture<AsyncResponse<T>> sendAsync(HttpRequest request,
296299
CompletableFuture<AsyncResponse<T>> cf = this.getHttpClient().sendAsync(builderImpl.build().request,
297300
handlerAndAsyncBody.handler).thenApply(r -> new AsyncResponse<>(r, handlerAndAsyncBody.asyncBody));
298301

299-
for (Interceptor interceptor : builder.interceptors.values()) {
302+
for (Interceptor interceptor : builder.getInterceptors().values()) {
300303
cf = cf.thenCompose(ar -> {
301304
java.net.http.HttpResponse<T> response = ar.response;
302305
if (response != null && !HttpResponse.isSuccessful(response.statusCode())) {
303-
return interceptor.afterFailure(builderImpl, new JdkHttpResponseImpl<>(response)).thenCompose(b -> {
304-
if (b) {
305-
HandlerAndAsyncBody<T> interceptedHandlerAndAsyncBody = handlerAndAsyncBodySupplier.get();
306-
307-
return this.getHttpClient().sendAsync(builderImpl.build().request, interceptedHandlerAndAsyncBody.handler)
308-
.thenApply(r -> new AsyncResponse<>(r, interceptedHandlerAndAsyncBody.asyncBody));
309-
}
310-
return CompletableFuture.completedFuture(ar);
311-
});
306+
return Interceptor.useConfig(interceptor, config).afterFailure(builderImpl, new JdkHttpResponseImpl<>(response))
307+
.thenCompose(b -> {
308+
if (b) {
309+
HandlerAndAsyncBody<T> interceptedHandlerAndAsyncBody = handlerAndAsyncBodySupplier.get();
310+
311+
return this.getHttpClient().sendAsync(builderImpl.build().request, interceptedHandlerAndAsyncBody.handler)
312+
.thenApply(r -> new AsyncResponse<>(r, interceptedHandlerAndAsyncBody.asyncBody));
313+
}
314+
return CompletableFuture.completedFuture(ar);
315+
});
312316
}
313317
return CompletableFuture.completedFuture(ar);
314318
});
@@ -324,7 +328,7 @@ public io.fabric8.kubernetes.client.http.WebSocket.Builder newWebSocketBuilder()
324328

325329
@Override
326330
public io.fabric8.kubernetes.client.http.HttpRequest.Builder newHttpRequestBuilder() {
327-
return new JdkHttpRequestImpl.BuilderImpl().timeout(this.builder.readTimeout);
331+
return new JdkHttpRequestImpl.BuilderImpl().timeout(this.builder.getReadTimeout());
328332
}
329333

330334
/*
@@ -344,23 +348,24 @@ public WebSocketResponse(WebSocket w, java.net.http.WebSocketHandshakeException
344348
public CompletableFuture<WebSocket> buildAsync(JdkWebSocketImpl.BuilderImpl webSocketBuilder, Listener listener) {
345349
JdkWebSocketImpl.BuilderImpl copy = webSocketBuilder.copy();
346350

347-
for (Interceptor interceptor : builder.interceptors.values()) {
348-
interceptor.before(copy, new JdkHttpRequestImpl(null, copy.asRequest()));
351+
for (Interceptor interceptor : builder.getInterceptors().values()) {
352+
Interceptor.useConfig(interceptor, config).before(copy, new JdkHttpRequestImpl(null, copy.asRequest()));
349353
}
350354

351355
CompletableFuture<WebSocket> result = new CompletableFuture<>();
352356

353357
CompletableFuture<WebSocketResponse> cf = internalBuildAsync(copy, listener);
354358

355-
for (Interceptor interceptor : builder.interceptors.values()) {
359+
for (Interceptor interceptor : builder.getInterceptors().values()) {
356360
cf = cf.thenCompose(response -> {
357361
if (response.wshse != null && response.wshse.getResponse() != null) {
358-
return interceptor.afterFailure(copy, new JdkHttpResponseImpl<>(response.wshse.getResponse())).thenCompose(b -> {
359-
if (b) {
360-
return this.internalBuildAsync(copy, listener);
361-
}
362-
return CompletableFuture.completedFuture(response);
363-
});
362+
return Interceptor.useConfig(interceptor, config)
363+
.afterFailure(copy, new JdkHttpResponseImpl<>(response.wshse.getResponse())).thenCompose(b -> {
364+
if (b) {
365+
return this.internalBuildAsync(copy, listener);
366+
}
367+
return CompletableFuture.completedFuture(response);
368+
});
364369
}
365370
return CompletableFuture.completedFuture(response);
366371
});
@@ -399,8 +404,8 @@ public CompletableFuture<WebSocketResponse> internalBuildAsync(JdkWebSocketImpl.
399404
}
400405
// the Watch logic sets a websocketTimeout as the readTimeout
401406
// TODO: this should probably be made clearer in the docs
402-
if (this.builder.readTimeout != null) {
403-
newBuilder.connectTimeout(this.builder.readTimeout);
407+
if (this.builder.getReadTimeout() != null) {
408+
newBuilder.connectTimeout(this.builder.getReadTimeout());
404409
}
405410

406411
AtomicLong queueSize = new AtomicLong();
@@ -436,9 +441,4 @@ java.net.http.HttpClient getHttpClient() {
436441
return httpClient;
437442
}
438443

439-
@Override
440-
public Factory getFactory() {
441-
return builder.clientFactory;
442-
}
443-
444444
}

0 commit comments

Comments
 (0)