Skip to content

Commit

Permalink
ATtempt to fix connetion pool issues
Browse files Browse the repository at this point in the history
  • Loading branch information
ramari16 committed Nov 1, 2024
1 parent eb358c2 commit 21ee860
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 28 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package edu.harvard.dbmi.avillach.service;

import edu.harvard.dbmi.avillach.data.repository.ResourceRepository;
import edu.harvard.dbmi.avillach.util.HttpClientUtil;
import edu.harvard.dbmi.avillach.util.Utilities;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
Expand All @@ -10,19 +9,28 @@
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContexts;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.net.ssl.SSLContext;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.LinkedList;
import java.util.List;

@ApplicationScoped
public class ProxyWebClient {
Expand All @@ -33,7 +41,39 @@ 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

try {
SSLConnectionSocketFactory.getSocketFactory();
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(null, null, null);
String[] defaultCiphers = sslContext.getServerSocketFactory().getDefaultCipherSuites();

List<String> limited = new LinkedList<String>();
for(String suite : defaultCiphers)
{
//filter out Diffie-Hellman ciphers
if( ! (suite.contains("_DHE_") || suite.contains("_DH_")))
{
limited.add(suite);
}
}

client = 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) {
throw new RuntimeException(e);
}
}

public Response postProxy(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,35 @@
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;
import edu.harvard.dbmi.avillach.util.exception.NotAuthorizedException;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.apache.http.ssl.SSLContexts;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.enterprise.context.ApplicationScoped;
import javax.net.ssl.SSLContext;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;
import java.util.Map;

import static edu.harvard.dbmi.avillach.util.HttpClientUtil.*;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.*;


/**
Expand All @@ -40,8 +50,70 @@ 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";

private HttpClient httpClient;

public ResourceWebClient() { }
public ResourceWebClient() {
PoolingHttpClientConnectionManager connectionManager;

connectionManager = new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(100); // Maximum total connections
connectionManager.setDefaultMaxPerRoute(20); // Maximum connections per route

try {
SSLConnectionSocketFactory.getSocketFactory();
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(null, null, null);
String[] defaultCiphers = sslContext.getServerSocketFactory().getDefaultCipherSuites();

List<String> limited = new LinkedList<String>();
for(String suite : defaultCiphers)
{
//filter out Diffie-Hellman ciphers
if( ! (suite.contains("_DHE_") || suite.contains("_DH_")))
{
limited.add(suite);
}
}

httpClient = 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) {
throw new RuntimeException(e);
}
}

private HttpResponse retrievePostResponse(String uri, Header[] headers, String body) {
try {
logger.debug("HttpClientUtil retrievePostResponse()");

List<Header> headerList = new ArrayList<>();

if (headers != null)
headerList = new ArrayList<>(Arrays.asList(headers));
headerList.add(new BasicHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON));

return HttpClientUtil.simplePost(uri, httpClient, new StringEntity(body), headerList.toArray(new Header[headerList.size()]));
} catch (ApplicationException | UnsupportedEncodingException e) {
throw new ResourceInterfaceException(uri, e);
}
}

public HttpResponse retrieveGetResponse(String uri, Header[] headers) {
try {
logger.debug("HttpClientUtil retrieveGetResponse()");

return HttpClientUtil.simpleGet(httpClient, uri, headers);
} catch (ApplicationException e) {
throw new ResourceInterfaceException(uri, e);
}
}

public ResourceInfo info(String rsURL, QueryRequest queryRequest){
logger.debug("Calling ResourceWebClient info()");
Expand All @@ -58,12 +130,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 = 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);
}
Expand All @@ -87,9 +159,9 @@ public PaginatedSearchResult<?> searchConceptValues(String rsURL, QueryRequest q
HttpResponse resourcesResponse = 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);
}
Expand All @@ -111,12 +183,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 = 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
Expand All @@ -138,12 +210,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 = 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);
Expand All @@ -167,14 +239,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 = 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);
Expand All @@ -198,10 +270,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 = 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){
Expand Down Expand Up @@ -229,10 +301,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 = 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){
Expand All @@ -258,7 +330,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 = 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());
Expand Down Expand Up @@ -301,7 +373,7 @@ public Response querySync(String rsURL, QueryRequest queryRequest, String reques
headers = newHeaders;
}

HttpResponse resourcesResponse = retrievePostResponse(composeURL(rsURL, pathName), headers, body);
HttpResponse resourcesResponse = retrievePostResponse(HttpClientUtil.composeURL(rsURL, pathName), headers, body);
if (resourcesResponse.getStatusLine().getStatusCode() != 200) {
throwError(resourcesResponse, rsURL);
}
Expand Down Expand Up @@ -357,7 +429,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 = retrievePostResponse(HttpClientUtil.composeURL(rsURL, pathName), headers, body);
if (resourcesResponse.getStatusLine().getStatusCode() != 200) {
throwError(resourcesResponse, rsURL);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.apache.http.ssl.SSLContexts;
import org.slf4j.Logger;
Expand Down

0 comments on commit 21ee860

Please sign in to comment.