diff --git a/pic-sure-resources/pic-sure-aggregate-data-sharing-resource/src/main/java/edu/harvard/hms/dbmi/avillach/AggregateDataSharingResourceRS.java b/pic-sure-resources/pic-sure-aggregate-data-sharing-resource/src/main/java/edu/harvard/hms/dbmi/avillach/AggregateDataSharingResourceRS.java index 4b1b88e8..b054055e 100644 --- a/pic-sure-resources/pic-sure-aggregate-data-sharing-resource/src/main/java/edu/harvard/hms/dbmi/avillach/AggregateDataSharingResourceRS.java +++ b/pic-sure-resources/pic-sure-aggregate-data-sharing-resource/src/main/java/edu/harvard/hms/dbmi/avillach/AggregateDataSharingResourceRS.java @@ -18,6 +18,7 @@ import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.message.BasicHeader; import org.apache.http.util.EntityUtils; import org.slf4j.Logger; @@ -35,6 +36,7 @@ import java.util.stream.Stream; import static edu.harvard.dbmi.avillach.service.ResourceWebClient.QUERY_METADATA_FIELD; +import static edu.harvard.dbmi.avillach.util.HttpClientUtil.getConfiguredHttpClient; import static edu.harvard.dbmi.avillach.util.HttpClientUtil.readObjectFromResponse; @Path("/aggregate-data-sharing") @@ -66,6 +68,8 @@ public class AggregateDataSharingResourceRS implements IResourceRS { private final String randomSalt; + private final HttpClientUtil httpClientUtil; + public AggregateDataSharingResourceRS() { this(null); } @@ -89,6 +93,11 @@ public AggregateDataSharingResourceRS(ApplicationProperties applicationPropertie randomSalt = properties.getTargetPicsureObfuscationSalt(); headers = new Header[]{new BasicHeader(HttpHeaders.AUTHORIZATION, BEARER_STRING + properties.getTargetPicsureToken())}; + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(); + connectionManager.setMaxTotal(100); // Maximum total connections + connectionManager.setDefaultMaxPerRoute(20); // Maximum connections per route + httpClientUtil = HttpClientUtil.getInstance(connectionManager); } @@ -120,8 +129,8 @@ public ResourceInfo info(QueryRequest infoRequest) { String payload = objectMapper.writeValueAsString(chainRequest); String composedURL = HttpClientUtil.composeURL(properties.getTargetPicsureUrl(), pathName); - HttpResponse response = HttpClientUtil.retrievePostResponse(composedURL, headers, payload); - if (!HttpClientUtil.is2xx(response)) { + HttpResponse response = httpClientUtil.retrievePostResponse(composedURL, headers, payload); + if (!httpClientUtil.is2xx(response)) { logger.error("{}{} did not return a 200: {} {} ", properties.getTargetPicsureUrl(), pathName, response.getStatusLine().getStatusCode(), response.getStatusLine().getReasonPhrase()); HttpClientUtil.throwResponseError(response, properties.getTargetPicsureUrl()); @@ -194,7 +203,7 @@ private HttpResponse postRequest(QueryRequest statusRequest, String pathName) { QueryRequest chainRequest = createChainRequest(statusRequest); String payload = objectMapper.writeValueAsString(chainRequest); String composedURL = HttpClientUtil.composeURL(properties.getTargetPicsureUrl(), pathName); - HttpResponse response = HttpClientUtil.retrievePostResponse(composedURL, headers, payload); + HttpResponse response = httpClientUtil.retrievePostResponse(composedURL, headers, payload); if (!HttpClientUtil.is2xx(response)) { logger.error("{}{} did not return a 200: {} {} ", properties.getTargetPicsureUrl(), pathName, response.getStatusLine().getStatusCode(), response.getStatusLine().getReasonPhrase()); @@ -267,7 +276,7 @@ private HttpResponse getHttpResponse(QueryRequest queryRequest, UUID resourceUUI String composedURL = HttpClientUtil.composeURL(targetPicsureUrl, pathName); logger.debug("Aggregate Data Sharing Resource, sending query: " + queryString + ", to: " + composedURL); - HttpResponse response = HttpClientUtil.retrievePostResponse(composedURL, headers, queryString); + HttpResponse response = httpClientUtil.retrievePostResponse(composedURL, headers, queryString); if (!HttpClientUtil.is2xx(response)) { logger.error("Not 200 status!"); logger.error( @@ -414,7 +423,7 @@ public Response queryFormat(QueryRequest queryRequest) { try { String queryString = objectMapper.writeValueAsString(queryRequest); String composedURL = HttpClientUtil.composeURL(properties.getTargetPicsureUrl(), pathName); - HttpResponse response = HttpClientUtil.retrievePostResponse(composedURL, headers, queryString); + HttpResponse response = httpClientUtil.retrievePostResponse(composedURL, headers, queryString); if (!HttpClientUtil.is2xx(response)) { logger.error( composedURL + " calling resource with id " + resourceUUID + " did not return a 200: {} {} ", diff --git a/pic-sure-resources/pic-sure-passthrough-resource/src/main/java/edu/harvard/hms/dbmi/avillach/resource/passthru/HttpClient.java b/pic-sure-resources/pic-sure-passthrough-resource/src/main/java/edu/harvard/hms/dbmi/avillach/resource/passthru/HttpClient.java deleted file mode 100644 index f929f91e..00000000 --- a/pic-sure-resources/pic-sure-passthrough-resource/src/main/java/edu/harvard/hms/dbmi/avillach/resource/passthru/HttpClient.java +++ /dev/null @@ -1,63 +0,0 @@ -package edu.harvard.hms.dbmi.avillach.resource.passthru; - -import javax.enterprise.context.ApplicationScoped; - -import org.apache.http.Header; -import org.apache.http.HttpResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import edu.harvard.dbmi.avillach.util.exception.ResourceInterfaceException; - -/** - * Wrapper class for HttpClientUtil in order used to support unit tests and mocking of responses. - * - * @author nixl5s - * - */ -@ApplicationScoped -public class HttpClient { - private static final int RETRY_LIMIT = 5; - - private static final Logger logger = LoggerFactory.getLogger(HttpClient.class); - - public String composeURL(String baseURL, String pathName) { - return edu.harvard.dbmi.avillach.util.HttpClientUtil.composeURL(baseURL, pathName); - } - - public T readObjectFromResponse(HttpResponse response, Class expectedElementType) { - return edu.harvard.dbmi.avillach.util.HttpClientUtil.readObjectFromResponse(response, expectedElementType); - } - -// public HttpResponse retrieveGetResponse(String uri, Header[] headers) { -// return edu.harvard.dbmi.avillach.util.HttpClientUtil.retrieveGetResponse(uri, headers); -// } - - public HttpResponse retrievePostResponse(String uri, Header[] headers, String body) { - - HttpResponse response = null; - for(int i = 1; i <= RETRY_LIMIT && response == null; i++) { - try { - response = edu.harvard.dbmi.avillach.util.HttpClientUtil.retrievePostResponse(uri, headers, body); - break; - } catch (ResourceInterfaceException e) { - if(i < RETRY_LIMIT ) { - logger.warn("Failed to contact remote server. Retrying"); - } else { - logger.error("Failed to contact remote server. Giving up!"); - throw e; - } - } - } - - return response; - } - - public void throwResponseError(HttpResponse response, String baseURL) { - edu.harvard.dbmi.avillach.util.HttpClientUtil.throwResponseError(response, baseURL); - } - - public void throwInternalResponseError(HttpResponse response, String baseURL) { - edu.harvard.dbmi.avillach.util.HttpClientUtil.throwInternalResponseError(response, baseURL); - } -} diff --git a/pic-sure-resources/pic-sure-passthrough-resource/src/main/java/edu/harvard/hms/dbmi/avillach/resource/passthru/PassThroughResourceRS.java b/pic-sure-resources/pic-sure-passthrough-resource/src/main/java/edu/harvard/hms/dbmi/avillach/resource/passthru/PassThroughResourceRS.java index 55727904..82b9595c 100644 --- a/pic-sure-resources/pic-sure-passthrough-resource/src/main/java/edu/harvard/hms/dbmi/avillach/resource/passthru/PassThroughResourceRS.java +++ b/pic-sure-resources/pic-sure-passthrough-resource/src/main/java/edu/harvard/hms/dbmi/avillach/resource/passthru/PassThroughResourceRS.java @@ -5,13 +5,13 @@ import javax.inject.Inject; import javax.ws.rs.*; -import javax.ws.rs.core.Context; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.Response; -import javax.ws.rs.core.SecurityContext; +import edu.harvard.dbmi.avillach.util.HttpClientUtil; import org.apache.http.Header; import org.apache.http.HttpResponse; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.message.BasicHeader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,14 +37,24 @@ public class PassThroughResourceRS implements IResourceRS { @Inject private ApplicationProperties properties; @Inject - private HttpClient httpClient; + private HttpClientUtil httpClient; public PassThroughResourceRS() { } @Inject - public PassThroughResourceRS(ApplicationProperties applicationProperties, HttpClient httpClient) { + public PassThroughResourceRS(ApplicationProperties applicationProperties) { this.properties = applicationProperties; + + PoolingHttpClientConnectionManager connectionManager; + connectionManager = new PoolingHttpClientConnectionManager(); + connectionManager.setMaxTotal(100); // Maximum total connections + connectionManager.setDefaultMaxPerRoute(20); // Maximum connections per route + this.httpClient = HttpClientUtil.getInstance(connectionManager); + } + + public PassThroughResourceRS(ApplicationProperties properties, HttpClientUtil httpClient) { + this.properties = properties; this.httpClient = httpClient; } diff --git a/pic-sure-resources/pic-sure-passthrough-resource/src/test/java/edu/harvard/hms/dbmi/avillach/resource/passthru/PassThroughResourceRSTest.java b/pic-sure-resources/pic-sure-passthrough-resource/src/test/java/edu/harvard/hms/dbmi/avillach/resource/passthru/PassThroughResourceRSTest.java index 3505ce69..ed78a72d 100644 --- a/pic-sure-resources/pic-sure-passthrough-resource/src/test/java/edu/harvard/hms/dbmi/avillach/resource/passthru/PassThroughResourceRSTest.java +++ b/pic-sure-resources/pic-sure-passthrough-resource/src/test/java/edu/harvard/hms/dbmi/avillach/resource/passthru/PassThroughResourceRSTest.java @@ -14,6 +14,7 @@ import java.util.Map; import java.util.UUID; +import edu.harvard.dbmi.avillach.util.HttpClientUtil; import org.apache.commons.io.IOUtils; import org.apache.http.Header; import org.apache.http.HeaderElement; @@ -41,7 +42,7 @@ @ExtendWith(MockitoExtension.class) class PassThroughResourceRSTest { - HttpClient httpClient; + HttpClientUtil httpClient; PassThroughResourceRS resource; ObjectMapper objectMapper = new ObjectMapper(); @@ -52,12 +53,7 @@ void init() { lenient().when(appProperties.getTargetPicsureUrl()).thenReturn("http://test"); lenient().when(appProperties.getTargetResourceId()).thenReturn(UUID.randomUUID().toString()); - httpClient = mock(HttpClient.class); - // not mocking these methods... - lenient().doCallRealMethod().when(httpClient).composeURL(anyString(), anyString()); - lenient().doCallRealMethod().when(httpClient).readObjectFromResponse(any(HttpResponse.class), any()); - lenient().doCallRealMethod().when(httpClient).throwResponseError(any(HttpResponse.class), anyString()); - lenient().doCallRealMethod().when(httpClient).throwInternalResponseError(any(HttpResponse.class), anyString()); + httpClient = mock(HttpClientUtil.class); resource = new PassThroughResourceRS(appProperties, httpClient); } diff --git a/pic-sure-resources/pic-sure-resource-api/src/main/java/edu/harvard/dbmi/avillach/service/ProxyWebClient.java b/pic-sure-resources/pic-sure-resource-api/src/main/java/edu/harvard/dbmi/avillach/service/ProxyWebClient.java index f5025233..17643a3d 100644 --- a/pic-sure-resources/pic-sure-resource-api/src/main/java/edu/harvard/dbmi/avillach/service/ProxyWebClient.java +++ b/pic-sure-resources/pic-sure-resource-api/src/main/java/edu/harvard/dbmi/avillach/service/ProxyWebClient.java @@ -11,6 +11,7 @@ import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.client.utils.URIBuilder; import org.apache.http.entity.StringEntity; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.message.BasicNameValuePair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,7 +34,13 @@ public class ProxyWebClient { ResourceRepository resourceRepository; public ProxyWebClient() { - client = HttpClientUtil.getConfiguredHttpClient(); + PoolingHttpClientConnectionManager connectionManager; + + connectionManager = new PoolingHttpClientConnectionManager(); + connectionManager.setMaxTotal(100); // Maximum total connections + connectionManager.setDefaultMaxPerRoute(20); // Maximum connections per route + + client = HttpClientUtil.getConfiguredHttpClient(connectionManager); } public Response postProxy( diff --git a/pic-sure-resources/pic-sure-resource-api/src/main/java/edu/harvard/dbmi/avillach/service/ResourceWebClient.java b/pic-sure-resources/pic-sure-resource-api/src/main/java/edu/harvard/dbmi/avillach/service/ResourceWebClient.java index 09567c41..09241877 100644 --- a/pic-sure-resources/pic-sure-resource-api/src/main/java/edu/harvard/dbmi/avillach/service/ResourceWebClient.java +++ b/pic-sure-resources/pic-sure-resource-api/src/main/java/edu/harvard/dbmi/avillach/service/ResourceWebClient.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import edu.harvard.dbmi.avillach.domain.*; +import edu.harvard.dbmi.avillach.util.HttpClientUtil; import edu.harvard.dbmi.avillach.util.exception.ApplicationException; import edu.harvard.dbmi.avillach.util.exception.ProtocolException; import edu.harvard.dbmi.avillach.util.exception.ResourceInterfaceException; @@ -11,6 +12,7 @@ import org.apache.http.Header; import org.apache.http.HttpResponse; import org.apache.http.client.utils.URIBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.message.BasicHeader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -22,8 +24,6 @@ import java.net.URISyntaxException; import java.util.Map; -import static edu.harvard.dbmi.avillach.util.HttpClientUtil.*; - /** * The ResourceWebClient class implements the client side logic for the endpoints specified in IResourceRS. @@ -40,8 +40,18 @@ public class ResourceWebClient { public static final String BEARER_STRING = "Bearer "; public static final String BEARER_TOKEN_KEY = "BEARER_TOKEN"; public static final String QUERY_METADATA_FIELD = "queryMetadata"; + + public final HttpClientUtil httpClientUtil; - public ResourceWebClient() { } + public ResourceWebClient() { + PoolingHttpClientConnectionManager connectionManager; + + connectionManager = new PoolingHttpClientConnectionManager(); + connectionManager.setMaxTotal(100); // Maximum total connections + connectionManager.setDefaultMaxPerRoute(20); // Maximum connections per route + + this.httpClientUtil = HttpClientUtil.getInstance(connectionManager); + } public ResourceInfo info(String rsURL, QueryRequest queryRequest){ logger.debug("Calling ResourceWebClient info()"); @@ -58,12 +68,12 @@ public ResourceInfo info(String rsURL, QueryRequest queryRequest){ logger.debug("Calling /info at ResourceURL: {}", rsURL); String pathName = "/info"; String body = json.writeValueAsString(queryRequest); - HttpResponse resourcesResponse = retrievePostResponse(composeURL(rsURL, pathName), createHeaders(queryRequest.getResourceCredentials()), body); + HttpResponse resourcesResponse = httpClientUtil.retrievePostResponse(httpClientUtil.composeURL(rsURL, pathName), createHeaders(queryRequest.getResourceCredentials()), body); if (resourcesResponse.getStatusLine().getStatusCode() != 200) { logger.error("ResourceRS did not return a 200"); - throwResponseError(resourcesResponse, rsURL); + httpClientUtil.throwResponseError(resourcesResponse, rsURL); } - return readObjectFromResponse(resourcesResponse, ResourceInfo.class); + return httpClientUtil.readObjectFromResponse(resourcesResponse, ResourceInfo.class); } catch (JsonProcessingException e){ throw new NotAuthorizedException("Unable to encode resource credentials", e); } @@ -84,12 +94,12 @@ public PaginatedSearchResult searchConceptValues(String rsURL, QueryRequest q uriBuilder.addParameter("size", size.toString()); } Map resourceCredentials = queryRequest != null ? queryRequest.getResourceCredentials() : Map.of(); - HttpResponse resourcesResponse = retrieveGetResponse(uriBuilder.build().toString(), createHeaders(resourceCredentials)); + HttpResponse resourcesResponse = httpClientUtil.retrieveGetResponse(uriBuilder.build().toString(), createHeaders(resourceCredentials)); if (resourcesResponse.getStatusLine().getStatusCode() != 200) { logger.error("ResourceRS did not return a 200"); - throwResponseError(resourcesResponse, rsURL); + httpClientUtil.throwResponseError(resourcesResponse, rsURL); } - return readObjectFromResponse(resourcesResponse, PaginatedSearchResult.class); + return httpClientUtil.readObjectFromResponse(resourcesResponse, PaginatedSearchResult.class); } catch (URISyntaxException e) { throw new ApplicationException("rsURL invalid : " + rsURL, e); } @@ -111,12 +121,12 @@ public SearchResults search(String rsURL, QueryRequest searchQueryRequest){ String pathName = "/search"; String body = json.writeValueAsString(searchQueryRequest); - HttpResponse resourcesResponse = retrievePostResponse(composeURL(rsURL, pathName), createHeaders(searchQueryRequest.getResourceCredentials()), body); + HttpResponse resourcesResponse = httpClientUtil.retrievePostResponse(httpClientUtil.composeURL(rsURL, pathName), createHeaders(searchQueryRequest.getResourceCredentials()), body); if (resourcesResponse.getStatusLine().getStatusCode() != 200) { logger.error("ResourceRS did not return a 200"); - throwResponseError(resourcesResponse, rsURL); + httpClientUtil.throwResponseError(resourcesResponse, rsURL); } - return readObjectFromResponse(resourcesResponse, SearchResults.class); + return httpClientUtil.readObjectFromResponse(resourcesResponse, SearchResults.class); } catch (JsonProcessingException e){ logger.error("Unable to serialize search query"); //TODO Write custom exception @@ -138,12 +148,12 @@ public QueryStatus query(String rsURL, QueryRequest dataQueryRequest){ } String pathName = "/query"; String body = json.writeValueAsString(dataQueryRequest); - HttpResponse resourcesResponse = retrievePostResponse(composeURL(rsURL, pathName), createHeaders(dataQueryRequest.getResourceCredentials()), body); + HttpResponse resourcesResponse = httpClientUtil.retrievePostResponse(httpClientUtil.composeURL(rsURL, pathName), createHeaders(dataQueryRequest.getResourceCredentials()), body); if (resourcesResponse.getStatusLine().getStatusCode() != 200) { logger.error("ResourceRS did not return a 200"); - throwResponseError(resourcesResponse, rsURL); + httpClientUtil.throwResponseError(resourcesResponse, rsURL); } - return readObjectFromResponse(resourcesResponse, QueryStatus.class); + return httpClientUtil.readObjectFromResponse(resourcesResponse, QueryStatus.class); } catch (JsonProcessingException e){ logger.error("Unable to encode data query"); throw new ProtocolException("Unable to encode data query", e); @@ -167,14 +177,14 @@ public QueryStatus queryStatus(String rsURL, String queryId, QueryRequest queryR } String pathName = "/query/" + queryId + "/status"; String body = json.writeValueAsString(queryRequest); - logger.debug(composeURL(rsURL, pathName)); + logger.debug(httpClientUtil.composeURL(rsURL, pathName)); logger.debug(body); - HttpResponse resourcesResponse = retrievePostResponse(composeURL(rsURL, pathName), createHeaders(queryRequest.getResourceCredentials()), body); + HttpResponse resourcesResponse = httpClientUtil.retrievePostResponse(httpClientUtil.composeURL(rsURL, pathName), createHeaders(queryRequest.getResourceCredentials()), body); if (resourcesResponse.getStatusLine().getStatusCode() != 200) { logger.error("ResourceRS did not return a 200"); - throwResponseError(resourcesResponse, rsURL); + httpClientUtil.throwResponseError(resourcesResponse, rsURL); } - return readObjectFromResponse(resourcesResponse, QueryStatus.class); + return httpClientUtil.readObjectFromResponse(resourcesResponse, QueryStatus.class); } catch (JsonProcessingException e){ logger.error("Unable to encode resource credentials"); throw new ProtocolException("Unable to encode resource credentials", e); @@ -198,10 +208,10 @@ public Response queryResult(String rsURL, String queryId, QueryRequest queryRequ } String pathName = "/query/" + queryId + "/result"; String body = json.writeValueAsString(queryRequest); - HttpResponse resourcesResponse = retrievePostResponse(composeURL(rsURL, pathName), createHeaders(queryRequest.getResourceCredentials()), body); + HttpResponse resourcesResponse = httpClientUtil.retrievePostResponse(httpClientUtil.composeURL(rsURL, pathName), createHeaders(queryRequest.getResourceCredentials()), body); if (resourcesResponse.getStatusLine().getStatusCode() != 200) { logger.error("ResourceRS did not return a 200"); - throwResponseError(resourcesResponse, rsURL); + httpClientUtil.throwResponseError(resourcesResponse, rsURL); } return Response.ok(resourcesResponse.getEntity().getContent()).build(); } catch (JsonProcessingException e){ @@ -229,10 +239,10 @@ public Response queryResultSignedUrl(String rsURL, String queryId, QueryRequest } String pathName = "/query/" + queryId + "/signed-url"; String body = json.writeValueAsString(queryRequest); - HttpResponse resourcesResponse = retrievePostResponse(composeURL(rsURL, pathName), createHeaders(queryRequest.getResourceCredentials()), body); + HttpResponse resourcesResponse = httpClientUtil.retrievePostResponse(httpClientUtil.composeURL(rsURL, pathName), createHeaders(queryRequest.getResourceCredentials()), body); if (resourcesResponse.getStatusLine().getStatusCode() != 200) { logger.error("ResourceRS did not return a 200"); - throwResponseError(resourcesResponse, rsURL); + httpClientUtil.throwResponseError(resourcesResponse, rsURL); } return Response.ok(resourcesResponse.getEntity().getContent()).build(); } catch (JsonProcessingException e){ @@ -258,7 +268,7 @@ public Response queryFormat(String rsURL, QueryRequest queryRequest){ } String pathName = "/query/format"; String body = json.writeValueAsString(queryRequest); - HttpResponse resourcesResponse = retrievePostResponse(composeURL(rsURL, pathName), createHeaders(queryRequest.getResourceCredentials()), body); + HttpResponse resourcesResponse = httpClientUtil.retrievePostResponse(httpClientUtil.composeURL(rsURL, pathName), createHeaders(queryRequest.getResourceCredentials()), body); int status = resourcesResponse.getStatusLine().getStatusCode(); if (status != 200) { logger.error("Query format request did not return a 200: " + resourcesResponse.getStatusLine().getStatusCode()); @@ -301,7 +311,7 @@ public Response querySync(String rsURL, QueryRequest queryRequest, String reques headers = newHeaders; } - HttpResponse resourcesResponse = retrievePostResponse(composeURL(rsURL, pathName), headers, body); + HttpResponse resourcesResponse = httpClientUtil.retrievePostResponse(httpClientUtil.composeURL(rsURL, pathName), headers, body); if (resourcesResponse.getStatusLine().getStatusCode() != 200) { throwError(resourcesResponse, rsURL); } @@ -357,7 +367,7 @@ public Response queryContinuous(String rsURL, QueryRequest queryRequest, String } logger.debug("Calling ResourceWebClient queryContinuous() with body: " + body + " and headers: " + queryRequest); - HttpResponse resourcesResponse = retrievePostResponse(composeURL(rsURL, pathName), headers, body); + HttpResponse resourcesResponse = httpClientUtil.retrievePostResponse(httpClientUtil.composeURL(rsURL, pathName), headers, body); if (resourcesResponse.getStatusLine().getStatusCode() != 200) { throwError(resourcesResponse, rsURL); } diff --git a/pic-sure-util/src/main/java/edu/harvard/dbmi/avillach/util/HttpClientUtil.java b/pic-sure-util/src/main/java/edu/harvard/dbmi/avillach/util/HttpClientUtil.java index 79d8c52f..c64dce23 100644 --- a/pic-sure-util/src/main/java/edu/harvard/dbmi/avillach/util/HttpClientUtil.java +++ b/pic-sure-util/src/main/java/edu/harvard/dbmi/avillach/util/HttpClientUtil.java @@ -11,7 +11,6 @@ import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.util.*; -import java.util.concurrent.TimeoutException; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -27,6 +26,7 @@ import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; +import org.apache.http.conn.HttpClientConnectionManager; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.HttpClientBuilder; @@ -48,12 +48,14 @@ public class HttpClientUtil { private static final Logger logger = LoggerFactory.getLogger(HttpClientUtil.class); - public static boolean is2xx(HttpResponse response) { - return response.getStatusLine().getStatusCode() / 100 == 2; + private final HttpClient httpClient; + + public HttpClientUtil(HttpClient httpClient) { + this.httpClient = httpClient; } - public static HttpResponse retrieveGetResponse(String uri, List
headers) { - return retrieveGetResponse(uri, headers.toArray(new Header[headers.size()])); + public static boolean is2xx(HttpResponse response) { + return response.getStatusLine().getStatusCode() / 100 == 2; } /** @@ -63,12 +65,12 @@ public static HttpResponse retrieveGetResponse(String uri, List
headers) * @param headers * @return */ - public static HttpResponse retrieveGetResponse(String uri, Header[] headers) { + public HttpResponse retrieveGetResponse(String uri, Header[] headers) { try { logger.debug("HttpClientUtil retrieveGetResponse()"); - HttpClient client = getConfiguredHttpClient(); - return simpleGet(client, uri, headers); + //HttpClient client = getConfiguredHttpClient(); + return simpleGet(httpClient, uri, headers); } catch (ApplicationException e) { throw new ResourceInterfaceException(uri, e); } @@ -105,7 +107,7 @@ public static String composeURL(String baseURL, String pathName, String query) { * @param headers * @return */ - public static HttpResponse retrievePostResponse(String uri, Header[] headers, String body) { + public HttpResponse retrievePostResponse(String uri, Header[] headers, String body) { try { logger.debug("HttpClientUtil retrievePostResponse()"); @@ -115,18 +117,18 @@ public static HttpResponse retrievePostResponse(String uri, Header[] headers, St headerList = new ArrayList<>(Arrays.asList(headers)); headerList.add(new BasicHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)); - HttpClient client = getConfiguredHttpClient(); - return simplePost(uri, client, new StringEntity(body), headerList.toArray(new Header[headerList.size()])); + //HttpClient client = getConfiguredHttpClient(); + return simplePost(uri, httpClient, new StringEntity(body), headerList.toArray(new Header[headerList.size()])); } catch (ApplicationException | UnsupportedEncodingException e) { throw new ResourceInterfaceException(uri, e); } } - public static HttpResponse retrievePostResponse(String uri, List
headers, String body) { + public HttpResponse retrievePostResponse(String uri, List
headers, String body) { return retrievePostResponse(uri, headers.toArray(new Header[headers.size()]), body); } - public static List readListFromResponse(HttpResponse response, Class expectedElementType) { + public List readListFromResponse(HttpResponse response, Class expectedElementType) { logger.debug("HttpClientUtil readListFromResponse()"); try { String responseBody = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8); @@ -137,7 +139,7 @@ public static List readListFromResponse(HttpResponse response, Class e } } - public static String readObjectFromResponse(HttpResponse response) { + public String readObjectFromResponse(HttpResponse response) { logger.debug("HttpClientUtil readObjectFromResponse(HttpResponse response)"); try { String responseBody = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8); @@ -212,18 +214,15 @@ public static void throwInternalResponseError(HttpResponse response, String base * @return HttpResponse * @throws ApplicationException */ - public static HttpResponse simplePost(String uri, HttpClient client, StringEntity requestBody, Header... headers) + public HttpResponse simplePost(String uri, HttpClient client, StringEntity requestBody, Header... headers) throws ApplicationException { - if (client == null) { - client = getConfiguredHttpClient(); - } HttpPost post = new HttpPost(uri); post.setHeaders(headers); post.setEntity(requestBody); try { - return client.execute(post, buildHttpClientContext()); + return httpClient.execute(post, buildHttpClientContext()); } catch (IOException ex) { logger.error("simplePost() Exception: {}, cannot get response by POST from url: {}", ex.getMessage(), uri); throw new ApplicationException("Inner problem, please contact system admin and check the server log"); @@ -239,7 +238,7 @@ public static HttpResponse simplePost(String uri, HttpClient client, StringEntit * @param headers * @return InputStream */ - public static InputStream simplePost(String uri, StringEntity requestBody, HttpClient client, Header... headers) { + public InputStream simplePost(String uri, StringEntity requestBody, HttpClient client, Header... headers) { HttpResponse response = simplePost(uri, client, requestBody, headers); try { @@ -250,27 +249,6 @@ public static InputStream simplePost(String uri, StringEntity requestBody, HttpC } } - /** - * only works if the POST method returns a JSON response body - * - * @param uri - * @param requestBody - * @param client - * @param objectMapper - * @param headers - * @return - */ - public static JsonNode simplePost(String uri, StringEntity requestBody, HttpClient client, - ObjectMapper objectMapper, Header... headers) { - try { - return objectMapper.readTree(simplePost(uri, requestBody, client, headers)); - } catch (IOException ex) { - logger.error("simplePost() Exception: {}, cannot parse content from by POST from url: {}", ex.getMessage(), - uri); - throw new ApplicationException("Inner problem, please contact system admin and check the server log"); - } - } - /** * for general and basic use of GET function using Apache Http Client * @@ -280,27 +258,23 @@ public static JsonNode simplePost(String uri, StringEntity requestBody, HttpClie * @return * @throws ApplicationException */ - public static HttpResponse simpleGet(HttpClient client, String uri, Header... headers) throws ApplicationException { - if (client == null) { - client = getConfiguredHttpClient(); - } - + public HttpResponse simpleGet(HttpClient client, String uri, Header... headers) throws ApplicationException { HttpGet get = new HttpGet(uri); get.setHeaders(headers); try { - return client.execute(get, buildHttpClientContext()); + return httpClient.execute(get, buildHttpClientContext()); } catch (IOException ex) { logger.error("HttpResponse simpleGet() cannot get response by GET from url: {} - " + ex.getLocalizedMessage(), uri); throw new ApplicationException("Inner problem, please contact system admin and check the server log"); } } - public static InputStream simpleGet(String uri, HttpClient client, Header... headers) { + public InputStream simpleGet(String uri, HttpClient client, Header... headers) { return simpleGetWithConfig(uri, client, null, headers); } - public static InputStream simpleGetWithConfig( + public InputStream simpleGetWithConfig( String uri, HttpClient client, RequestConfig config, Header... headers ) throws ApplicationException { HttpGet get = new HttpGet(uri); @@ -310,7 +284,7 @@ public static InputStream simpleGetWithConfig( } try { - return client.execute(get, buildHttpClientContext()) + return httpClient.execute(get, buildHttpClientContext()) .getEntity() .getContent(); } catch (IOException ex) { @@ -318,37 +292,8 @@ public static InputStream simpleGetWithConfig( throw new ApplicationException("Inner problem, please contact system admin and check the server log"); } } - - /** - * only work if the GET method returns a JSON response body - * - * @param uri - * @param client - * @param objectMapper - * @param headers - * @return - */ - public static JsonNode simpleGet(String uri, HttpClient client, ObjectMapper objectMapper, Header... headers) { - try { - return objectMapper.readTree(simpleGet(uri, client, headers)); - } catch (IOException ex) { - logger.error("simpleGet() cannot parse content from by GET from url: {}", uri, ex); - throw new ApplicationException("Inner problem, please contact system admin and check the server log"); - } - } - - public static JsonNode simpleGetWithConfig( - String uri, HttpClient client, ObjectMapper objectMapper, RequestConfig requestConfig, Header... headers - ) { - try { - return objectMapper.readTree(simpleGetWithConfig(uri, client, requestConfig, headers)); - } catch (IOException ex) { - logger.error("simpleGet() cannot parse content from by GET from url: {}", uri, ex); - throw new ApplicationException("Inner problem, please contact system admin and check the server log"); - } - } - public static HttpClient getConfiguredHttpClient() { + public static HttpClient getConfiguredHttpClient(HttpClientConnectionManager connectionManager) { try { SSLConnectionSocketFactory.getSocketFactory(); SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); @@ -364,13 +309,14 @@ public static HttpClient getConfiguredHttpClient() { limited.add(suite); } } - + return HttpClients.custom() .setSSLSocketFactory(new SSLConnectionSocketFactory( SSLContexts.createSystemDefault(), new String[]{"TLSv1.2"}, limited.toArray(new String[limited.size()]), SSLConnectionSocketFactory.getDefaultHostnameVerifier())) + .setConnectionManager(connectionManager) .build(); } catch( NoSuchAlgorithmException | KeyManagementException e) { logger.warn("Unable to establish SSL context. using default client", e); @@ -379,4 +325,8 @@ public static HttpClient getConfiguredHttpClient() { //default return HttpClientBuilder.create().useSystemProperties().build(); } + + public static HttpClientUtil getInstance(HttpClientConnectionManager connectionManager) { + return new HttpClientUtil(getConfiguredHttpClient(connectionManager)); + } }