Skip to content

Commit 6ab4000

Browse files
author
mizantrop2397
authored
Merge pull request #268 from art-community/feature/http-client-extension
add validateAfterInactivityMillis
2 parents bb80519 + f96f0ff commit 6ab4000

File tree

9 files changed

+174
-69
lines changed

9 files changed

+174
-69
lines changed

application-config-extensions/src/main/java/ru/art/config/extensions/http/HttpClientAgileConfiguration.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ public class HttpClientAgileConfiguration extends HttpClientModuleDefaultConfigu
6262
private MimeToContentTypeMapper producesMimeTypeMapper;
6363
private int maxConnectionsPerRoute;
6464
private int maxConnectionsTotal;
65+
private int validateAfterInactivityMillis;
6566

6667
public HttpClientAgileConfiguration() {
6768
refresh();
@@ -96,8 +97,7 @@ public void refresh() {
9697
.requestConfig(RequestConfig.custom()
9798
.setConnectTimeout(getOrElse(config.getInt(CONNECTION_TIMEOUT), super.getRequestConfig().getConnectTimeout()))
9899
.setSocketTimeout(getOrElse(config.getInt(SOCKET_TIMEOUT), super.getRequestConfig().getSocketTimeout()))
99-
.setConnectionRequestTimeout(getOrElse(config.getInt(CONNECTION_REQUEST_TIMEOUT),
100-
super.getRequestConfig().getConnectionRequestTimeout()))
100+
.setConnectionRequestTimeout(getOrElse(config.getInt(CONNECTION_REQUEST_TIMEOUT), super.getRequestConfig().getConnectionRequestTimeout()))
101101
.build())
102102
.build(), super.getCommunicationTargets());
103103
int socketTimeout = configInt(HTTP_COMMUNICATION_SECTION_ID, SOCKET_TIMEOUT, RequestConfig.DEFAULT.getSocketTimeout());
@@ -123,5 +123,6 @@ public void refresh() {
123123
sslKeyStorePassword = configString(HTTP_COMMUNICATION_SECTION_ID, SSL_KEY_STORE_PASSWORD, super.getSslKeyStorePassword());
124124
maxConnectionsPerRoute = configInt(HTTP_COMMUNICATION_SECTION_ID, MAX_CONNECTIONS_PER_ROUTE, super.getMaxConnectionsPerRoute());
125125
maxConnectionsTotal = configInt(HTTP_COMMUNICATION_SECTION_ID, MAX_CONNECTIONS_TOTAL, super.getMaxConnectionsTotal());
126+
validateAfterInactivityMillis = configInt(HTTP_COMMUNICATION_SECTION_ID, VALIDATE_AFTER_INACTIVITY_MILLIS, super.getValidateAfterInactivityMillis());
126127
}
127128
}

application-config-extensions/src/main/java/ru/art/config/extensions/http/HttpConfigKeys.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public interface HttpConfigKeys {
2626
String MIN_SPARE_THREADS_COUNT = "minSpareThreadsCount";
2727
String CONNECTION_TIMEOUT = "connectionTimeout";
2828
String SO_TIMEOUT = "soTimeout";
29+
String VALIDATE_AFTER_INACTIVITY_MILLIS = "validateAfterInactivityMillis";
2930
String CONNECTION_REQUEST_TIMEOUT = "connectionRequestTimeout";
3031
String SOCKET_TIMEOUT = "socketTimeout";
3132
String SCHEME = "scheme";

application-http-client/src/main/java/ru/art/http/client/configuration/HttpClientModuleConfiguration.java

Lines changed: 75 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,20 @@
2020

2121
import lombok.*;
2222
import org.apache.http.*;
23-
import org.apache.http.client.*;
2423
import org.apache.http.client.config.*;
2524
import org.apache.http.config.*;
25+
import org.apache.http.conn.socket.*;
26+
import org.apache.http.conn.ssl.*;
27+
import org.apache.http.conn.util.*;
2628
import org.apache.http.impl.client.*;
29+
import org.apache.http.impl.conn.*;
2730
import org.apache.http.impl.nio.client.*;
31+
import org.apache.http.impl.nio.conn.*;
2832
import org.apache.http.impl.nio.reactor.*;
33+
import org.apache.http.nio.conn.*;
34+
import org.apache.http.nio.conn.ssl.*;
35+
import org.apache.http.ssl.SSLContexts;
2936
import org.zalando.logbook.httpclient.*;
30-
import ru.art.http.client.constants.*;
3137
import ru.art.http.client.exception.*;
3238
import ru.art.http.client.interceptor.*;
3339
import ru.art.http.client.model.*;
@@ -58,6 +64,8 @@ public interface HttpClientModuleConfiguration extends HttpModuleConfiguration {
5864

5965
int getMaxConnectionsTotal();
6066

67+
int getValidateAfterInactivityMillis();
68+
6169
CloseableHttpClient getClient();
6270

6371
CloseableHttpAsyncClient getAsynchronousClient();
@@ -103,8 +111,10 @@ default HttpCommunicationTargetConfiguration getCommunicationTargetConfiguration
103111

104112
@Getter
105113
class HttpClientModuleDefaultConfiguration extends HttpModuleDefaultConfiguration implements HttpClientModuleConfiguration {
114+
private static HostnameVerifier ALLOW_ALL = (hostName, session) -> true;
106115
int maxConnectionsPerRoute = DEFAULT_MAX_CONNECTIONS_PER_ROUTE;
107116
int maxConnectionsTotal = DEFAULT_MAX_CONNECTIONS_TOTAL;
117+
int validateAfterInactivityMillis = DEFAULT_VALIDATE_AFTER_INACTIVITY_MILLIS;
108118
private final RequestConfig requestConfig = RequestConfig.DEFAULT;
109119
private final SocketConfig socketConfig = SocketConfig.DEFAULT;
110120
private final ConnectionConfig connectionConfig = ConnectionConfig.DEFAULT;
@@ -132,25 +142,8 @@ class HttpClientModuleDefaultConfiguration extends HttpModuleDefaultConfiguratio
132142
@SuppressWarnings({"Duplicates", "WeakerAccess"})
133143
protected CloseableHttpAsyncClient createAsyncHttpClient() {
134144
HttpAsyncClientBuilder clientBuilder = HttpAsyncClients.custom()
135-
.setMaxConnPerRoute(getMaxConnectionsPerRoute())
136-
.setMaxConnTotal(getMaxConnectionsTotal())
137-
.setDefaultRequestConfig(getRequestConfig())
138-
.setDefaultIOReactorConfig(getIoReactorConfig())
139-
.setDefaultConnectionConfig(getConnectionConfig());
140-
if (isSsl()) {
141-
try {
142-
if (disableSslHostNameVerification) {
143-
HostnameVerifier allowAll = (hostName, session) -> true;
144-
clientBuilder.setSSLHostnameVerifier(allowAll);
145-
}
146-
clientBuilder.setSSLContext(custom()
147-
.loadKeyMaterial(loadKeyStore(), getSslKeyStorePassword().toCharArray())
148-
.build());
149-
} catch (Throwable throwable) {
150-
throw new HttpClientException(HTTP_SSL_CONFIGURATION_FAILED, throwable);
151-
}
152-
}
153-
clientBuilder.addInterceptorFirst(new LogbookHttpRequestInterceptor(getLogbook()));
145+
.setConnectionManager(createAsyncConnectionManager())
146+
.addInterceptorFirst(new LogbookHttpRequestInterceptor(getLogbook()));
154147
CloseableHttpAsyncClient client = httpClientModuleState().registerClient(clientBuilder.build());
155148
client.start();
156149
return client;
@@ -165,21 +158,74 @@ protected CloseableHttpClient createHttpClient() {
165158
.setDefaultConnectionConfig(getConnectionConfig())
166159
.setDefaultSocketConfig(getSocketConfig())
167160
.addInterceptorFirst(new LogbookHttpRequestInterceptor(getLogbook()))
168-
.addInterceptorLast(new LogbookHttpResponseInterceptor());
161+
.addInterceptorLast(new LogbookHttpResponseInterceptor())
162+
.setConnectionManager(createConnectionManager());
163+
return httpClientModuleState().registerClient(clientBuilder.build());
164+
}
165+
166+
private PoolingHttpClientConnectionManager createConnectionManager() {
167+
HostnameVerifier hostnameVerifier = new DefaultHostnameVerifier(PublicSuffixMatcherLoader.getDefault());
168+
SSLContext sslContext = null;
169169
if (isSsl()) {
170170
try {
171-
if (disableSslHostNameVerification) {
172-
HostnameVerifier allowAll = (hostName, session) -> true;
173-
clientBuilder.setSSLHostnameVerifier(allowAll);
171+
sslContext = custom().loadKeyMaterial(loadKeyStore(), getSslKeyStorePassword().toCharArray()).build();
172+
if (isDisableSslHostNameVerification()) {
173+
hostnameVerifier = ALLOW_ALL;
174174
}
175-
clientBuilder.setSSLContext(custom()
176-
.loadKeyMaterial(loadKeyStore(), getSslKeyStorePassword().toCharArray())
177-
.build());
178175
} catch (Throwable throwable) {
179176
throw new HttpClientException(HTTP_SSL_CONFIGURATION_FAILED, throwable);
180177
}
181178
}
182-
return httpClientModuleState().registerClient(clientBuilder.build());
179+
180+
SSLConnectionSocketFactory sslSocketFactory = isNull(sslContext)
181+
? new SSLConnectionSocketFactory(org.apache.http.ssl.SSLContexts.createDefault(), hostnameVerifier)
182+
: new SSLConnectionSocketFactory(sslContext, null, null, hostnameVerifier);
183+
184+
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
185+
.register(HTTP_SCHEME, PlainConnectionSocketFactory.getSocketFactory())
186+
.register(HTTPS_SCHEME, sslSocketFactory)
187+
.build();
188+
PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager(registry);
189+
manager.setDefaultSocketConfig(getSocketConfig());
190+
manager.setDefaultConnectionConfig(getConnectionConfig());
191+
manager.setMaxTotal(getMaxConnectionsTotal());
192+
manager.setDefaultMaxPerRoute(getMaxConnectionsPerRoute());
193+
manager.setValidateAfterInactivity(getValidateAfterInactivityMillis());
194+
return manager;
195+
}
196+
197+
private PoolingNHttpClientConnectionManager createAsyncConnectionManager() {
198+
HostnameVerifier hostnameVerifier = new DefaultHostnameVerifier(PublicSuffixMatcherLoader.getDefault());
199+
SSLContext sslContext = null;
200+
if (isSsl()) {
201+
try {
202+
sslContext = custom().loadKeyMaterial(loadKeyStore(), getSslKeyStorePassword().toCharArray()).build();
203+
if (isDisableSslHostNameVerification()) {
204+
hostnameVerifier = ALLOW_ALL;
205+
}
206+
} catch (Throwable throwable) {
207+
throw new HttpClientException(HTTP_SSL_CONFIGURATION_FAILED, throwable);
208+
}
209+
}
210+
211+
SSLIOSessionStrategy sslSessionStrategy = isNull(sslContext)
212+
? new SSLIOSessionStrategy(SSLContexts.createDefault(), hostnameVerifier)
213+
: new SSLIOSessionStrategy(sslContext, null, null, hostnameVerifier);
214+
215+
Registry<SchemeIOSessionStrategy> registry = RegistryBuilder.<SchemeIOSessionStrategy>create()
216+
.register(HTTP_SCHEME, NoopIOSessionStrategy.INSTANCE)
217+
.register(HTTPS_SCHEME, sslSessionStrategy)
218+
.build();
219+
PoolingNHttpClientConnectionManager manager = null;
220+
try {
221+
manager = new PoolingNHttpClientConnectionManager(new DefaultConnectingIOReactor(getIoReactorConfig()), registry);
222+
} catch (Throwable throwable) {
223+
throw new HttpClientException(HTTP_ASYNC_CONFIGURATION_FAILED, throwable);
224+
}
225+
manager.setDefaultConnectionConfig(getConnectionConfig());
226+
manager.setMaxTotal(getMaxConnectionsTotal());
227+
manager.setDefaultMaxPerRoute(getMaxConnectionsPerRoute());
228+
return manager;
183229
}
184230

185231
private KeyStore loadKeyStore() {

application-http-client/src/main/java/ru/art/http/client/constants/HttpClientExceptionMessages.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,6 @@ public interface HttpClientExceptionMessages {
2525
String RESPONSE_INTERCEPTION_IS_NULL = "Response interception is null";
2626
String REQUEST_BODY_READING_EXCEPTION = "Request request reading exception";
2727
String HTTP_SSL_CONFIGURATION_FAILED = "Failed to configure SSL http client. Please check SSL settings";
28+
String HTTP_ASYNC_CONFIGURATION_FAILED = "Failed to configure async http client. Please check IOReactor settings";
2829
String HTTP_COMMUNICATION_TARGET_NOT_FOUND = "Http communication target for service ''{0}'' was not found";
2930
}

application-http-client/src/main/java/ru/art/http/client/constants/HttpClientModuleConstants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ public interface HttpClientModuleConstants {
2727
int RESPONSE_BUFFER_DEFAULT_SIZE = 4096;
2828
int DEFAULT_MAX_CONNECTIONS_PER_ROUTE = 2;
2929
int DEFAULT_MAX_CONNECTIONS_TOTAL = 20;
30+
int DEFAULT_VALIDATE_AFTER_INACTIVITY_MILLIS = 4000;
3031

3132
enum ConnectionClosingPolicy {
3233
CLOSE_AFTER_RESPONSE,

application-http-client/src/main/java/ru/art/http/client/factory/HttpClientsFactory.java

Lines changed: 73 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,18 @@
1919
package ru.art.http.client.factory;
2020

2121
import lombok.experimental.*;
22+
import org.apache.http.config.*;
23+
import org.apache.http.conn.socket.*;
24+
import org.apache.http.conn.ssl.*;
25+
import org.apache.http.conn.util.*;
2226
import org.apache.http.impl.client.*;
27+
import org.apache.http.impl.conn.*;
2328
import org.apache.http.impl.nio.client.*;
29+
import org.apache.http.impl.nio.conn.*;
30+
import org.apache.http.impl.nio.reactor.*;
31+
import org.apache.http.nio.conn.*;
32+
import org.apache.http.nio.conn.ssl.*;
33+
import org.apache.http.ssl.SSLContexts;
2434
import org.zalando.logbook.httpclient.*;
2535
import ru.art.http.client.configuration.*;
2636
import ru.art.http.client.exception.*;
@@ -30,35 +40,20 @@
3040
import static org.apache.http.ssl.SSLContexts.*;
3141
import static ru.art.http.client.constants.HttpClientExceptionMessages.*;
3242
import static ru.art.http.client.module.HttpClientModule.*;
43+
import static ru.art.http.constants.HttpCommonConstants.*;
3344
import static ru.art.logging.LoggingModule.*;
3445
import javax.net.ssl.*;
3546
import java.io.*;
3647
import java.security.*;
3748

3849
@UtilityClass
3950
public class HttpClientsFactory {
51+
private static HostnameVerifier ALLOW_ALL = (hostName, session) -> true;
52+
4053
@SuppressWarnings("Duplicates")
4154
public static CloseableHttpAsyncClient createAsyncHttpClient(HttpClientConfiguration configuration) {
4255
HttpAsyncClientBuilder clientBuilder = HttpAsyncClients.custom()
43-
.setMaxConnPerRoute(configuration.getMaxConnectionsPerRoute())
44-
.setMaxConnTotal(configuration.getMaxConnectionsTotal())
45-
.setDefaultRequestConfig(configuration.getRequestConfig())
46-
.setDefaultIOReactorConfig(configuration.getIoReactorConfig())
47-
.setDefaultConnectionConfig(configuration.getConnectionConfig());
48-
if (configuration.isSsl()) {
49-
try {
50-
if (configuration.isDisableSslHostNameVerification()) {
51-
HostnameVerifier allowAll = (hostName, session) -> true;
52-
clientBuilder.setSSLHostnameVerifier(allowAll);
53-
}
54-
clientBuilder.setSSLContext(custom()
55-
.loadKeyMaterial(loadKeyStore(configuration), configuration.getSslKeyStorePassword().toCharArray())
56-
.build());
57-
} catch (Throwable throwable) {
58-
throw new HttpClientException(HTTP_SSL_CONFIGURATION_FAILED, throwable);
59-
}
60-
}
61-
clientBuilder
56+
.setConnectionManager(createAsyncConnectionManager(configuration))
6257
.addInterceptorFirst(new LogbookHttpRequestInterceptor(httpClientModule().getLogbook()))
6358
.addInterceptorLast(new LogbookHttpResponseInterceptor());
6459
CloseableHttpAsyncClient client = httpClientModuleState().registerClient(clientBuilder.build());
@@ -69,27 +64,75 @@ public static CloseableHttpAsyncClient createAsyncHttpClient(HttpClientConfigura
6964
@SuppressWarnings("Duplicates")
7065
public static CloseableHttpClient createHttpClient(HttpClientConfiguration configuration) {
7166
HttpClientBuilder clientBuilder = HttpClients.custom()
72-
.setMaxConnPerRoute(configuration.getMaxConnectionsPerRoute())
73-
.setMaxConnTotal(configuration.getMaxConnectionsTotal())
74-
.setDefaultRequestConfig(configuration.getRequestConfig())
75-
.setDefaultConnectionConfig(configuration.getConnectionConfig())
76-
.setDefaultSocketConfig(configuration.getSocketConfig())
67+
.setConnectionManager(createConnectionManager(configuration))
7768
.addInterceptorFirst(new LogbookHttpRequestInterceptor(httpClientModule().getLogbook()))
7869
.addInterceptorLast(new LogbookHttpResponseInterceptor());
70+
return httpClientModuleState().registerClient(clientBuilder.build());
71+
}
72+
73+
private static PoolingHttpClientConnectionManager createConnectionManager(HttpClientConfiguration configuration) {
74+
HostnameVerifier hostnameVerifier = new DefaultHostnameVerifier(PublicSuffixMatcherLoader.getDefault());
75+
SSLContext sslContext = null;
7976
if (configuration.isSsl()) {
8077
try {
78+
sslContext = custom().loadKeyMaterial(loadKeyStore(configuration), configuration.getSslKeyStorePassword().toCharArray()).build();
8179
if (configuration.isDisableSslHostNameVerification()) {
82-
HostnameVerifier allowAll = (hostName, session) -> true;
83-
clientBuilder.setSSLHostnameVerifier(allowAll);
80+
hostnameVerifier = ALLOW_ALL;
8481
}
85-
clientBuilder.setSSLContext(custom()
86-
.loadKeyMaterial(loadKeyStore(configuration), configuration.getSslKeyStorePassword().toCharArray())
87-
.build());
8882
} catch (Throwable throwable) {
8983
throw new HttpClientException(HTTP_SSL_CONFIGURATION_FAILED, throwable);
9084
}
9185
}
92-
return httpClientModuleState().registerClient(clientBuilder.build());
86+
87+
SSLConnectionSocketFactory sslSocketFactory = isNull(sslContext)
88+
? new SSLConnectionSocketFactory(SSLContexts.createDefault(), hostnameVerifier)
89+
: new SSLConnectionSocketFactory(sslContext, null, null, hostnameVerifier);
90+
91+
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
92+
.register(HTTP_SCHEME, PlainConnectionSocketFactory.getSocketFactory())
93+
.register(HTTPS_SCHEME, sslSocketFactory)
94+
.build();
95+
PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager(registry);
96+
manager.setDefaultSocketConfig(configuration.getSocketConfig());
97+
manager.setDefaultConnectionConfig(configuration.getConnectionConfig());
98+
manager.setMaxTotal(configuration.getMaxConnectionsTotal());
99+
manager.setDefaultMaxPerRoute(configuration.getMaxConnectionsPerRoute());
100+
manager.setValidateAfterInactivity(configuration.getValidateAfterInactivityMillis());
101+
return manager;
102+
}
103+
104+
private static PoolingNHttpClientConnectionManager createAsyncConnectionManager(HttpClientConfiguration configuration) {
105+
HostnameVerifier hostnameVerifier = new DefaultHostnameVerifier(PublicSuffixMatcherLoader.getDefault());
106+
SSLContext sslContext = null;
107+
if (configuration.isSsl()) {
108+
try {
109+
sslContext = custom().loadKeyMaterial(loadKeyStore(configuration), configuration.getSslKeyStorePassword().toCharArray()).build();
110+
if (configuration.isDisableSslHostNameVerification()) {
111+
hostnameVerifier = ALLOW_ALL;
112+
}
113+
} catch (Throwable throwable) {
114+
throw new HttpClientException(HTTP_SSL_CONFIGURATION_FAILED, throwable);
115+
}
116+
}
117+
118+
SSLIOSessionStrategy sslSessionStrategy = isNull(sslContext)
119+
? new SSLIOSessionStrategy(SSLContexts.createDefault(), hostnameVerifier)
120+
: new SSLIOSessionStrategy(sslContext, null, null, hostnameVerifier);
121+
122+
Registry<SchemeIOSessionStrategy> registry = RegistryBuilder.<SchemeIOSessionStrategy>create()
123+
.register(HTTP_SCHEME, NoopIOSessionStrategy.INSTANCE)
124+
.register(HTTPS_SCHEME, sslSessionStrategy)
125+
.build();
126+
PoolingNHttpClientConnectionManager manager = null;
127+
try {
128+
manager = new PoolingNHttpClientConnectionManager(new DefaultConnectingIOReactor(configuration.getIoReactorConfig()), registry);
129+
} catch (Throwable throwable) {
130+
throw new HttpClientException(HTTP_ASYNC_CONFIGURATION_FAILED, throwable);
131+
}
132+
manager.setDefaultConnectionConfig(configuration.getConnectionConfig());
133+
manager.setMaxTotal(configuration.getMaxConnectionsTotal());
134+
manager.setDefaultMaxPerRoute(configuration.getMaxConnectionsPerRoute());
135+
return manager;
93136
}
94137

95138
private static KeyStore loadKeyStore(HttpClientConfiguration configuration) {

application-http-client/src/main/java/ru/art/http/client/model/HttpClientConfiguration.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,6 @@ public class HttpClientConfiguration {
5151
private final int maxConnectionsPerRoute = httpClientModule().getMaxConnectionsPerRoute();
5252
@Builder.Default
5353
private final int maxConnectionsTotal = httpClientModule().getMaxConnectionsTotal();
54+
@Builder.Default
55+
private final int validateAfterInactivityMillis = httpClientModule().getValidateAfterInactivityMillis();
5456
}

0 commit comments

Comments
 (0)