Skip to content

Commit 4533f52

Browse files
authored
Merge pull request #2 from SourceLabOrg/sp/httpClient5
Refactor to use HttpComponents/HttpClient 5.0.x
2 parents f72ae9f + 6d47b3a commit 4533f52

File tree

7 files changed

+116
-91
lines changed

7 files changed

+116
-91
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,8 @@
22
The format is based on [Keep a Changelog](http://keepachangelog.com/)
33
and this project adheres to [Semantic Versioning](http://semver.org/).
44

5+
## 0.2.0 (01/19/2021)
6+
- Upgrade internal dependency of HttpClient from 4.5.x to 5.0.3.
7+
58
## 0.1.0 (01/18/2021)
69
- Initial release!

pom.xml

+4-4
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>org.sourcelab</groupId>
88
<artifactId>java-hkp-client</artifactId>
9-
<version>0.1.1-SNAPSHOT</version>
9+
<version>0.2.0</version>
1010

1111
<!-- Require Maven 3.3.9 -->
1212
<prerequisites>
@@ -48,7 +48,7 @@
4848
<maven.compiler.target>8</maven.compiler.target>
4949

5050
<!-- Http Components version -->
51-
<http-components.version>4.5.13</http-components.version>
51+
<http-components.version>5.0.3</http-components.version>
5252

5353
<!-- Specify which Checkstyle ruleset to use -->
5454
<checkstyle.ruleset>build/checkstyle.xml</checkstyle.ruleset>
@@ -75,8 +75,8 @@
7575
<dependencies>
7676
<!-- Http Client -->
7777
<dependency>
78-
<groupId>org.apache.httpcomponents</groupId>
79-
<artifactId>httpclient</artifactId>
78+
<groupId>org.apache.httpcomponents.client5</groupId>
79+
<artifactId>httpclient5</artifactId>
8080
<version>${http-components.version}</version>
8181
</dependency>
8282

src/main/java/org/sourcelab/hkp/HkpClient.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@
2626
import org.sourcelab.hkp.request.GetRequest;
2727
import org.sourcelab.hkp.request.Request;
2828
import org.sourcelab.hkp.request.SearchRequest;
29+
import org.sourcelab.hkp.response.ErrorResponse;
30+
import org.sourcelab.hkp.response.Result;
2931
import org.sourcelab.hkp.response.get.PgpPublicKey;
3032
import org.sourcelab.hkp.response.search.SearchIndexResponse;
31-
import org.sourcelab.hkp.rest.HttpClientRestClient;
33+
import org.sourcelab.hkp.rest.HttpClient5RestClient;
3234
import org.sourcelab.hkp.rest.RestClient;
3335
import org.sourcelab.hkp.rest.RestResponse;
34-
import org.sourcelab.hkp.response.ErrorResponse;
35-
import org.sourcelab.hkp.response.Result;
3636

3737
import java.io.IOException;
3838
import java.util.Objects;
@@ -66,7 +66,7 @@ public class HkpClient implements AutoCloseable {
6666
public HkpClient(final ConfigurationBuilder configurationBuilder) {
6767
this(
6868
configurationBuilder,
69-
new HttpClientRestClient()
69+
new HttpClient5RestClient()
7070
);
7171
}
7272

src/main/java/org/sourcelab/hkp/rest/HttpClientRestClient.java renamed to src/main/java/org/sourcelab/hkp/rest/HttpClient5RestClient.java

+58-59
Original file line numberDiff line numberDiff line change
@@ -17,30 +17,32 @@
1717

1818
package org.sourcelab.hkp.rest;
1919

20-
import org.apache.http.HttpHost;
21-
import org.apache.http.NameValuePair;
22-
import org.apache.http.auth.AuthScope;
23-
import org.apache.http.auth.UsernamePasswordCredentials;
24-
import org.apache.http.client.AuthCache;
25-
import org.apache.http.client.ClientProtocolException;
26-
import org.apache.http.client.CredentialsProvider;
27-
import org.apache.http.client.ResponseHandler;
28-
import org.apache.http.client.config.RequestConfig;
29-
import org.apache.http.client.entity.UrlEncodedFormEntity;
30-
import org.apache.http.client.methods.HttpGet;
31-
import org.apache.http.client.methods.HttpPost;
32-
import org.apache.http.client.protocol.HttpClientContext;
33-
import org.apache.http.client.utils.URIBuilder;
34-
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
35-
import org.apache.http.conn.ssl.NoopHostnameVerifier;
36-
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
37-
import org.apache.http.impl.auth.BasicScheme;
38-
import org.apache.http.impl.client.BasicAuthCache;
39-
import org.apache.http.impl.client.BasicCredentialsProvider;
40-
import org.apache.http.impl.client.CloseableHttpClient;
41-
import org.apache.http.impl.client.HttpClientBuilder;
42-
import org.apache.http.message.BasicNameValuePair;
43-
import org.apache.http.ssl.SSLContexts;
20+
import org.apache.hc.client5.http.ClientProtocolException;
21+
import org.apache.hc.client5.http.auth.AuthCache;
22+
import org.apache.hc.client5.http.auth.AuthScope;
23+
import org.apache.hc.client5.http.auth.CredentialsStore;
24+
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
25+
import org.apache.hc.client5.http.classic.methods.HttpGet;
26+
import org.apache.hc.client5.http.config.RequestConfig;
27+
import org.apache.hc.client5.http.impl.auth.BasicAuthCache;
28+
import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
29+
import org.apache.hc.client5.http.impl.auth.BasicScheme;
30+
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
31+
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
32+
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
33+
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
34+
import org.apache.hc.client5.http.protocol.HttpClientContext;
35+
import org.apache.hc.client5.http.ssl.DefaultHostnameVerifier;
36+
import org.apache.hc.client5.http.ssl.NoopHostnameVerifier;
37+
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
38+
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactoryBuilder;
39+
import org.apache.hc.core5.http.ClassicHttpRequest;
40+
import org.apache.hc.core5.http.HttpHost;
41+
import org.apache.hc.core5.http.io.HttpClientResponseHandler;
42+
import org.apache.hc.core5.http.ssl.TLS;
43+
import org.apache.hc.core5.net.URIBuilder;
44+
import org.apache.hc.core5.ssl.SSLContexts;
45+
import org.apache.hc.core5.util.Timeout;
4446
import org.slf4j.Logger;
4547
import org.slf4j.LoggerFactory;
4648
import org.sourcelab.hkp.ConnectionFailedException;
@@ -55,7 +57,6 @@
5557
import javax.net.ssl.TrustManager;
5658
import javax.net.ssl.TrustManagerFactory;
5759
import java.io.IOException;
58-
import java.net.ConnectException;
5960
import java.net.SocketException;
6061
import java.net.URISyntaxException;
6162
import java.nio.charset.StandardCharsets;
@@ -64,17 +65,13 @@
6465
import java.security.KeyStoreException;
6566
import java.security.NoSuchAlgorithmException;
6667
import java.security.SecureRandom;
67-
import java.util.ArrayList;
68-
import java.util.HashMap;
69-
import java.util.List;
7068
import java.util.Map;
71-
import java.util.concurrent.TimeUnit;
7269

7370
/**
7471
* RestClient implementation using HTTPClient.
7572
*/
76-
public class HttpClientRestClient implements RestClient {
77-
private static final Logger logger = LoggerFactory.getLogger(HttpClientRestClient.class);
73+
public class HttpClient5RestClient implements RestClient {
74+
private static final Logger logger = LoggerFactory.getLogger(HttpClient5RestClient.class);
7875

7976
/**
8077
* Save a copy of the configuration.
@@ -90,7 +87,7 @@ public class HttpClientRestClient implements RestClient {
9087
/**
9188
* Constructor.
9289
*/
93-
public HttpClientRestClient() {
90+
public HttpClient5RestClient() {
9491
}
9592

9693
/**
@@ -123,23 +120,22 @@ public void init(final Configuration configuration) {
123120
hostnameVerifier = NoopHostnameVerifier.INSTANCE;
124121
} else {
125122
// Use default implementation
126-
hostnameVerifier = SSLConnectionSocketFactory.getDefaultHostnameVerifier();
123+
hostnameVerifier = new DefaultHostnameVerifier();
127124
}
128125

129126
// Allow TLSv1_1 and TLSv1_2 protocols
130-
final LayeredConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
131-
sslcontext,
132-
new String[] { "TLSv1.1", "TLSv1.2" },
133-
null,
134-
hostnameVerifier
135-
);
127+
final SSLConnectionSocketFactory sslsf = SSLConnectionSocketFactoryBuilder.create()
128+
.setSslContext(sslcontext)
129+
.setTlsVersions(TLS.V_1_1, TLS.V_1_2)
130+
.setHostnameVerifier(hostnameVerifier)
131+
.build();
132+
final HttpClientConnectionManager cm = PoolingHttpClientConnectionManagerBuilder.create()
133+
.setSSLSocketFactory(sslsf)
134+
.build();
136135

137136
// Setup client builder
138-
final HttpClientBuilder clientBuilder = HttpClientBuilder.create();
139-
clientBuilder
140-
// Disconnect requests after 120 seconds.
141-
.setConnectionTimeToLive(configuration.getRequestTimeoutSecs(), TimeUnit.SECONDS)
142-
.setSSLSocketFactory(sslsf);
137+
final HttpClientBuilder clientBuilder = HttpClientBuilder.create()
138+
.setConnectionManager(cm);
143139

144140
// Define our RequestConfigBuilder
145141
final RequestConfig.Builder requestConfigBuilder = RequestConfig.custom();
@@ -154,32 +150,32 @@ public void init(final Configuration configuration) {
154150
if (configuration.hasProxyConfigured()) {
155151
// Define proxy host
156152
final HttpHost proxyHost = new HttpHost(
153+
configuration.getProxyConfiguration().getScheme(),
157154
configuration.getProxyConfiguration().getHost(),
158-
configuration.getProxyConfiguration().getPort(),
159-
configuration.getProxyConfiguration().getScheme()
155+
configuration.getProxyConfiguration().getPort()
160156
);
161157

162158
// If we have proxy auth enabled
163159
if (configuration.getProxyConfiguration().isAuthenticationRequired()) {
164160
// Create credential provider
165-
final CredentialsProvider credsProvider = new BasicCredentialsProvider();
161+
final CredentialsStore credsProvider = new BasicCredentialsProvider();
166162
credsProvider.setCredentials(
167163
new AuthScope(
168164
configuration.getProxyConfiguration().getHost(),
169165
configuration.getProxyConfiguration().getPort()
170166
),
171167
new UsernamePasswordCredentials(
172168
configuration.getProxyConfiguration().getUsername(),
173-
configuration.getProxyConfiguration().getPassword()
169+
configuration.getProxyConfiguration().getPassword().toCharArray()
174170
)
175171
);
176172

177173
// Preemptive load context with authentication.
178174
authCache.put(
179175
new HttpHost(
176+
configuration.getProxyConfiguration().getScheme(),
180177
configuration.getProxyConfiguration().getHost(),
181-
configuration.getProxyConfiguration().getPort(),
182-
configuration.getProxyConfiguration().getScheme()
178+
configuration.getProxyConfiguration().getPort()
183179
),
184180
new BasicScheme()
185181
);
@@ -190,7 +186,10 @@ public void init(final Configuration configuration) {
190186
}
191187

192188
// Attach Proxy to request config builder
193-
requestConfigBuilder.setProxy(proxyHost);
189+
requestConfigBuilder
190+
.setConnectionRequestTimeout(Timeout.ofSeconds(configuration.getRequestTimeoutSecs()))
191+
.setConnectTimeout(Timeout.ofSeconds(configuration.getRequestTimeoutSecs()))
192+
.setProxy(proxyHost);
194193

195194
// Configure context.
196195
httpClientContext.setAuthCache(authCache);
@@ -233,8 +232,8 @@ public void close() {
233232
if (httpClient != null) {
234233
try {
235234
httpClient.close();
236-
} catch (IOException e) {
237-
logger.error("Error closing: {}", e.getMessage(), e);
235+
} catch (final IOException exception) {
236+
logger.error("Error closing: {}", exception.getMessage(), exception);
238237
}
239238
}
240239
httpClient = null;
@@ -250,7 +249,7 @@ public void close() {
250249
public RestResponse submitRequest(final Request request) throws RestException {
251250
try {
252251
return submitRequest(request, new RestResponseHandler());
253-
} catch (IOException exception) {
252+
} catch (final IOException exception) {
254253
throw new RestException(exception.getMessage(), exception);
255254
}
256255
}
@@ -262,7 +261,7 @@ public RestResponse submitRequest(final Request request) throws RestException {
262261
* @param <T> The return type.
263262
* @return The parsed API response.
264263
*/
265-
private <T> T submitRequest(final Request request, final ResponseHandler<T> responseHandler) throws IOException {
264+
private <T> T submitRequest(final Request request, final HttpClientResponseHandler<T> responseHandler) throws IOException {
266265
final String url = constructApiUrl(request);
267266
return submitRequest(url, request.getRequestParameters(), responseHandler);
268267
}
@@ -276,7 +275,7 @@ private <T> T submitRequest(final Request request, final ResponseHandler<T> resp
276275
* @return Parsed response.
277276
* @throws ConnectionFailedException if remote server does not accept connection.
278277
*/
279-
private <T> T submitRequest(final String url, final Map<String, String> getParams, final ResponseHandler<T> responseHandler) throws IOException {
278+
private <T> T submitRequest(final String url, final Map<String, String> getParams, final HttpClientResponseHandler<T> responseHandler) {
280279
try {
281280
// Construct URI including our request parameters.
282281
final URIBuilder uriBuilder = new URIBuilder(url)
@@ -288,13 +287,13 @@ private <T> T submitRequest(final String url, final Map<String, String> getParam
288287
}
289288

290289
// Build Get Request
291-
final HttpGet get = new HttpGet(uriBuilder.build());
290+
final ClassicHttpRequest get = new HttpGet(uriBuilder.build());
292291

293292
// Debug logging
294-
logger.info("Executing request {}", get.getRequestLine());
293+
logger.info("Executing request {}", get.getRequestUri());
295294

296295
// Execute and return
297-
return httpClient.execute(get, responseHandler, httpClientContext);
296+
return httpClient.execute(get, httpClientContext, responseHandler);
298297
} catch (final ClientProtocolException | SocketException | URISyntaxException | SSLHandshakeException connectionException) {
299298
// Signals that an error occurred while attempting to connect a
300299
// socket to a remote address and port. Typically, the connection

src/main/java/org/sourcelab/hkp/rest/handlers/RestResponseHandler.java

+9-8
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@
1717

1818
package org.sourcelab.hkp.rest.handlers;
1919

20-
import org.apache.http.HttpEntity;
21-
import org.apache.http.HttpResponse;
22-
import org.apache.http.client.ResponseHandler;
23-
import org.apache.http.util.EntityUtils;
20+
import org.apache.hc.core5.http.ClassicHttpResponse;
21+
import org.apache.hc.core5.http.HttpEntity;
22+
import org.apache.hc.core5.http.ParseException;
23+
import org.apache.hc.core5.http.io.HttpClientResponseHandler;
24+
import org.apache.hc.core5.http.io.entity.EntityUtils;
2425
import org.slf4j.Logger;
2526
import org.slf4j.LoggerFactory;
2627
import org.sourcelab.hkp.rest.RestResponse;
@@ -30,12 +31,12 @@
3031
/**
3132
* Handles parsing a response to RestResponse object.
3233
*/
33-
public class RestResponseHandler implements ResponseHandler<RestResponse> {
34+
public class RestResponseHandler implements HttpClientResponseHandler<RestResponse> {
3435
private static final Logger logger = LoggerFactory.getLogger(RestResponseHandler.class);
3536

3637
@Override
37-
public RestResponse handleResponse(final HttpResponse response) {
38-
final int statusCode = response.getStatusLine().getStatusCode();
38+
public RestResponse handleResponse(final ClassicHttpResponse response) {
39+
final int statusCode = response.getCode();
3940

4041
try {
4142
final HttpEntity entity = response.getEntity();
@@ -46,7 +47,7 @@ public RestResponse handleResponse(final HttpResponse response) {
4647

4748
// Construct return object
4849
return new RestResponse(responseStr, statusCode);
49-
} catch (final IOException exception) {
50+
} catch (final IOException | ParseException exception) {
5051
logger.error("Failed to read entity: {}", exception.getMessage(), exception);
5152
throw new RuntimeException("Failed to read entity", exception);
5253
}

src/main/java/org/sourcelab/hkp/rest/handlers/StringResponseHandler.java

+23-13
Original file line numberDiff line numberDiff line change
@@ -17,27 +17,37 @@
1717

1818
package org.sourcelab.hkp.rest.handlers;
1919

20-
import org.apache.http.HttpEntity;
21-
import org.apache.http.HttpResponse;
22-
import org.apache.http.client.ResponseHandler;
23-
import org.apache.http.util.EntityUtils;
20+
import org.apache.hc.core5.http.ClassicHttpResponse;
21+
import org.apache.hc.core5.http.HttpEntity;
22+
import org.apache.hc.core5.http.ParseException;
23+
import org.apache.hc.core5.http.io.HttpClientResponseHandler;
24+
import org.apache.hc.core5.http.io.entity.EntityUtils;
25+
import org.slf4j.Logger;
26+
import org.slf4j.LoggerFactory;
2427

2528
import java.io.IOException;
2629

2730
/**
2831
* Returns response as a string.
2932
*/
30-
public class StringResponseHandler implements ResponseHandler<String> {
31-
@Override
32-
public String handleResponse(final HttpResponse response) throws IOException {
33+
public class StringResponseHandler implements HttpClientResponseHandler<String> {
34+
private static final Logger logger = LoggerFactory.getLogger(StringResponseHandler.class);
3335

34-
final HttpEntity entity = response.getEntity();
35-
final String responseStr = entity != null ? EntityUtils.toString(entity) : null;
36+
@Override
37+
public String handleResponse(final ClassicHttpResponse response) throws IOException {
38+
try {
39+
final HttpEntity entity = response.getEntity();
40+
final String responseStr;
41+
responseStr = entity != null ? EntityUtils.toString(entity) : null;
3642

37-
// Fully consume entity.
38-
EntityUtils.consume(entity);
43+
// Fully consume entity.
44+
EntityUtils.consume(entity);
3945

40-
// Construct return object
41-
return responseStr;
46+
// Construct return object
47+
return responseStr;
48+
} catch (final ParseException exception) {
49+
logger.error("Failed to read entity: {}", exception.getMessage(), exception);
50+
throw new RuntimeException("Failed to read entity", exception);
51+
}
4252
}
4353
}

0 commit comments

Comments
 (0)