This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch fix/CAMEL-24274 in repository https://gitbox.apache.org/repos/asf/camel.git
commit 6074326a7cdaf05e7a44625a772f36936a999256 Author: Claus Ibsen <[email protected]> AuthorDate: Mon Jul 27 16:14:56 2026 +0200 CAMEL-24274: camel-tui - Send Message uses HTTP for platform-http routes Co-Authored-By: Claude Opus 4.6 <[email protected]> Signed-off-by: Claus Ibsen <[email protected]> --- .../dsl/jbang/core/commands/tui/ActionsPopup.java | 2 +- .../jbang/core/commands/tui/SendMessagePopup.java | 136 ++++++++++++++++++++- 2 files changed, 135 insertions(+), 3 deletions(-) diff --git a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ActionsPopup.java b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ActionsPopup.java index c5aff66eb649..0319f66cafed 100644 --- a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ActionsPopup.java +++ b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ActionsPopup.java @@ -1180,7 +1180,7 @@ class ActionsPopup { setNotification("No routes available", true); return; } - sendMessagePopup.open(ctx, pid, info.name, info.routes, preSelectedRouteId, info.directory); + sendMessagePopup.open(ctx, pid, info.name, info.routes, preSelectedRouteId, info.directory, info.httpServer); preSelectedRouteId = null; } diff --git a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SendMessagePopup.java b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SendMessagePopup.java index 3125e4c6cc7e..56ae976f99d9 100644 --- a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SendMessagePopup.java +++ b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SendMessagePopup.java @@ -17,9 +17,17 @@ package org.apache.camel.dsl.jbang.core.commands.tui; import java.io.File; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Duration; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ExecutorService; @@ -67,6 +75,7 @@ class SendMessagePopup { private boolean sending; private String pid; private String integrationName; + private String httpServer; private List<RouteInfo> routes; private int selectedRouteIndex; private final TextAreaState bodyState = new TextAreaState(""); @@ -104,17 +113,18 @@ class SendMessagePopup { } void open(MonitorContext ctx, String pid, String name, List<RouteInfo> routes, String preSelectRouteId) { - open(ctx, pid, name, routes, preSelectRouteId, null); + open(ctx, pid, name, routes, preSelectRouteId, null, null); } void open( MonitorContext ctx, String pid, String name, List<RouteInfo> routes, - String preSelectRouteId, String sourceDirectory) { + String preSelectRouteId, String sourceDirectory, String httpServer) { if (pid == null || routes == null || routes.isEmpty()) { return; } this.pid = pid; this.integrationName = name; + this.httpServer = httpServer; this.routes = new ArrayList<>(routes); this.selectedRouteIndex = findSmartDefault(preSelectRouteId); this.bodyState.clear(); @@ -507,6 +517,18 @@ class SendMessagePopup { List<FormHelper.HeaderEntry> hdrs = headers != null ? new ArrayList<>(headers) : null; String routeId = route.routeId; + // platform-http routes are consumer-only so we send an HTTP request directly + if (route.from != null && route.from.startsWith("platform-http:") && httpServer != null) { + executor.execute(() -> { + try { + doSendHttp(route, sendBody, hdrs, captureInOut, routeId); + } finally { + sending = false; + } + }); + return; + } + executor.execute(() -> { try { JsonObject root = new JsonObject(); @@ -627,6 +649,116 @@ class SendMessagePopup { }); } + private void doSendHttp( + RouteInfo route, String body, List<FormHelper.HeaderEntry> hdrs, + boolean captureInOut, String routeId) { + try { + String path = extractPlatformHttpPath(route.from); + String baseUrl = httpServer.replace("0.0.0.0", "localhost"); + String url = baseUrl + path; + String method = extractHttpMethod(route.from, body); + + // read file content if body references a file + String sendBody = body; + if (sendBody != null && sendBody.startsWith("file:")) { + sendBody = Files.readString(Path.of(sendBody.substring(5))); + } + + HttpClient client = HttpClient.newBuilder() + .connectTimeout(Duration.ofSeconds(10)) + .build(); + + boolean hasBody = sendBody != null && !sendBody.isEmpty(); + HttpRequest.BodyPublisher bodyPublisher = hasBody + ? HttpRequest.BodyPublishers.ofString(sendBody) + : HttpRequest.BodyPublishers.noBody(); + + HttpRequest.Builder reqBuilder = HttpRequest.newBuilder() + .uri(URI.create(url)) + .timeout(Duration.ofSeconds(20)) + .method(method, bodyPublisher); + + if (hdrs != null) { + for (FormHelper.HeaderEntry he : hdrs) { + String k = he.keyInput().text().trim(); + String v = he.valueInput().text(); + if (!k.isEmpty()) { + reqBuilder.header(k, v); + } + } + } + + long start = System.currentTimeMillis(); + HttpResponse<String> response = client.send(reqBuilder.build(), + HttpResponse.BodyHandlers.ofString()); + long elapsed = System.currentTimeMillis() - start; + + int httpStatus = response.statusCode(); + boolean error = httpStatus >= 400; + + List<String> hdrLines = new ArrayList<>(); + hdrLines.add("HTTP " + method + " " + url); + hdrLines.add("status: " + httpStatus); + + if (captureInOut) { + for (Map.Entry<String, List<String>> entry : response.headers().map().entrySet()) { + String k = entry.getKey(); + if (k == null || k.startsWith(":")) { + continue; + } + for (String v : entry.getValue()) { + hdrLines.add(k + ": " + v); + } + } + } + + String rawBody = captureInOut ? response.body() : null; + + applyResult(routeId, body, hdrs, captureInOut, + String.valueOf(httpStatus), elapsed, null, hdrLines, rawBody, + error, error ? "HTTP " + httpStatus : null); + } catch (Exception e) { + applyResult(routeId, body, hdrs, captureInOut, + null, 0, null, null, null, + true, "Error: " + e.getMessage()); + } + } + + private static String extractPlatformHttpPath(String fromUri) { + // platform-http:///path?opts or platform-http:/path?opts + String path = fromUri.substring("platform-http:".length()); + // strip query parameters + int q = path.indexOf('?'); + if (q >= 0) { + path = path.substring(0, q); + } + // strip leading slashes from scheme separator (platform-http:///path -> /path) + while (path.startsWith("//")) { + path = path.substring(1); + } + if (!path.startsWith("/")) { + path = "/" + path; + } + return path; + } + + private static String extractHttpMethod(String fromUri, String body) { + int q = fromUri.indexOf('?'); + if (q >= 0) { + String query = fromUri.substring(q + 1); + for (String param : query.split("&")) { + if (param.startsWith("httpMethodRestrict=")) { + String methods = param.substring("httpMethodRestrict=".length()); + // take the first method if comma-separated + int comma = methods.indexOf(','); + return comma > 0 ? methods.substring(0, comma).trim() : methods.trim(); + } + } + } + // default: POST if body is present, GET otherwise + return (body != null && !body.isEmpty()) ? "POST" : "GET"; + } + private void applyResult( String routeId, String body, List<FormHelper.HeaderEntry> hdrs, boolean wasInOut, String status, long elapsed, String exchangeId,
