diff --git a/doc/src/asciidoc/module_http_client.adoc b/doc/src/asciidoc/module_http_client.adoc index 03b33095c5..ade4278b91 100644 --- a/doc/src/asciidoc/module_http_client.adoc +++ b/doc/src/asciidoc/module_http_client.adoc @@ -36,6 +36,9 @@ The `HttpQuery` participant has the following configuration properties: * `preemptiveAuth`: if doing Basic Authentication (by presence of context value), do it on the first request (default `false`) * `responseBodyOnError`: should an HTTP response body be included for responses with error status code? (`boolean`, default `false`); +* `maxConnections`: set the maximum number of concurrent client connections; if unset it will default to **25** concurrent connetions.+ + **NOTE:** This value is overridable by the `http.maxConnections` Java system property, and it applies globally to the whole process. + In addition, `HttpQuery` picks a few _configurable_ entries from the `Context`: @@ -52,8 +55,8 @@ In addition, `HttpQuery` picks a few _configurable_ entries from the `Context`: ** a `String[]` where each item follows the `header_name:header_value` syntax ** a `List` where each item follows the `header_name:header_value` syntax ** a `Map` where the keys represent _header names_, and the values the corresponding _header values_ -* `.HTTP_BASIC_AUTHENTICATION`: A String of the form `:` used for HTTP Basic Authentication. - NOTE: The default `Context` name starts with a period (`.`), meaning it will be hidden in the logs during a context dump. +* `.HTTP_BASIC_AUTHENTICATION`: A String of the form `:` used for HTTP Basic Authentication. + + **NOTE:** The default `Context` name starts with a period (`.`), meaning it will be hidden in the logs during a context dump. After successful completion (which may include normal HTTP errors such as `404` or `500`), `HttpQuery` stores the result back into the `Context`: diff --git a/modules/http-client/src/main/java/org/jpos/http/client/HttpQuery.java b/modules/http-client/src/main/java/org/jpos/http/client/HttpQuery.java index e9ece53843..31594e133f 100644 --- a/modules/http-client/src/main/java/org/jpos/http/client/HttpQuery.java +++ b/modules/http-client/src/main/java/org/jpos/http/client/HttpQuery.java @@ -77,6 +77,8 @@ @SuppressWarnings("unused") public class HttpQuery extends Log implements AbortParticipant, Configurable, Destroyable { + private static final String DEFAULT_MAX_CONNECTIONS = "25"; // overridable by sys prop http.maxConnections, or with cfg "maxConnections" + private static final int DEFAULT_CONNECT_TIMEOUT = 10000; private static final int DEFAULT_TIMEOUT = 15000; @@ -261,9 +263,27 @@ else if ("lax".equals(redirProp)) redirectStrategy= LaxRedirectStrategy.INSTANCE; else throw new ConfigurationException("'redirect-strategy' must be 'lax' or 'default'"); + + + String maxConn = System.getProperty("http.maxConnections"); + if (maxConn == null || maxConn.trim().isEmpty()) { + String maxConnCfg = cfg.get("maxConnections", DEFAULT_MAX_CONNECTIONS); + maxConn = maxConnCfg.trim(); + System.setProperty("http.maxConnections", maxConn); + } + try { Integer.parseInt(maxConn); } + catch (Exception e) { + throw new ConfigurationException("Bad value for maxConnections: "+maxConn); + } } - public CloseableHttpAsyncClient getHttpClient(boolean trustAllCerts) { + + /** + Method is synchronized against this instance of HttpQuery, because the instance of + the CloseableHttpAsyncClient is *lazily* created upon first request, and only one + should be created and shared by all threads. + */ + public synchronized CloseableHttpAsyncClient getHttpClient(boolean trustAllCerts) { if (trustAllCerts) { if (unsecureHttpClient == null) { setUnsecureHttpClient(getClientBuilder(true).build()); @@ -291,6 +311,7 @@ protected HttpAsyncClientBuilder getClientBuilder(boolean trustAllCerts) { if (trustAllCerts) { disableSSLVerification(builder); } + return builder; }