io.datarouter.httpclient.client.DatarouterHttpClientBuilder Maven / Gradle / Ivy
The newest version!
/*
* Copyright © 2009 HotPads ([email protected])
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.datarouter.httpclient.client;
import java.net.URI;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.time.Duration;
import java.util.Optional;
import java.util.function.Supplier;
import javax.net.ssl.SSLContext;
import org.apache.http.client.RedirectStrategy;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustAllStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.LaxRedirectStrategy;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContextBuilder;
import io.datarouter.httpclient.endpoint.java.JavaEndpointType;
import io.datarouter.httpclient.endpoint.link.LinkType;
import io.datarouter.httpclient.link.DatarouterLinkSettings;
import io.datarouter.httpclient.security.CsrfGenerator;
import io.datarouter.httpclient.security.CsrfGenerator.RefreshableCsrfGenerator;
import io.datarouter.httpclient.security.SecurityParameters;
import io.datarouter.httpclient.security.SignatureGenerator;
import io.datarouter.httpclient.security.SignatureGenerator.RefreshableSignatureGenerator;
import io.datarouter.instrumentation.refreshable.RefreshableSupplier;
import io.datarouter.json.JsonSerializer;
public class DatarouterHttpClientBuilder{
public static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(3);
public static final int DEFAULT_MAX_TOTAL_CONNECTIONS = 200;
private final String clientName;
private final JsonSerializer jsonSerializer;
private int timeoutMs; // must be int due to RequestConfig.set*Timeout() methods
private int connectTimeoutMs;
private int maxTotalConnections;
private int maxConnectionsPerRoute;
private Optional validateAfterInactivityMs;
private final HttpClientBuilder httpClientBuilder;
private Supplier retryCount;
private CloseableHttpClient customHttpClient;
private SignatureGenerator signatureGenerator;
private CsrfGenerator csrfGenerator;
private Supplier apiKeySupplier;
private RefreshableSignatureGenerator refreshableSignatureGenerator;
private RefreshableCsrfGenerator refreshableCsrfGenerator;
private RefreshableSupplier refreshableApiKeySupplier;
private DatarouterHttpClientConfig config;
private boolean ignoreSsl;
private SSLContext customSslContext;
private final String simpleClassName;
private Supplier urlPrefix;
private Supplier traceInQueryString;
private Supplier debugLog;
private String apiKeyFieldName;
public DatarouterHttpClientBuilder(String clientName, JsonSerializer jsonSerializer){
this.clientName = clientName;
this.jsonSerializer = jsonSerializer;
this.timeoutMs = (int)DEFAULT_TIMEOUT.toMillis();
this.connectTimeoutMs = (int)Duration.ofSeconds(1).toMillis();
this.maxTotalConnections = DEFAULT_MAX_TOTAL_CONNECTIONS;
this.maxConnectionsPerRoute = 200;
this.validateAfterInactivityMs = Optional.empty();
this.httpClientBuilder = HttpClientBuilder.create()
.setRedirectStrategy(LaxRedirectStrategy.INSTANCE);
this.retryCount = () -> HttpRetryTool.DEFAULT_RETRY_COUNT;
String className = new Throwable().getStackTrace()[1].getClassName();
this.simpleClassName = className.substring(className.lastIndexOf(".") + 1, className.length());
this.traceInQueryString = () -> false;
this.debugLog = () -> false;
this.apiKeyFieldName = SecurityParameters.API_KEY;
}
private StandardDatarouterHttpClient buildStandardDatarouterHttpClient(){
httpClientBuilder.setRetryHandler(new DatarouterHttpRetryHandler(retryCount));
httpClientBuilder.setServiceUnavailableRetryStrategy(new DatarouterServiceUnavailableRetryStrategy(retryCount));
RequestConfig defaultRequestConfig = RequestConfig.custom()
.setCookieSpec(CookieSpecs.STANDARD)
.setConnectTimeout(connectTimeoutMs)
.setConnectionRequestTimeout(timeoutMs)
.setSocketTimeout(timeoutMs)
.build();
httpClientBuilder.setDefaultRequestConfig(defaultRequestConfig);
httpClientBuilder.setKeepAliveStrategy(new DatarouterConnectionKeepAliveStrategy(Duration.ofMinutes(5)));
SSLConnectionSocketFactory sslsf;
if(ignoreSsl || customSslContext != null){
if(ignoreSsl){
try{
var ssLContext = new SSLContextBuilder()
.loadTrustMaterial(null, TrustAllStrategy.INSTANCE)
.build();
sslsf = new SSLConnectionSocketFactory(ssLContext, NoopHostnameVerifier.INSTANCE);
}catch(KeyManagementException | KeyStoreException | NoSuchAlgorithmException e){
throw new RuntimeException(e);
}
}else{
sslsf = new SSLConnectionSocketFactory(
customSslContext,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
}
}else{
sslsf = SSLConnectionSocketFactory.getSocketFactory();
}
Registry socketFactoryRegistry = RegistryBuilder
.create()
.register(
"http",
new DatarouterConnectionSocketFactory(PlainConnectionSocketFactory.INSTANCE, simpleClassName))
.register("https", new DatarouterLayeredConnectionSocketFactory(sslsf, simpleClassName))
.build();
var connectionManager = new PoolingHttpClientConnectionManager(
socketFactoryRegistry,
null,
new DatarouterHttpClientDnsResolver(simpleClassName));
connectionManager.setMaxTotal(maxTotalConnections);
connectionManager.setDefaultMaxPerRoute(maxConnectionsPerRoute);
validateAfterInactivityMs.ifPresent(connectionManager::setValidateAfterInactivity);
httpClientBuilder.setConnectionManager(connectionManager);
CloseableHttpClient builtHttpClient;
if(customHttpClient == null){
builtHttpClient = httpClientBuilder.build();
}else{
builtHttpClient = customHttpClient;
}
if(config == null){
config = new DatarouterHttpClientDefaultConfig();
}
return new StandardDatarouterHttpClient(
clientName,
builtHttpClient,
this.jsonSerializer,
this.signatureGenerator,
this.csrfGenerator,
this.apiKeySupplier,
this.refreshableSignatureGenerator,
this.refreshableCsrfGenerator,
this.refreshableApiKeySupplier,
this.config,
connectionManager,
simpleClassName,
urlPrefix,
traceInQueryString,
debugLog,
apiKeyFieldName);
}
public DatarouterHttpClient build(){
return buildStandardDatarouterHttpClient();
}
public DatarouterEndpointClient buildEndpointClient(){
StandardDatarouterHttpClient client = buildStandardDatarouterHttpClient();
return new StandardDatarouterEndpointClient<>(client);
}
public DatarouterLinkClient buildLinkClient(){
StandardDatarouterHttpClient client = buildStandardDatarouterHttpClient();
return new StandardDatarouterLinkClient<>(client);
}
public DatarouterHttpClientBuilder setRetryCount(Supplier retryCount){
if(customHttpClient != null){
throw new UnsupportedOperationException("You cannot change the retry count of a custom http client");
}
this.retryCount = retryCount;
return this;
}
public DatarouterHttpClientBuilder setCustomHttpClient(CloseableHttpClient httpClient){
this.customHttpClient = httpClient;
return this;
}
public DatarouterHttpClientBuilder setSignatureGenerator(SignatureGenerator signatureGenerator){
this.signatureGenerator = signatureGenerator;
return this;
}
public DatarouterHttpClientBuilder setCsrfGenerator(CsrfGenerator csrfGenerator){
this.csrfGenerator = csrfGenerator;
return this;
}
public DatarouterHttpClientBuilder setApiKeySupplier(Supplier apiKeySupplier){
this.apiKeySupplier = apiKeySupplier;
return this;
}
public DatarouterHttpClientBuilder setRefreshableSignatureGenerator(
RefreshableSignatureGenerator refreshableSignatureGenerator){
this.refreshableSignatureGenerator = refreshableSignatureGenerator;
return this;
}
public DatarouterHttpClientBuilder setRefreshableCsrfGenerator(RefreshableCsrfGenerator refreshableCsrfGenerator){
this.refreshableCsrfGenerator = refreshableCsrfGenerator;
return this;
}
public DatarouterHttpClientBuilder setRefreshableApiKeySupplier(
RefreshableSupplier refreshableApiKeySupplier){
this.refreshableApiKeySupplier = refreshableApiKeySupplier;
return this;
}
public DatarouterHttpClientBuilder setConfig(DatarouterHttpClientConfig config){
this.config = config;
return this;
}
public DatarouterHttpClientBuilder setMaxTotalConnections(int maxTotalConnections){
this.maxTotalConnections = maxTotalConnections;
return this;
}
public DatarouterHttpClientBuilder setMaxConnectionsPerRoute(int maxConnectionsPerRoute){
this.maxConnectionsPerRoute = maxConnectionsPerRoute;
return this;
}
// TODO rename to setReadTimeout
public DatarouterHttpClientBuilder setTimeout(Duration timeout){
this.timeoutMs = (int)timeout.toMillis();
return this;
}
public DatarouterHttpClientBuilder setConnectTimeoutMs(Duration connectTimeoutMs){
this.connectTimeoutMs = (int)connectTimeoutMs.toMillis();
return this;
}
public DatarouterHttpClientBuilder setIgnoreSsl(boolean ignoreSsl){
this.ignoreSsl = ignoreSsl;
return this;
}
public DatarouterHttpClientBuilder setCustomSslContext(SSLContext customSslContext){
this.customSslContext = customSslContext;
return this;
}
public DatarouterHttpClientBuilder setRedirectStrategy(RedirectStrategy redirectStrategy){
httpClientBuilder.setRedirectStrategy(redirectStrategy);
return this;
}
public DatarouterHttpClientBuilder disableRedirectHandling(){
httpClientBuilder.disableRedirectHandling();
return this;
}
public DatarouterHttpClientBuilder setValidateAfterInactivityMs(int validateAfterInactivityMs){
this.validateAfterInactivityMs = Optional.of(validateAfterInactivityMs);
return this;
}
public DatarouterHttpClientBuilder setUrlPrefix(Supplier urlPrefix){
this.urlPrefix = urlPrefix;
return this;
}
public DatarouterHttpClientBuilder setTraceInQueryString(Supplier traceInQueryString){
this.traceInQueryString = traceInQueryString;
return this;
}
public DatarouterHttpClientBuilder setDebugLog(Supplier debugLog){
this.debugLog = debugLog;
return this;
}
public DatarouterHttpClientBuilder setApiKeyFieldName(String apiKeyFieldName){
this.apiKeyFieldName = apiKeyFieldName;
return this;
}
public DatarouterHttpClientBuilder forDatarouterHttpClientSettings(SimpleDatarouterHttpClientSettings settings){
return this
.setTimeout(settings.getTimeout())
.setRetryCount(settings.getNumRetries())
.setTraceInQueryString(settings.getTraceInQueryString())
.setDebugLog(settings.getDebugLog());
}
public DatarouterHttpClientBuilder forDatarouterHttpClientSettings(DatarouterHttpClientSettings settings){
return forDatarouterHttpClientSettings((SimpleDatarouterHttpClientSettings)settings)
.setUrlPrefix(settings::getEndpointUrl);
}
public DatarouterHttpClientBuilder forLinkSettings(
DatarouterLinkSettings settings, String serviceName){
return this.setUrlPrefix(settings.getLinkUrl(serviceName));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy