All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.datarouter.httpclient.client.DatarouterHttpClientBuilder Maven / Gradle / Ivy

There is a newer version: 0.0.126
Show 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.lang.StackWalker.Option;
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.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.json.GsonJsonSerializer;
import io.datarouter.httpclient.json.HttpClientGsonTool;
import io.datarouter.httpclient.json.JsonSerializer;
import io.datarouter.httpclient.security.CsrfGenerator;
import io.datarouter.httpclient.security.SignatureGenerator;

public class DatarouterHttpClientBuilder{

	public static final Duration DEFAULT_TIMEOUT = Duration.ofSeconds(3);

	private static final JsonSerializer DEFAULT_SERIALIZER = new GsonJsonSerializer(HttpClientGsonTool.GSON);
	private static final StackWalker STACK_WALKER = StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE);

	private int timeoutMs; // must be int due to RequestConfig.set*Timeout() methods
	private int maxTotalConnections;
	private int maxConnectionsPerRoute;
	private Optional validateAfterInactivityMs;
	private HttpClientBuilder httpClientBuilder;
	private Supplier retryCount;
	private JsonSerializer jsonSerializer;
	private CloseableHttpClient customHttpClient;
	private SignatureGenerator signatureGenerator;
	private CsrfGenerator csrfGenerator;
	private Supplier apiKeySupplier;
	private DatarouterHttpClientConfig config;
	private boolean ignoreSsl;
	private SSLContext customSslContext;
	private String name;
	private Supplier enableBreakers;

	public DatarouterHttpClientBuilder(){
		this.timeoutMs = (int)DEFAULT_TIMEOUT.toMillis();
		this.maxTotalConnections = 100;
		this.maxConnectionsPerRoute = 100;
		this.validateAfterInactivityMs = Optional.empty();
		this.httpClientBuilder = HttpClientBuilder.create()
				.setRedirectStrategy(LaxRedirectStrategy.INSTANCE);
		this.retryCount = () -> HttpRetryTool.DEFAULT_RETRY_COUNT;
		this.name = STACK_WALKER.getCallerClass().getSimpleName();
	}

	public DatarouterHttpClient build(){
		httpClientBuilder.setRetryHandler(new DatarouterHttpRetryHandler(retryCount));
		httpClientBuilder.setServiceUnavailableRetryStrategy(new DatarouterServiceUnavailableRetryStrategy(retryCount));
		RequestConfig defaultRequestConfig = RequestConfig.custom()
				.setCookieSpec(CookieSpecs.STANDARD)
				.setConnectTimeout(timeoutMs)
				.setConnectionRequestTimeout(timeoutMs)
				.setSocketTimeout(timeoutMs)
				.build();
		httpClientBuilder.setDefaultRequestConfig(defaultRequestConfig);
		httpClientBuilder.setKeepAliveStrategy(new DatarouterConnectionKeepAliveStrategy(Duration.ofMinutes(5)));
		PoolingHttpClientConnectionManager connectionManager;
		if(ignoreSsl || customSslContext != null){
			SSLConnectionSocketFactory sslsf;
			if(ignoreSsl){
				try{
					SSLContextBuilder builder = new SSLContextBuilder();
					builder.loadTrustMaterial(null, (chain, authType) -> true);
					sslsf = new SSLConnectionSocketFactory(builder.build(), NoopHostnameVerifier.INSTANCE);
				}catch(KeyManagementException | KeyStoreException | NoSuchAlgorithmException e){
					throw new RuntimeException(e);
				}
			}else{
				sslsf = new SSLConnectionSocketFactory(
						customSslContext,
						SSLConnectionSocketFactory.getDefaultHostnameVerifier());
			}
			Registry socketFactoryRegistry = RegistryBuilder.create()
					.register("http", PlainConnectionSocketFactory.getSocketFactory())
					.register("https", sslsf)
					.build();
			connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
		}else{
			connectionManager = new PoolingHttpClientConnectionManager();
		}
		connectionManager.setMaxTotal(maxTotalConnections);
		connectionManager.setDefaultMaxPerRoute(maxConnectionsPerRoute);
		if(validateAfterInactivityMs.isPresent()){
			connectionManager.setValidateAfterInactivity(validateAfterInactivityMs.get());
		}
		httpClientBuilder.setConnectionManager(connectionManager);
		CloseableHttpClient builtHttpClient;
		if(customHttpClient == null){
			builtHttpClient = httpClientBuilder.build();
		}else{
			builtHttpClient = customHttpClient;
		}
		if(config == null){
			config = new DatarouterHttpClientDefaultConfig();
		}
		if(jsonSerializer == null){
			jsonSerializer = DEFAULT_SERIALIZER;
		}
		if(enableBreakers == null){
			enableBreakers = () -> false;
		}
		return new StandardDatarouterHttpClient(
				builtHttpClient,
				this.jsonSerializer,
				this.signatureGenerator,
				this.csrfGenerator,
				this.apiKeySupplier,
				this.config,
				connectionManager,
				name,
				enableBreakers);
	}

	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 setJsonSerializer(JsonSerializer jsonSerializer){
		this.jsonSerializer = jsonSerializer;
		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 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;
	}

	public DatarouterHttpClientBuilder setTimeout(Duration timeout){
		this.timeoutMs = (int)timeout.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 setValidateAfterInactivityMs(int validateAfterInactivityMs){
		this.validateAfterInactivityMs = Optional.of(validateAfterInactivityMs);
		return this;
	}

	public DatarouterHttpClientBuilder setEnableBreakers(Supplier enableBreakers){
		this.enableBreakers = enableBreakers;
		return this;
	}

	public DatarouterHttpClientBuilder forDatarouterHttpClientSettings(SimpleDatarouterHttpClientSettings settings){
		return this
				.setTimeout(settings.getTimeout())
				.setRetryCount(settings.getNumRetries())
				.setEnableBreakers(settings.getEnableBreakers());
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy