From 74deeded0e7b13baef65e799f157ba7a6b5d562e Mon Sep 17 00:00:00 2001 From: "J. Koster" Date: Mon, 14 Oct 2024 13:44:44 +0200 Subject: [PATCH] STNG-8 Reuse HttpClient (#191) --- .../booking/party/BookingCarrier.java | 7 +-- .../core/party/ConformanceParty.java | 5 +- .../conformance/core/toolkit/IOToolkit.java | 13 +++++ .../sandbox/ConformanceSandbox.java | 50 +++++++++---------- 4 files changed, 44 insertions(+), 31 deletions(-) create mode 100644 core/src/main/java/org/dcsa/conformance/core/toolkit/IOToolkit.java diff --git a/booking/src/main/java/org/dcsa/conformance/standards/booking/party/BookingCarrier.java b/booking/src/main/java/org/dcsa/conformance/standards/booking/party/BookingCarrier.java index 105ac18b..bffe7205 100644 --- a/booking/src/main/java/org/dcsa/conformance/standards/booking/party/BookingCarrier.java +++ b/booking/src/main/java/org/dcsa/conformance/standards/booking/party/BookingCarrier.java @@ -1,5 +1,7 @@ package org.dcsa.conformance.standards.booking.party; +import static org.dcsa.conformance.core.toolkit.JsonToolkit.OBJECT_MAPPER; + import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; import java.time.Instant; @@ -22,8 +24,6 @@ import org.dcsa.conformance.standards.booking.checks.ScenarioType; import org.dcsa.conformance.standards.booking.model.PersistableCarrierBooking; -import static org.dcsa.conformance.core.toolkit.JsonToolkit.OBJECT_MAPPER; - @Slf4j public class BookingCarrier extends ConformanceParty { private static final Random RANDOM = new Random(); @@ -91,7 +91,8 @@ protected Map, Consumer> getActionP } private void supplyScenarioParameters(JsonNode actionPrompt) { - log.info("Carrier.supplyScenarioParameters(%s)".formatted(actionPrompt.toPrettyString())); + if (log.isInfoEnabled()) + log.info("Carrier.supplyScenarioParameters({})", actionPrompt.toPrettyString()); var scenarioType = ScenarioType.valueOf(actionPrompt.required("scenarioType").asText()); CarrierScenarioParameters carrierScenarioParameters = switch (scenarioType) { case REGULAR, REGULAR_SHIPPER_OWNED -> new CarrierScenarioParameters("SCR-1234-REGULAR", diff --git a/core/src/main/java/org/dcsa/conformance/core/party/ConformanceParty.java b/core/src/main/java/org/dcsa/conformance/core/party/ConformanceParty.java index a22e6024..f9eeff2b 100644 --- a/core/src/main/java/org/dcsa/conformance/core/party/ConformanceParty.java +++ b/core/src/main/java/org/dcsa/conformance/core/party/ConformanceParty.java @@ -6,7 +6,6 @@ import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import java.net.URI; -import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.time.Duration; @@ -22,6 +21,7 @@ import org.dcsa.conformance.core.scenario.ConformanceAction; import org.dcsa.conformance.core.state.JsonNodeMap; import org.dcsa.conformance.core.state.StatefulEntity; +import org.dcsa.conformance.core.toolkit.IOToolkit; import org.dcsa.conformance.core.toolkit.JsonToolkit; import org.dcsa.conformance.core.traffic.ConformanceMessage; import org.dcsa.conformance.core.traffic.ConformanceMessageBody; @@ -296,12 +296,13 @@ private JsonNode _syncGetPartyPrompt() { partyConfiguration.getOrchestratorUrl() + "/party/%s/prompt/json".formatted(partyConfiguration.getName())); log.info("ConformanceParty.getPartyPrompt() calling: %s".formatted(uri)); + // Allow long debugging sessions or slow business logic at customer's side HttpRequest.Builder httpRequestBuilder = HttpRequest.newBuilder().uri(uri).timeout(Duration.ofHours(1)).GET(); orchestratorAuthHeader.forEach( (name, values) -> values.forEach(value -> httpRequestBuilder.header(name, value))); String stringResponseBody = - HttpClient.newHttpClient() + IOToolkit.HTTP_CLIENT .send(httpRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()) .body(); return new ConformanceMessageBody(stringResponseBody).getJsonBody(); diff --git a/core/src/main/java/org/dcsa/conformance/core/toolkit/IOToolkit.java b/core/src/main/java/org/dcsa/conformance/core/toolkit/IOToolkit.java new file mode 100644 index 00000000..f8105382 --- /dev/null +++ b/core/src/main/java/org/dcsa/conformance/core/toolkit/IOToolkit.java @@ -0,0 +1,13 @@ +package org.dcsa.conformance.core.toolkit; + +import java.net.http.HttpClient; +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = lombok.AccessLevel.PRIVATE) +public class IOToolkit { + + public static final HttpClient HTTP_CLIENT = + HttpClient.newBuilder() + .followRedirects(HttpClient.Redirect.NORMAL) + .build(); +} diff --git a/sandbox/src/main/java/org/dcsa/conformance/sandbox/ConformanceSandbox.java b/sandbox/src/main/java/org/dcsa/conformance/sandbox/ConformanceSandbox.java index 99e8c8fa..7c691cae 100644 --- a/sandbox/src/main/java/org/dcsa/conformance/sandbox/ConformanceSandbox.java +++ b/sandbox/src/main/java/org/dcsa/conformance/sandbox/ConformanceSandbox.java @@ -6,7 +6,6 @@ import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import java.net.URI; -import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.time.Duration; @@ -23,6 +22,7 @@ import org.dcsa.conformance.core.party.CounterpartConfiguration; import org.dcsa.conformance.core.party.PartyWebClient; import org.dcsa.conformance.core.state.JsonNodeMap; +import org.dcsa.conformance.core.toolkit.IOToolkit; import org.dcsa.conformance.core.toolkit.JsonToolkit; import org.dcsa.conformance.core.traffic.*; import org.dcsa.conformance.sandbox.configuration.SandboxConfiguration; @@ -239,14 +239,13 @@ public static ConformanceWebResponse handleRequest( ConformanceWebRequest webRequest, Consumer deferredSandboxTaskConsumer) { log.info( - "ConformanceSandbox.handleRequest() " - + OBJECT_MAPPER.valueToTree(webRequest).toPrettyString()); + "ConformanceSandbox.handleRequest() {}", + OBJECT_MAPPER.valueToTree(webRequest).toPrettyString()); String expectedPrefix = "/conformance/sandbox/"; int expectedPrefixStart = webRequest.url().indexOf(expectedPrefix); if (expectedPrefixStart < 0) { - log.info( - "Rejecting request with missing '%s' in: %s".formatted(expectedPrefix, webRequest.url())); + log.info("Rejecting request with missing '{}' in: {}", expectedPrefix, webRequest.url()); return new ConformanceWebResponse(404, JsonToolkit.JSON_UTF_8, Collections.emptyMap(), "{}"); } String remainingUri = webRequest.url().substring(expectedPrefixStart + expectedPrefix.length()); @@ -594,7 +593,7 @@ private static void _asyncHandleOutboundRequest( .put("handler", "_syncHandleOutboundRequest") .put("sandboxId", sandboxId) .set("conformanceRequest", conformanceRequest.toJson()); - log.debug("Deferring task: " + deferredTask.toPrettyString()); + log.debug("Deferring task: {}", deferredTask.toPrettyString()); deferredSandboxTaskConsumer.accept(deferredTask); } @@ -605,7 +604,7 @@ private static void _asyncSendOutboundWebRequest( .createObjectNode() .put("handler", "_syncSendOutboundWebRequest") .set("conformanceWebRequest", conformanceWebRequest.toJson()); - log.debug("Deferring task: " + deferredTask.toPrettyString()); + log.debug("Deferring task: {}", deferredTask.toPrettyString()); deferredSandboxTaskConsumer.accept(deferredTask); } @@ -614,7 +613,7 @@ public static void executeDeferredTask( Consumer deferredSandboxTaskConsumer, JsonNode jsonNode) { try { - log.debug("ConformanceSandbox.executeDeferredTask(%s)".formatted(jsonNode.toPrettyString())); + log.debug("ConformanceSandbox.executeDeferredTask({})", jsonNode.toPrettyString()); switch (jsonNode.path("handler").asText()) { case "_syncHandleOutboundRequest": _syncHandleOutboundRequest( @@ -628,7 +627,7 @@ public static void executeDeferredTask( ConformanceWebRequest.fromJson((ObjectNode) jsonNode.get("conformanceWebRequest"))); return; default: - log.error("Unsupported deferred task: " + jsonNode.toPrettyString()); + log.error("Unsupported deferred task: {}", jsonNode.toPrettyString()); } } catch (Exception e) { log.error( @@ -642,8 +641,9 @@ public static void executeDeferredTask( private static ConformanceResponse _syncHttpRequest(ConformanceRequest conformanceRequest) { URI uri = conformanceRequest.toURI(); log.info( - "ConformanceSandbox.syncHttpRequest(%s) request: %s" - .formatted(uri, conformanceRequest.toJson().toPrettyString())); + "ConformanceSandbox.syncHttpRequest({}) request: {}", + uri, + conformanceRequest.toJson().toPrettyString()); HttpRequest.Builder httpRequestBuilder = "GET".equals(conformanceRequest.method()) @@ -655,6 +655,7 @@ private static ConformanceResponse _syncHttpRequest(ConformanceRequest conforman HttpRequest.BodyPublishers.ofString( conformanceRequest.message().body().getStringBody())); + // Allow long debugging sessions or slow business logic at customer's side httpRequestBuilder.timeout(Duration.ofHours(1)); conformanceRequest @@ -662,20 +663,17 @@ private static ConformanceResponse _syncHttpRequest(ConformanceRequest conforman .headers() .forEach((name, values) -> values.forEach(value -> httpRequestBuilder.header(name, value))); - HttpResponse httpResponse; - try (HttpClient httpClient = - HttpClient.newBuilder().followRedirects(HttpClient.Redirect.NORMAL).build()) { - httpResponse = - httpClient.send(httpRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()); - } + HttpResponse httpResponse = + IOToolkit.HTTP_CLIENT.send( + httpRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()); ConformanceResponse conformanceResponse = conformanceRequest.createResponse( httpResponse.statusCode(), httpResponse.headers().map(), new ConformanceMessageBody(httpResponse.body())); log.info( - "ConformanceSandbox.syncHttpRequest() response: %s" - .formatted(conformanceResponse.toJson().toPrettyString())); + "ConformanceSandbox.syncHttpRequest() response: {}", + conformanceResponse.toJson().toPrettyString()); return conformanceResponse; } @@ -713,6 +711,7 @@ private static ConformanceResponse _syncHandleOutboundRequest( private static void _syncSendOutboundWebRequest(ConformanceWebRequest conformanceWebRequest) { try { + // Allow long debugging sessions or slow business logic at customer's side HttpRequest.Builder httpRequestBuilder = HttpRequest.newBuilder() .uri(URI.create(conformanceWebRequest.url())) @@ -722,13 +721,11 @@ private static void _syncSendOutboundWebRequest(ConformanceWebRequest conformanc .headers() .forEach( (name, values) -> values.forEach(value -> httpRequestBuilder.header(name, value))); - try (HttpClient httpClient = HttpClient.newHttpClient()) { - httpClient.send(httpRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()); - } + IOToolkit.HTTP_CLIENT.send(httpRequestBuilder.build(), HttpResponse.BodyHandlers.ofString()); } catch (Exception e) { log.error( - "Failed to send outbound request: %s" - .formatted(conformanceWebRequest.toJson().toPrettyString()), + "Failed to send outbound request: {}", + conformanceWebRequest.toJson().toPrettyString(), e); } } @@ -749,8 +746,9 @@ private static ConformanceWebResponse _handleGetPartyPrompt( orchestrator -> partyPromptReference.set(orchestrator.handleGetPartyPrompt(partyName))) .run(); log.info( - "Returning prompt for party %s: %s" - .formatted(partyName, partyPromptReference.get().toPrettyString())); + "Returning prompt for party {}: {}", + partyName, + partyPromptReference.get().toPrettyString()); return new ConformanceWebResponse( 200, JsonToolkit.JSON_UTF_8,