Skip to content

Commit

Permalink
Merge pull request #268 from art-community/feature/http-client-extension
Browse files Browse the repository at this point in the history
add validateAfterInactivityMillis
  • Loading branch information
mizantrop2397 authored Apr 6, 2020
2 parents bb80519 + f96f0ff commit 6ab4000
Show file tree
Hide file tree
Showing 9 changed files with 174 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public class HttpClientAgileConfiguration extends HttpClientModuleDefaultConfigu
private MimeToContentTypeMapper producesMimeTypeMapper;
private int maxConnectionsPerRoute;
private int maxConnectionsTotal;
private int validateAfterInactivityMillis;

public HttpClientAgileConfiguration() {
refresh();
Expand Down Expand Up @@ -96,8 +97,7 @@ public void refresh() {
.requestConfig(RequestConfig.custom()
.setConnectTimeout(getOrElse(config.getInt(CONNECTION_TIMEOUT), super.getRequestConfig().getConnectTimeout()))
.setSocketTimeout(getOrElse(config.getInt(SOCKET_TIMEOUT), super.getRequestConfig().getSocketTimeout()))
.setConnectionRequestTimeout(getOrElse(config.getInt(CONNECTION_REQUEST_TIMEOUT),
super.getRequestConfig().getConnectionRequestTimeout()))
.setConnectionRequestTimeout(getOrElse(config.getInt(CONNECTION_REQUEST_TIMEOUT), super.getRequestConfig().getConnectionRequestTimeout()))
.build())
.build(), super.getCommunicationTargets());
int socketTimeout = configInt(HTTP_COMMUNICATION_SECTION_ID, SOCKET_TIMEOUT, RequestConfig.DEFAULT.getSocketTimeout());
Expand All @@ -123,5 +123,6 @@ public void refresh() {
sslKeyStorePassword = configString(HTTP_COMMUNICATION_SECTION_ID, SSL_KEY_STORE_PASSWORD, super.getSslKeyStorePassword());
maxConnectionsPerRoute = configInt(HTTP_COMMUNICATION_SECTION_ID, MAX_CONNECTIONS_PER_ROUTE, super.getMaxConnectionsPerRoute());
maxConnectionsTotal = configInt(HTTP_COMMUNICATION_SECTION_ID, MAX_CONNECTIONS_TOTAL, super.getMaxConnectionsTotal());
validateAfterInactivityMillis = configInt(HTTP_COMMUNICATION_SECTION_ID, VALIDATE_AFTER_INACTIVITY_MILLIS, super.getValidateAfterInactivityMillis());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public interface HttpConfigKeys {
String MIN_SPARE_THREADS_COUNT = "minSpareThreadsCount";
String CONNECTION_TIMEOUT = "connectionTimeout";
String SO_TIMEOUT = "soTimeout";
String VALIDATE_AFTER_INACTIVITY_MILLIS = "validateAfterInactivityMillis";
String CONNECTION_REQUEST_TIMEOUT = "connectionRequestTimeout";
String SOCKET_TIMEOUT = "socketTimeout";
String SCHEME = "scheme";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,20 @@

import lombok.*;
import org.apache.http.*;
import org.apache.http.client.*;
import org.apache.http.client.config.*;
import org.apache.http.config.*;
import org.apache.http.conn.socket.*;
import org.apache.http.conn.ssl.*;
import org.apache.http.conn.util.*;
import org.apache.http.impl.client.*;
import org.apache.http.impl.conn.*;
import org.apache.http.impl.nio.client.*;
import org.apache.http.impl.nio.conn.*;
import org.apache.http.impl.nio.reactor.*;
import org.apache.http.nio.conn.*;
import org.apache.http.nio.conn.ssl.*;
import org.apache.http.ssl.SSLContexts;
import org.zalando.logbook.httpclient.*;
import ru.art.http.client.constants.*;
import ru.art.http.client.exception.*;
import ru.art.http.client.interceptor.*;
import ru.art.http.client.model.*;
Expand Down Expand Up @@ -58,6 +64,8 @@ public interface HttpClientModuleConfiguration extends HttpModuleConfiguration {

int getMaxConnectionsTotal();

int getValidateAfterInactivityMillis();

CloseableHttpClient getClient();

CloseableHttpAsyncClient getAsynchronousClient();
Expand Down Expand Up @@ -103,8 +111,10 @@ default HttpCommunicationTargetConfiguration getCommunicationTargetConfiguration

@Getter
class HttpClientModuleDefaultConfiguration extends HttpModuleDefaultConfiguration implements HttpClientModuleConfiguration {
private static HostnameVerifier ALLOW_ALL = (hostName, session) -> true;
int maxConnectionsPerRoute = DEFAULT_MAX_CONNECTIONS_PER_ROUTE;
int maxConnectionsTotal = DEFAULT_MAX_CONNECTIONS_TOTAL;
int validateAfterInactivityMillis = DEFAULT_VALIDATE_AFTER_INACTIVITY_MILLIS;
private final RequestConfig requestConfig = RequestConfig.DEFAULT;
private final SocketConfig socketConfig = SocketConfig.DEFAULT;
private final ConnectionConfig connectionConfig = ConnectionConfig.DEFAULT;
Expand Down Expand Up @@ -132,25 +142,8 @@ class HttpClientModuleDefaultConfiguration extends HttpModuleDefaultConfiguratio
@SuppressWarnings({"Duplicates", "WeakerAccess"})
protected CloseableHttpAsyncClient createAsyncHttpClient() {
HttpAsyncClientBuilder clientBuilder = HttpAsyncClients.custom()
.setMaxConnPerRoute(getMaxConnectionsPerRoute())
.setMaxConnTotal(getMaxConnectionsTotal())
.setDefaultRequestConfig(getRequestConfig())
.setDefaultIOReactorConfig(getIoReactorConfig())
.setDefaultConnectionConfig(getConnectionConfig());
if (isSsl()) {
try {
if (disableSslHostNameVerification) {
HostnameVerifier allowAll = (hostName, session) -> true;
clientBuilder.setSSLHostnameVerifier(allowAll);
}
clientBuilder.setSSLContext(custom()
.loadKeyMaterial(loadKeyStore(), getSslKeyStorePassword().toCharArray())
.build());
} catch (Throwable throwable) {
throw new HttpClientException(HTTP_SSL_CONFIGURATION_FAILED, throwable);
}
}
clientBuilder.addInterceptorFirst(new LogbookHttpRequestInterceptor(getLogbook()));
.setConnectionManager(createAsyncConnectionManager())
.addInterceptorFirst(new LogbookHttpRequestInterceptor(getLogbook()));
CloseableHttpAsyncClient client = httpClientModuleState().registerClient(clientBuilder.build());
client.start();
return client;
Expand All @@ -165,21 +158,74 @@ protected CloseableHttpClient createHttpClient() {
.setDefaultConnectionConfig(getConnectionConfig())
.setDefaultSocketConfig(getSocketConfig())
.addInterceptorFirst(new LogbookHttpRequestInterceptor(getLogbook()))
.addInterceptorLast(new LogbookHttpResponseInterceptor());
.addInterceptorLast(new LogbookHttpResponseInterceptor())
.setConnectionManager(createConnectionManager());
return httpClientModuleState().registerClient(clientBuilder.build());
}

private PoolingHttpClientConnectionManager createConnectionManager() {
HostnameVerifier hostnameVerifier = new DefaultHostnameVerifier(PublicSuffixMatcherLoader.getDefault());
SSLContext sslContext = null;
if (isSsl()) {
try {
if (disableSslHostNameVerification) {
HostnameVerifier allowAll = (hostName, session) -> true;
clientBuilder.setSSLHostnameVerifier(allowAll);
sslContext = custom().loadKeyMaterial(loadKeyStore(), getSslKeyStorePassword().toCharArray()).build();
if (isDisableSslHostNameVerification()) {
hostnameVerifier = ALLOW_ALL;
}
clientBuilder.setSSLContext(custom()
.loadKeyMaterial(loadKeyStore(), getSslKeyStorePassword().toCharArray())
.build());
} catch (Throwable throwable) {
throw new HttpClientException(HTTP_SSL_CONFIGURATION_FAILED, throwable);
}
}
return httpClientModuleState().registerClient(clientBuilder.build());

SSLConnectionSocketFactory sslSocketFactory = isNull(sslContext)
? new SSLConnectionSocketFactory(org.apache.http.ssl.SSLContexts.createDefault(), hostnameVerifier)
: new SSLConnectionSocketFactory(sslContext, null, null, hostnameVerifier);

Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register(HTTP_SCHEME, PlainConnectionSocketFactory.getSocketFactory())
.register(HTTPS_SCHEME, sslSocketFactory)
.build();
PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager(registry);
manager.setDefaultSocketConfig(getSocketConfig());
manager.setDefaultConnectionConfig(getConnectionConfig());
manager.setMaxTotal(getMaxConnectionsTotal());
manager.setDefaultMaxPerRoute(getMaxConnectionsPerRoute());
manager.setValidateAfterInactivity(getValidateAfterInactivityMillis());
return manager;
}

private PoolingNHttpClientConnectionManager createAsyncConnectionManager() {
HostnameVerifier hostnameVerifier = new DefaultHostnameVerifier(PublicSuffixMatcherLoader.getDefault());
SSLContext sslContext = null;
if (isSsl()) {
try {
sslContext = custom().loadKeyMaterial(loadKeyStore(), getSslKeyStorePassword().toCharArray()).build();
if (isDisableSslHostNameVerification()) {
hostnameVerifier = ALLOW_ALL;
}
} catch (Throwable throwable) {
throw new HttpClientException(HTTP_SSL_CONFIGURATION_FAILED, throwable);
}
}

SSLIOSessionStrategy sslSessionStrategy = isNull(sslContext)
? new SSLIOSessionStrategy(SSLContexts.createDefault(), hostnameVerifier)
: new SSLIOSessionStrategy(sslContext, null, null, hostnameVerifier);

Registry<SchemeIOSessionStrategy> registry = RegistryBuilder.<SchemeIOSessionStrategy>create()
.register(HTTP_SCHEME, NoopIOSessionStrategy.INSTANCE)
.register(HTTPS_SCHEME, sslSessionStrategy)
.build();
PoolingNHttpClientConnectionManager manager = null;
try {
manager = new PoolingNHttpClientConnectionManager(new DefaultConnectingIOReactor(getIoReactorConfig()), registry);
} catch (Throwable throwable) {
throw new HttpClientException(HTTP_ASYNC_CONFIGURATION_FAILED, throwable);
}
manager.setDefaultConnectionConfig(getConnectionConfig());
manager.setMaxTotal(getMaxConnectionsTotal());
manager.setDefaultMaxPerRoute(getMaxConnectionsPerRoute());
return manager;
}

private KeyStore loadKeyStore() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,6 @@ public interface HttpClientExceptionMessages {
String RESPONSE_INTERCEPTION_IS_NULL = "Response interception is null";
String REQUEST_BODY_READING_EXCEPTION = "Request request reading exception";
String HTTP_SSL_CONFIGURATION_FAILED = "Failed to configure SSL http client. Please check SSL settings";
String HTTP_ASYNC_CONFIGURATION_FAILED = "Failed to configure async http client. Please check IOReactor settings";
String HTTP_COMMUNICATION_TARGET_NOT_FOUND = "Http communication target for service ''{0}'' was not found";
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public interface HttpClientModuleConstants {
int RESPONSE_BUFFER_DEFAULT_SIZE = 4096;
int DEFAULT_MAX_CONNECTIONS_PER_ROUTE = 2;
int DEFAULT_MAX_CONNECTIONS_TOTAL = 20;
int DEFAULT_VALIDATE_AFTER_INACTIVITY_MILLIS = 4000;

enum ConnectionClosingPolicy {
CLOSE_AFTER_RESPONSE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,18 @@
package ru.art.http.client.factory;

import lombok.experimental.*;
import org.apache.http.config.*;
import org.apache.http.conn.socket.*;
import org.apache.http.conn.ssl.*;
import org.apache.http.conn.util.*;
import org.apache.http.impl.client.*;
import org.apache.http.impl.conn.*;
import org.apache.http.impl.nio.client.*;
import org.apache.http.impl.nio.conn.*;
import org.apache.http.impl.nio.reactor.*;
import org.apache.http.nio.conn.*;
import org.apache.http.nio.conn.ssl.*;
import org.apache.http.ssl.SSLContexts;
import org.zalando.logbook.httpclient.*;
import ru.art.http.client.configuration.*;
import ru.art.http.client.exception.*;
Expand All @@ -30,35 +40,20 @@
import static org.apache.http.ssl.SSLContexts.*;
import static ru.art.http.client.constants.HttpClientExceptionMessages.*;
import static ru.art.http.client.module.HttpClientModule.*;
import static ru.art.http.constants.HttpCommonConstants.*;
import static ru.art.logging.LoggingModule.*;
import javax.net.ssl.*;
import java.io.*;
import java.security.*;

@UtilityClass
public class HttpClientsFactory {
private static HostnameVerifier ALLOW_ALL = (hostName, session) -> true;

@SuppressWarnings("Duplicates")
public static CloseableHttpAsyncClient createAsyncHttpClient(HttpClientConfiguration configuration) {
HttpAsyncClientBuilder clientBuilder = HttpAsyncClients.custom()
.setMaxConnPerRoute(configuration.getMaxConnectionsPerRoute())
.setMaxConnTotal(configuration.getMaxConnectionsTotal())
.setDefaultRequestConfig(configuration.getRequestConfig())
.setDefaultIOReactorConfig(configuration.getIoReactorConfig())
.setDefaultConnectionConfig(configuration.getConnectionConfig());
if (configuration.isSsl()) {
try {
if (configuration.isDisableSslHostNameVerification()) {
HostnameVerifier allowAll = (hostName, session) -> true;
clientBuilder.setSSLHostnameVerifier(allowAll);
}
clientBuilder.setSSLContext(custom()
.loadKeyMaterial(loadKeyStore(configuration), configuration.getSslKeyStorePassword().toCharArray())
.build());
} catch (Throwable throwable) {
throw new HttpClientException(HTTP_SSL_CONFIGURATION_FAILED, throwable);
}
}
clientBuilder
.setConnectionManager(createAsyncConnectionManager(configuration))
.addInterceptorFirst(new LogbookHttpRequestInterceptor(httpClientModule().getLogbook()))
.addInterceptorLast(new LogbookHttpResponseInterceptor());
CloseableHttpAsyncClient client = httpClientModuleState().registerClient(clientBuilder.build());
Expand All @@ -69,27 +64,75 @@ public static CloseableHttpAsyncClient createAsyncHttpClient(HttpClientConfigura
@SuppressWarnings("Duplicates")
public static CloseableHttpClient createHttpClient(HttpClientConfiguration configuration) {
HttpClientBuilder clientBuilder = HttpClients.custom()
.setMaxConnPerRoute(configuration.getMaxConnectionsPerRoute())
.setMaxConnTotal(configuration.getMaxConnectionsTotal())
.setDefaultRequestConfig(configuration.getRequestConfig())
.setDefaultConnectionConfig(configuration.getConnectionConfig())
.setDefaultSocketConfig(configuration.getSocketConfig())
.setConnectionManager(createConnectionManager(configuration))
.addInterceptorFirst(new LogbookHttpRequestInterceptor(httpClientModule().getLogbook()))
.addInterceptorLast(new LogbookHttpResponseInterceptor());
return httpClientModuleState().registerClient(clientBuilder.build());
}

private static PoolingHttpClientConnectionManager createConnectionManager(HttpClientConfiguration configuration) {
HostnameVerifier hostnameVerifier = new DefaultHostnameVerifier(PublicSuffixMatcherLoader.getDefault());
SSLContext sslContext = null;
if (configuration.isSsl()) {
try {
sslContext = custom().loadKeyMaterial(loadKeyStore(configuration), configuration.getSslKeyStorePassword().toCharArray()).build();
if (configuration.isDisableSslHostNameVerification()) {
HostnameVerifier allowAll = (hostName, session) -> true;
clientBuilder.setSSLHostnameVerifier(allowAll);
hostnameVerifier = ALLOW_ALL;
}
clientBuilder.setSSLContext(custom()
.loadKeyMaterial(loadKeyStore(configuration), configuration.getSslKeyStorePassword().toCharArray())
.build());
} catch (Throwable throwable) {
throw new HttpClientException(HTTP_SSL_CONFIGURATION_FAILED, throwable);
}
}
return httpClientModuleState().registerClient(clientBuilder.build());

SSLConnectionSocketFactory sslSocketFactory = isNull(sslContext)
? new SSLConnectionSocketFactory(SSLContexts.createDefault(), hostnameVerifier)
: new SSLConnectionSocketFactory(sslContext, null, null, hostnameVerifier);

Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register(HTTP_SCHEME, PlainConnectionSocketFactory.getSocketFactory())
.register(HTTPS_SCHEME, sslSocketFactory)
.build();
PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager(registry);
manager.setDefaultSocketConfig(configuration.getSocketConfig());
manager.setDefaultConnectionConfig(configuration.getConnectionConfig());
manager.setMaxTotal(configuration.getMaxConnectionsTotal());
manager.setDefaultMaxPerRoute(configuration.getMaxConnectionsPerRoute());
manager.setValidateAfterInactivity(configuration.getValidateAfterInactivityMillis());
return manager;
}

private static PoolingNHttpClientConnectionManager createAsyncConnectionManager(HttpClientConfiguration configuration) {
HostnameVerifier hostnameVerifier = new DefaultHostnameVerifier(PublicSuffixMatcherLoader.getDefault());
SSLContext sslContext = null;
if (configuration.isSsl()) {
try {
sslContext = custom().loadKeyMaterial(loadKeyStore(configuration), configuration.getSslKeyStorePassword().toCharArray()).build();
if (configuration.isDisableSslHostNameVerification()) {
hostnameVerifier = ALLOW_ALL;
}
} catch (Throwable throwable) {
throw new HttpClientException(HTTP_SSL_CONFIGURATION_FAILED, throwable);
}
}

SSLIOSessionStrategy sslSessionStrategy = isNull(sslContext)
? new SSLIOSessionStrategy(SSLContexts.createDefault(), hostnameVerifier)
: new SSLIOSessionStrategy(sslContext, null, null, hostnameVerifier);

Registry<SchemeIOSessionStrategy> registry = RegistryBuilder.<SchemeIOSessionStrategy>create()
.register(HTTP_SCHEME, NoopIOSessionStrategy.INSTANCE)
.register(HTTPS_SCHEME, sslSessionStrategy)
.build();
PoolingNHttpClientConnectionManager manager = null;
try {
manager = new PoolingNHttpClientConnectionManager(new DefaultConnectingIOReactor(configuration.getIoReactorConfig()), registry);
} catch (Throwable throwable) {
throw new HttpClientException(HTTP_ASYNC_CONFIGURATION_FAILED, throwable);
}
manager.setDefaultConnectionConfig(configuration.getConnectionConfig());
manager.setMaxTotal(configuration.getMaxConnectionsTotal());
manager.setDefaultMaxPerRoute(configuration.getMaxConnectionsPerRoute());
return manager;
}

private static KeyStore loadKeyStore(HttpClientConfiguration configuration) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,6 @@ public class HttpClientConfiguration {
private final int maxConnectionsPerRoute = httpClientModule().getMaxConnectionsPerRoute();
@Builder.Default
private final int maxConnectionsTotal = httpClientModule().getMaxConnectionsTotal();
@Builder.Default
private final int validateAfterInactivityMillis = httpClientModule().getValidateAfterInactivityMillis();
}
Loading

0 comments on commit 6ab4000

Please sign in to comment.