summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjørn Christian Seime <bjorncs@verizonmedia.com>2021-05-11 13:32:09 +0200
committerBjørn Christian Seime <bjorncs@verizonmedia.com>2021-05-11 13:32:09 +0200
commit7ac7e6e3c39fd80b24c38561949466e4fc00921a (patch)
tree47245435575610ae2365f7e302d28e08eda40daa
parentd620a96865da85cef199a1b73e10dbeeacca99cf (diff)
Construct underlying apache httpclient5 builder
-rw-r--r--vespa-feed-client/src/main/java/com/yahoo/vespa/feed/client/FeedClientBuilder.java30
-rw-r--r--vespa-feed-client/src/main/java/com/yahoo/vespa/feed/client/HttpFeedClient.java73
2 files changed, 103 insertions, 0 deletions
diff --git a/vespa-feed-client/src/main/java/com/yahoo/vespa/feed/client/FeedClientBuilder.java b/vespa-feed-client/src/main/java/com/yahoo/vespa/feed/client/FeedClientBuilder.java
index e49d253a321..9e5f2a53a8d 100644
--- a/vespa-feed-client/src/main/java/com/yahoo/vespa/feed/client/FeedClientBuilder.java
+++ b/vespa-feed-client/src/main/java/com/yahoo/vespa/feed/client/FeedClientBuilder.java
@@ -1,14 +1,44 @@
// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.feed.client;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLContext;
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Supplier;
+
/**
+ * Builder for creating a {@link FeedClient} instance.
+ *
* @author bjorncs
*/
public class FeedClientBuilder {
+ SSLContext sslContext;
+ HostnameVerifier hostnameVerifier;
+ final Map<String, Supplier<String>> requestHeaders = new HashMap<>();
+ URI endpoint;
+ Integer maxConnections;
+
public static FeedClientBuilder create() { return new FeedClientBuilder(); }
private FeedClientBuilder() {}
+ public FeedClientBuilder setMaxConnection(int max) { this.maxConnections = max; return this; }
+
+ public FeedClientBuilder setEndpoint(URI endpoint) { this.endpoint = endpoint; return this; }
+
+ public FeedClientBuilder setSslContext(SSLContext context) { this.sslContext = context; return this; }
+
+ public FeedClientBuilder setHostnameVerifier(HostnameVerifier verifier) { this.hostnameVerifier = verifier; return this; }
+
+ public FeedClientBuilder addRequestHeader(String name, String value) { return addRequestHeader(name, () -> value); }
+
+ public FeedClientBuilder addRequestHeader(String name, Supplier<String> valueSupplier) {
+ this.requestHeaders.put(name, valueSupplier);
+ return this;
+ }
+
public FeedClient build() { return new HttpFeedClient(this); }
}
diff --git a/vespa-feed-client/src/main/java/com/yahoo/vespa/feed/client/HttpFeedClient.java b/vespa-feed-client/src/main/java/com/yahoo/vespa/feed/client/HttpFeedClient.java
index 6cf56ac9cdd..a7e39001117 100644
--- a/vespa-feed-client/src/main/java/com/yahoo/vespa/feed/client/HttpFeedClient.java
+++ b/vespa-feed-client/src/main/java/com/yahoo/vespa/feed/client/HttpFeedClient.java
@@ -1,15 +1,85 @@
// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.feed.client;
+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.HttpAsyncClientBuilder;
+import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
+import org.apache.hc.client5.http.ssl.ClientTlsStrategyBuilder;
+import org.apache.hc.core5.http.message.BasicHeader;
+import org.apache.hc.core5.http2.config.H2Config;
+import org.apache.hc.core5.pool.PoolConcurrencyPolicy;
+import org.apache.hc.core5.reactor.IOReactorConfig;
+import org.apache.hc.core5.util.TimeValue;
+import org.apache.hc.core5.util.Timeout;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
import java.util.concurrent.Future;
+import java.util.function.Supplier;
/**
+ * HTTP implementation of {@link FeedClient}
+ *
* @author bjorncs
*/
class HttpFeedClient implements FeedClient {
+ private final CloseableHttpAsyncClient httpClient;
+ private final URI endpoint;
+ private final Map<String, Supplier<String>> requestHeaders;
+
HttpFeedClient(FeedClientBuilder builder) {
+ this.httpClient = createHttpClient(builder);
+ this.endpoint = getEndpoint(builder);
+ this.requestHeaders = new HashMap<>(builder.requestHeaders);
+ }
+
+ private static CloseableHttpAsyncClient createHttpClient(FeedClientBuilder builder) {
+ HttpAsyncClientBuilder httpClientBuilder = HttpAsyncClientBuilder.create()
+ .setUserAgent(String.format("vespa-feed-client/%s", Vespa.VERSION))
+ .setDefaultHeaders(Collections.singletonList(new BasicHeader("Vespa-Client-Version", Vespa.VERSION)))
+ .disableCookieManagement()
+ .disableRedirectHandling()
+ .disableConnectionState()
+ .setIOReactorConfig(IOReactorConfig.custom()
+ .setSoTimeout(Timeout.ofSeconds(10))
+ .build())
+ .setDefaultRequestConfig(
+ RequestConfig.custom()
+ .setConnectTimeout(Timeout.ofSeconds(10))
+ .setConnectionRequestTimeout(Timeout.DISABLED)
+ .setResponseTimeout(Timeout.ofMinutes(5))
+ .build())
+ .setH2Config(H2Config.custom()
+ .setMaxConcurrentStreams(128)
+ .setPushEnabled(false)
+ .build());
+ int maxConnections = builder.maxConnections != null ? builder.maxConnections : 4;
+ PoolingAsyncClientConnectionManagerBuilder connectionManagerBuilder = PoolingAsyncClientConnectionManagerBuilder.create()
+ .setConnectionTimeToLive(TimeValue.ofMinutes(10))
+ .setMaxConnTotal(maxConnections)
+ .setMaxConnPerRoute(maxConnections)
+ .setPoolConcurrencyPolicy(PoolConcurrencyPolicy.LAX);
+ if (builder.sslContext != null) {
+ ClientTlsStrategyBuilder tlsStrategyBuilder = ClientTlsStrategyBuilder.create()
+ .setSslContext(builder.sslContext);
+ if (builder.hostnameVerifier != null) {
+ tlsStrategyBuilder.setHostnameVerifier(builder.hostnameVerifier);
+ }
+ connectionManagerBuilder.setTlsStrategy(tlsStrategyBuilder.build());
+ }
+ httpClientBuilder.setConnectionManager(connectionManagerBuilder.build());
+ return httpClientBuilder.build();
+ }
+
+ private static URI getEndpoint(FeedClientBuilder builder) {
+ if (builder.endpoint == null) throw new IllegalArgumentException("Endpoint must be specified");
+ return builder.endpoint;
}
@Override
@@ -26,4 +96,7 @@ class HttpFeedClient implements FeedClient {
public Future<Result> update(String documentId, String documentJson, OperationParameters params, ResultCallback callback) {
return null;
}
+
+ @Override public void close() throws IOException { this.httpClient.close(); }
+
}