This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new f5b908935d2 CAMEL-21605: camel-jbang - Add send dev console to use 
instead of special logic in cli-connector.
f5b908935d2 is described below

commit f5b908935d29c7947ccbe2da0264abb1b24692ff
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon Jan 13 15:23:03 2025 +0100

    CAMEL-21605: camel-jbang - Add send dev console to use instead of special 
logic in cli-connector.
---
 .../apache/camel/catalog/dev-consoles.properties   |   1 +
 .../apache/camel/catalog/dev-consoles/send.json    |  15 +
 .../impl/console/SendDevConsoleConfigurer.java     |  77 +++++
 .../org/apache/camel/dev-console/send.json         |  15 +
 .../org.apache.camel.impl.console.SendDevConsole   |   2 +
 .../services/org/apache/camel/dev-console/send     |   2 +
 .../org/apache/camel/dev-consoles.properties       |   2 +-
 .../apache/camel/impl/console/SendDevConsole.java  | 338 +++++++++++++++++++++
 .../camel/cli/connector/LocalCliConnector.java     | 182 ++---------
 .../core/commands/action/CamelSendAction.java      |   5 +-
 10 files changed, 483 insertions(+), 156 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/dev-consoles.properties
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/dev-consoles.properties
index a586f018ed8..41c1ba05629 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/dev-consoles.properties
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/dev-consoles.properties
@@ -37,6 +37,7 @@ rest
 route
 route-controller
 route-dump
+send
 service
 source
 startup-recorder
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/dev-consoles/send.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/dev-consoles/send.json
new file mode 100644
index 00000000000..693dfc88e7b
--- /dev/null
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/dev-consoles/send.json
@@ -0,0 +1,15 @@
+{
+  "console": {
+    "kind": "console",
+    "group": "camel",
+    "name": "send",
+    "title": "Camel Send",
+    "description": "Send messages to endpoints",
+    "deprecated": false,
+    "javaType": "org.apache.camel.impl.console.SendDevConsole",
+    "groupId": "org.apache.camel",
+    "artifactId": "camel-console",
+    "version": "4.10.0-SNAPSHOT"
+  }
+}
+
diff --git 
a/core/camel-console/src/generated/java/org/apache/camel/impl/console/SendDevConsoleConfigurer.java
 
b/core/camel-console/src/generated/java/org/apache/camel/impl/console/SendDevConsoleConfigurer.java
new file mode 100644
index 00000000000..5e81863d8dc
--- /dev/null
+++ 
b/core/camel-console/src/generated/java/org/apache/camel/impl/console/SendDevConsoleConfigurer.java
@@ -0,0 +1,77 @@
+/* Generated by camel build tools - do NOT edit this file! */
+package org.apache.camel.impl.console;
+
+import javax.annotation.processing.Generated;
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.spi.ExtendedPropertyConfigurerGetter;
+import org.apache.camel.spi.PropertyConfigurerGetter;
+import org.apache.camel.spi.ConfigurerStrategy;
+import org.apache.camel.spi.GeneratedPropertyConfigurer;
+import org.apache.camel.util.CaseInsensitiveMap;
+import org.apache.camel.impl.console.SendDevConsole;
+
+/**
+ * Generated by camel build tools - do NOT edit this file!
+ */
+@Generated("org.apache.camel.maven.packaging.GenerateConfigurerMojo")
+@SuppressWarnings("unchecked")
+public class SendDevConsoleConfigurer extends 
org.apache.camel.support.component.PropertyConfigurerSupport implements 
GeneratedPropertyConfigurer, ExtendedPropertyConfigurerGetter {
+
+    private static final Map<String, Object> ALL_OPTIONS;
+    static {
+        Map<String, Object> map = new CaseInsensitiveMap();
+        map.put("BodyMaxChars", int.class);
+        map.put("CamelContext", org.apache.camel.CamelContext.class);
+        map.put("PollTimeout", int.class);
+        ALL_OPTIONS = map;
+    }
+
+    @Override
+    public boolean configure(CamelContext camelContext, Object obj, String 
name, Object value, boolean ignoreCase) {
+        org.apache.camel.impl.console.SendDevConsole target = 
(org.apache.camel.impl.console.SendDevConsole) obj;
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "bodymaxchars":
+        case "bodyMaxChars": target.setBodyMaxChars(property(camelContext, 
int.class, value)); return true;
+        case "camelcontext":
+        case "camelContext": target.setCamelContext(property(camelContext, 
org.apache.camel.CamelContext.class, value)); return true;
+        case "polltimeout":
+        case "pollTimeout": target.setPollTimeout(property(camelContext, 
int.class, value)); return true;
+        default: return false;
+        }
+    }
+
+    @Override
+    public Map<String, Object> getAllOptions(Object target) {
+        return ALL_OPTIONS;
+    }
+
+    @Override
+    public Class<?> getOptionType(String name, boolean ignoreCase) {
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "bodymaxchars":
+        case "bodyMaxChars": return int.class;
+        case "camelcontext":
+        case "camelContext": return org.apache.camel.CamelContext.class;
+        case "polltimeout":
+        case "pollTimeout": return int.class;
+        default: return null;
+        }
+    }
+
+    @Override
+    public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
+        org.apache.camel.impl.console.SendDevConsole target = 
(org.apache.camel.impl.console.SendDevConsole) obj;
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "bodymaxchars":
+        case "bodyMaxChars": return target.getBodyMaxChars();
+        case "camelcontext":
+        case "camelContext": return target.getCamelContext();
+        case "polltimeout":
+        case "pollTimeout": return target.getPollTimeout();
+        default: return null;
+        }
+    }
+}
+
diff --git 
a/core/camel-console/src/generated/resources/META-INF/org/apache/camel/dev-console/send.json
 
b/core/camel-console/src/generated/resources/META-INF/org/apache/camel/dev-console/send.json
new file mode 100644
index 00000000000..693dfc88e7b
--- /dev/null
+++ 
b/core/camel-console/src/generated/resources/META-INF/org/apache/camel/dev-console/send.json
@@ -0,0 +1,15 @@
+{
+  "console": {
+    "kind": "console",
+    "group": "camel",
+    "name": "send",
+    "title": "Camel Send",
+    "description": "Send messages to endpoints",
+    "deprecated": false,
+    "javaType": "org.apache.camel.impl.console.SendDevConsole",
+    "groupId": "org.apache.camel",
+    "artifactId": "camel-console",
+    "version": "4.10.0-SNAPSHOT"
+  }
+}
+
diff --git 
a/core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/configurer/org.apache.camel.impl.console.SendDevConsole
 
b/core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/configurer/org.apache.camel.impl.console.SendDevConsole
new file mode 100644
index 00000000000..8d0a66498d2
--- /dev/null
+++ 
b/core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/configurer/org.apache.camel.impl.console.SendDevConsole
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.impl.console.SendDevConsoleConfigurer
diff --git 
a/core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/dev-console/send
 
b/core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/dev-console/send
new file mode 100644
index 00000000000..928b9a90beb
--- /dev/null
+++ 
b/core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/dev-console/send
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.impl.console.SendDevConsole
diff --git 
a/core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/dev-consoles.properties
 
b/core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/dev-consoles.properties
index 1c2b5739f39..a13c0d402a6 100644
--- 
a/core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/dev-consoles.properties
+++ 
b/core/camel-console/src/generated/resources/META-INF/services/org/apache/camel/dev-consoles.properties
@@ -1,5 +1,5 @@
 # Generated by camel build tools - do NOT edit this file!
-dev-consoles=bean blocked browse circuit-breaker consumer context debug 
endpoint event gc health inflight java-security jvm log memory properties 
receive reload rest route route-controller route-dump service source 
startup-recorder thread top trace transformers type-converters variables
+dev-consoles=bean blocked browse circuit-breaker consumer context debug 
endpoint event gc health inflight java-security jvm log memory properties 
receive reload rest route route-controller route-dump send service source 
startup-recorder thread top trace transformers type-converters variables
 groupId=org.apache.camel
 artifactId=camel-console
 version=4.10.0-SNAPSHOT
diff --git 
a/core/camel-console/src/main/java/org/apache/camel/impl/console/SendDevConsole.java
 
b/core/camel-console/src/main/java/org/apache/camel/impl/console/SendDevConsole.java
new file mode 100644
index 00000000000..3ae30b10c8e
--- /dev/null
+++ 
b/core/camel-console/src/main/java/org/apache/camel/impl/console/SendDevConsole.java
@@ -0,0 +1,338 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.impl.console;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.camel.ConsumerTemplate;
+import org.apache.camel.Endpoint;
+import org.apache.camel.Exchange;
+import org.apache.camel.ExchangePattern;
+import org.apache.camel.NoSuchEndpointException;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.Route;
+import org.apache.camel.spi.Configurer;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.annotations.DevConsole;
+import org.apache.camel.support.EndpointHelper;
+import org.apache.camel.support.ExceptionHelper;
+import org.apache.camel.support.MessageHelper;
+import org.apache.camel.support.console.AbstractDevConsole;
+import org.apache.camel.support.service.ServiceHelper;
+import org.apache.camel.util.IOHelper;
+import org.apache.camel.util.StopWatch;
+import org.apache.camel.util.TimeUtils;
+import org.apache.camel.util.json.JsonObject;
+
+@DevConsole(name = "send", displayName = "Camel Send", description = "Send 
messages to endpoints")
+@Configurer(extended = true)
+public class SendDevConsole extends AbstractDevConsole {
+
+    private ProducerTemplate producer;
+    private ConsumerTemplate consumer;
+
+    @Metadata(defaultValue = "32768",
+              description = "Maximum size of the message body to include in 
the dump")
+    private int bodyMaxChars = 32 * 1024;
+
+    @Metadata(defaultValue = "20000", label = "advanced",
+              description = "Timeout when using poll mode")
+    private int pollTimeout = 20000;
+
+    /**
+     * Maximum size of the message body to include in the dump
+     */
+    public static final String BODY_MAX_CHARS = "bodyMaxChars";
+
+    /**
+     * The message body to send. Can refer to files using file: prefix
+     */
+    public static final String BODY = "body";
+
+    /**
+     * Whether to poll message from the endpoint instead of sending
+     */
+    public static final String POLL = "poll";
+
+    /**
+     * Timeout when using poll mode
+     */
+    public static final String POLL_TIMEOUT = "pollTimeout";
+
+    /**
+     * Exchange pattern when sending
+     */
+    public static final String EXCHANGE_PATTERN = "exchangePattern";
+
+    /**
+     * Endpoint for where to send messages (can also refer to a route id, 
endpoint pattern).
+     */
+    public static final String ENDPOINT = "endpoint";
+
+    public SendDevConsole() {
+        super("camel", "send", "Camel Send", "Send messages to endpoints");
+    }
+
+    @Override
+    protected void doInit() throws Exception {
+        super.doInit();
+        consumer = getCamelContext().createConsumerTemplate();
+        producer = getCamelContext().createProducerTemplate();
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        super.doStop();
+        ServiceHelper.stopService(consumer, producer);
+    }
+
+    public int getBodyMaxChars() {
+        return bodyMaxChars;
+    }
+
+    public void setBodyMaxChars(int bodyMaxChars) {
+        this.bodyMaxChars = bodyMaxChars;
+    }
+
+    public int getPollTimeout() {
+        return pollTimeout;
+    }
+
+    public void setPollTimeout(int pollTimeout) {
+        this.pollTimeout = pollTimeout;
+    }
+
+    protected String doCallText(Map<String, Object> options) {
+        StringBuilder sb = new StringBuilder();
+
+        StopWatch watch = new StopWatch();
+        String endpoint = (String) options.get(ENDPOINT);
+        String body = (String) options.getOrDefault(BODY, "");
+        String exchangePattern = (String) options.get(EXCHANGE_PATTERN);
+        boolean poll = "true".equals(options.get(POLL));
+        int timeout = Integer.parseInt((String) 
options.getOrDefault(POLL_TIMEOUT, String.valueOf(pollTimeout)));
+        // give extra time as CLI needs to process reply also
+        timeout += 5000;
+
+        Endpoint target = null;
+        Exchange out = null;
+        Exception cause = null;
+        try {
+            target = findTarget(endpoint);
+            out = findToTarget(target, poll, timeout, exchangePattern, body, 
options);
+        } catch (Exception e) {
+            cause = e;
+        }
+        if (endpoint != null && target == null) {
+            cause = new NoSuchEndpointException(endpoint);
+        }
+        if (out != null && out.getException() != null) {
+            cause = out.getException();
+        }
+        long taken = watch.taken();
+        String status = "success";
+        if (cause != null) {
+            status = "error";
+        } else if (poll && out == null) {
+            status = "timeout";
+        }
+
+        if (target != null) {
+            sb.append(String.format("\n    Endpoint: %s", target));
+        } else if (endpoint != null) {
+            sb.append(String.format("\n    Endpoint: %s", endpoint));
+        }
+        sb.append(String.format("\n    Status: %s", status));
+        sb.append(String.format("\n    Elapsed: %s", 
TimeUtils.printDuration(taken)));
+        if (cause != null) {
+            sb.append(String.format("\n    Error Message: %s", 
cause.getMessage()));
+            final String stackTrace = 
ExceptionHelper.stackTraceToString(cause);
+            sb.append("\n\n");
+            sb.append(stackTrace);
+            sb.append("\n\n");
+        }
+        if (out != null && (poll || "InOut".equals(exchangePattern))) {
+            sb.append("\n    Response Message:\n");
+            int maxChars = Integer.parseInt((String) 
options.getOrDefault(BODY_MAX_CHARS, "" + bodyMaxChars));
+            String json
+                    = MessageHelper.dumpAsJSon(out.getMessage(), false, false, 
true, 2, true, true, true,
+                            maxChars, true);
+            sb.append(json);
+            sb.append("\n");
+        }
+
+        return sb.toString();
+    }
+
+    @Override
+    protected Map<String, Object> doCallJson(Map<String, Object> options) {
+        JsonObject root = new JsonObject();
+
+        StopWatch watch = new StopWatch();
+        long timestamp = System.currentTimeMillis();
+        String endpoint = (String) options.get(ENDPOINT);
+        String body = (String) options.getOrDefault(BODY, "");
+        String exchangePattern = (String) options.get(EXCHANGE_PATTERN);
+        boolean poll = "true".equals(options.get(POLL));
+        int timeout = Integer.parseInt((String) 
options.getOrDefault(POLL_TIMEOUT, String.valueOf(pollTimeout)));
+        // give extra time as CLI needs to process reply also
+        timeout += 5000;
+
+        Endpoint target = null;
+        Exchange out = null;
+        Exception cause = null;
+        try {
+            target = findTarget(endpoint);
+            out = findToTarget(target, poll, timeout, exchangePattern, body, 
options);
+        } catch (Exception e) {
+            cause = e;
+        }
+        if (endpoint != null && target == null) {
+            cause = new NoSuchEndpointException(endpoint);
+        }
+        if (out != null && out.getException() != null) {
+            cause = out.getException();
+        }
+        long taken = watch.taken();
+        String status = "success";
+        if (cause != null) {
+            status = "error";
+        } else if (poll && out == null) {
+            status = "timeout";
+        }
+
+        root.put("timestamp", timestamp);
+        root.put("status", status);
+        root.put("elapsed", taken);
+        if (target != null) {
+            root.put("endpoint", target.toString());
+        } else if (endpoint != null) {
+            root.put("endpoint", endpoint);
+        }
+        if (cause != null) {
+            // avoid double wrap
+            root.put("exception", 
MessageHelper.dumpExceptionAsJSonObject(cause).getMap("exception"));
+        }
+        if (out != null && (poll || "InOut".equals(exchangePattern))) {
+            root.put("exchangeId", out.getExchangeId());
+            int maxChars = Integer.parseInt((String) 
options.getOrDefault(BODY_MAX_CHARS, "" + bodyMaxChars));
+            // avoid double wrap
+            root.put("message", 
MessageHelper.dumpAsJSonObject(out.getMessage(), true, true, true, true, true, 
true,
+                    maxChars).getMap("message"));
+        }
+
+        return root;
+    }
+
+    private Exchange findToTarget(
+            Endpoint target, boolean poll, int timeout, String 
exchangePattern, String body, Map<String, Object> options)
+            throws Exception {
+        Exchange out = null;
+        if (target != null) {
+            final Object inputBody = prepareBody(body);
+            final Map<String, Object> inputHeaders = prepareHeaders(options);
+            if (poll) {
+                out = consumer.receive(target, timeout);
+            } else {
+                final String mep = exchangePattern;
+                out = producer.send(target, exchange -> {
+                    exchange.getMessage().setBody(inputBody);
+                    if (!inputHeaders.isEmpty()) {
+                        exchange.getMessage().setHeaders(inputHeaders);
+                    }
+                    exchange.setPattern(
+                            "InOut".equals(mep) ? ExchangePattern.InOut : 
ExchangePattern.InOnly);
+                });
+            }
+            if (inputBody instanceof Closeable c) {
+                IOHelper.close(c);
+            }
+        }
+        return out;
+    }
+
+    private Endpoint findTarget(String endpoint) {
+        Endpoint target = null;
+        if (endpoint == null) {
+            List<Route> routes = getCamelContext().getRoutes();
+            if (!routes.isEmpty()) {
+                // grab endpoint from 1st route
+                target = routes.get(0).getEndpoint();
+            }
+        } else {
+            // is the endpoint a pattern or route id
+            boolean scheme = endpoint.contains(":");
+            boolean pattern = endpoint.endsWith("*");
+            if (!scheme || pattern) {
+                if (!scheme) {
+                    endpoint = endpoint + "*";
+                }
+                for (Route route : getCamelContext().getRoutes()) {
+                    Endpoint e = route.getEndpoint();
+                    if (EndpointHelper.matchEndpoint(getCamelContext(), 
e.getEndpointUri(), endpoint)) {
+                        target = e;
+                        break;
+                    }
+                }
+                if (target == null) {
+                    // okay it may refer to a route id
+                    for (Route route : getCamelContext().getRoutes()) {
+                        String id = route.getRouteId();
+                        Endpoint e = route.getEndpoint();
+                        if (EndpointHelper.matchEndpoint(getCamelContext(), 
id, endpoint)) {
+                            target = e;
+                            break;
+                        }
+                    }
+                }
+            } else {
+                target = getCamelContext().getEndpoint(endpoint);
+            }
+        }
+        return target;
+    }
+
+    private Object prepareBody(String body) throws Exception {
+        Object b = body;
+        if (body.startsWith("file:")) {
+            File file = new File(body.substring(5));
+            b = new FileInputStream(file);
+        }
+        return b;
+    }
+
+    private Map prepareHeaders(Map<String, Object> options) {
+        Map<String, Object> answer = new HashMap<>();
+        options.forEach((k, v) -> {
+            if (isCustomHeader(k)) {
+                answer.put(k, v);
+            }
+        });
+        return answer;
+    }
+
+    private static boolean isCustomHeader(String key) {
+        return !BODY.equals(key) && !BODY_MAX_CHARS.equals(key) && 
!POLL.equals(key) && !POLL_TIMEOUT.equals(key)
+                && !EXCHANGE_PATTERN.equals(key) && !ENDPOINT.equals(key);
+    }
+
+}
diff --git 
a/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/LocalCliConnector.java
 
b/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/LocalCliConnector.java
index 33271493389..30f7d604617 100644
--- 
a/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/LocalCliConnector.java
+++ 
b/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/LocalCliConnector.java
@@ -44,11 +44,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
 import org.apache.camel.CamelContext;
 import org.apache.camel.CamelContextAware;
 import org.apache.camel.ConsumerTemplate;
-import org.apache.camel.Endpoint;
 import org.apache.camel.Exchange;
 import org.apache.camel.ExchangePattern;
 import org.apache.camel.Expression;
-import org.apache.camel.NoSuchEndpointException;
 import org.apache.camel.ProducerTemplate;
 import org.apache.camel.Route;
 import org.apache.camel.RoutesBuilder;
@@ -70,7 +68,6 @@ import org.apache.camel.spi.Resource;
 import org.apache.camel.spi.ResourceLoader;
 import org.apache.camel.spi.ResourceReloadStrategy;
 import org.apache.camel.spi.RoutesLoader;
-import org.apache.camel.support.EndpointHelper;
 import org.apache.camel.support.MessageHelper;
 import org.apache.camel.support.PatternHelper;
 import org.apache.camel.support.PluginHelper;
@@ -506,161 +503,40 @@ public class LocalCliConnector extends ServiceSupport 
implements CliConnector, C
     }
 
     private void doActionSendTask(JsonObject root) throws Exception {
-        StopWatch watch = new StopWatch();
-        long timestamp = System.currentTimeMillis();
-        String endpoint = root.getString("endpoint");
-        String body = root.getStringOrDefault("body", "");
-        String exchangePattern = root.getString("exchangePattern");
-        boolean poll = root.getBooleanOrDefault("poll", false);
-        long pollTimeout = root.getLongOrDefault("pollTimeout", 20000L);
-        // give extra time as jbang need to have response
-        pollTimeout += 5000;
-        Collection<JsonObject> headers = root.getCollection("headers");
-        if (body != null) {
-            InputStream is = null;
-            Object b = body;
-            Map<String, Object> map = null;
-            if (body.startsWith("file:")) {
-                File file = new File(body.substring(5));
-                try {
-                    is = new FileInputStream(file);
-                    b = is;
-                } catch (Exception e) {
-                    JsonObject jo = new JsonObject();
-                    jo.put("endpoint", endpoint != null ? endpoint : "");
-                    jo.put("exchangeId", "");
-                    jo.put("exchangePattern", exchangePattern);
-                    jo.put("timestamp", timestamp);
-                    jo.put("elapsed", watch.taken());
-                    jo.put("status", "failed");
-                    // avoid double wrap
-                    jo.put("exception", 
MessageHelper.dumpExceptionAsJSonObject(e).getMap("exception"));
-                    IOHelper.writeText(jo.toJson(), outputFile);
-                    return;
-                }
+        DevConsole dc = 
camelContext.getCamelContextExtension().getContextPlugin(DevConsoleRegistry.class)
+                .resolveById("send");
+        if (dc != null) {
+            JsonObject json;
+            String endpoint = root.getString("endpoint");
+            String body = root.getString("body");
+            String exchangePattern = root.getString("exchangePattern");
+            String poll = root.getString("poll");
+            String pollTimeout = root.getString("pollTimeout");
+            final Map<String, Object> args = new LinkedHashMap<>();
+            if (endpoint != null) {
+                args.put("endpoint", endpoint);
             }
-            if (headers != null) {
-                map = new HashMap<>();
-                for (JsonObject jo : headers) {
-                    map.put(jo.getString("key"), jo.getString("value"));
-                }
+            if (body != null) {
+                args.put("body", body);
             }
-            final Object inputBody = b;
-            final Map<String, Object> inputHeaders = map;
-            Exchange out;
-            Endpoint target = null;
-            if (endpoint == null) {
-                List<Route> routes = camelContext.getRoutes();
-                if (!routes.isEmpty()) {
-                    // grab endpoint from 1st route
-                    target = routes.get(0).getEndpoint();
-                }
-            } else {
-                // is the endpoint a pattern or route id
-                boolean scheme = endpoint.contains(":");
-                boolean pattern = endpoint.endsWith("*");
-                if (!scheme || pattern) {
-                    if (!scheme) {
-                        endpoint = endpoint + "*";
-                    }
-                    for (Route route : camelContext.getRoutes()) {
-                        Endpoint e = route.getEndpoint();
-                        if (EndpointHelper.matchEndpoint(camelContext, 
e.getEndpointUri(), endpoint)) {
-                            target = e;
-                            break;
-                        }
-                    }
-                    if (target == null) {
-                        // okay it may refer to a route id
-                        for (Route route : camelContext.getRoutes()) {
-                            String id = route.getRouteId();
-                            Endpoint e = route.getEndpoint();
-                            if (EndpointHelper.matchEndpoint(camelContext, id, 
endpoint)) {
-                                target = e;
-                                break;
-                            }
-                        }
-                    }
-                } else {
-                    target = camelContext.getEndpoint(endpoint);
-                }
+            if (exchangePattern != null) {
+                args.put("exchangePattern", exchangePattern);
             }
-
-            if (target != null) {
-                if (poll) {
-                    exchangePattern = "InOut";
-                    out = consumer.receive(target, pollTimeout);
-                } else {
-                    final String mep = exchangePattern;
-                    out = producer.send(target, exchange -> {
-                        exchange.getMessage().setBody(inputBody);
-                        if (inputHeaders != null) {
-                            exchange.getMessage().setHeaders(inputHeaders);
-                        }
-                        exchange.setPattern(
-                                "InOut".equals(mep) ? ExchangePattern.InOut : 
ExchangePattern.InOnly);
-                    });
-                }
-                IOHelper.close(is);
-                LOG.trace("Updating output file: {}", outputFile);
-                if (out != null && out.getException() != null) {
-                    JsonObject jo = new JsonObject();
-                    jo.put("endpoint", target.getEndpointUri());
-                    jo.put("exchangeId", out.getExchangeId());
-                    jo.put("exchangePattern", exchangePattern);
-                    jo.put("timestamp", timestamp);
-                    jo.put("elapsed", watch.taken());
-                    jo.put("status", "failed");
-                    // avoid double wrap
-                    jo.put("exception",
-                            
MessageHelper.dumpExceptionAsJSonObject(out.getException()).getMap("exception"));
-                    IOHelper.writeText(jo.toJson(), outputFile);
-                } else if (out != null && "InOut".equals(exchangePattern)) {
-                    JsonObject jo = new JsonObject();
-                    jo.put("endpoint", target.getEndpointUri());
-                    jo.put("exchangeId", out.getExchangeId());
-                    jo.put("exchangePattern", exchangePattern);
-                    jo.put("timestamp", timestamp);
-                    jo.put("elapsed", watch.taken());
-                    jo.put("status", "success");
-                    // avoid double wrap
-                    jo.put("message", 
MessageHelper.dumpAsJSonObject(out.getMessage(), true, true, true, true, true, 
true,
-                            BODY_MAX_CHARS).getMap("message"));
-                    IOHelper.writeText(jo.toJson(), outputFile);
-                } else if (out != null) {
-                    JsonObject jo = new JsonObject();
-                    jo.put("endpoint", target.getEndpointUri());
-                    jo.put("exchangeId", out.getExchangeId());
-                    jo.put("exchangePattern", exchangePattern);
-                    jo.put("timestamp", timestamp);
-                    jo.put("elapsed", watch.taken());
-                    jo.put("status", "success");
-                    IOHelper.writeText(jo.toJson(), outputFile);
-                } else {
-                    JsonObject jo = new JsonObject();
-                    jo.put("endpoint", target.getEndpointUri());
-                    jo.put("exchangeId", "");
-                    jo.put("exchangePattern", exchangePattern);
-                    jo.put("timestamp", timestamp);
-                    jo.put("elapsed", watch.taken());
-                    jo.put("status", "timeout");
-                    IOHelper.writeText(jo.toJson(), outputFile);
+            if (poll != null) {
+                args.put("poll", poll);
+            }
+            if (pollTimeout != null) {
+                args.put("pollTimeout", pollTimeout);
+            }
+            Collection<JsonObject> headers = root.getCollection("headers");
+            if (headers != null) {
+                for (JsonObject jo : headers) {
+                    args.put(jo.getString("key"), jo.getString("value"));
                 }
-            } else {
-                // there is no valid endpoint
-                JsonObject jo = new JsonObject();
-                jo.put("endpoint", endpoint != null ? endpoint : "");
-                jo.put("exchangeId", "");
-                jo.put("exchangePattern", exchangePattern);
-                jo.put("timestamp", timestamp);
-                jo.put("elapsed", watch.taken());
-                jo.put("status", "failed");
-                // avoid double wrap
-                jo.put("exception",
-                        MessageHelper.dumpExceptionAsJSonObject(new 
NoSuchEndpointException(root.getString("endpoint")))
-                                .getMap("exception"));
-                IOHelper.writeText(jo.toJson(), outputFile);
             }
+            json = (JsonObject) dc.call(DevConsole.MediaType.JSON, args);
+            LOG.trace("Updating output file: {}", outputFile);
+            IOHelper.writeText(json.toJson(), outputFile);
         } else {
             IOHelper.writeText("{}", outputFile);
         }
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSendAction.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSendAction.java
index 21dd012abc6..a2573b91d87 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSendAction.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelSendAction.java
@@ -127,7 +127,7 @@ public class CamelSendAction extends ActionBaseCommand {
         if (timeout < 5000) {
             timeout = 5000;
         }
-        root.put("pollTimeout", Math.min(1000, timeout - 1000)); // poll 
timeout should be shorter than jbang timeout
+        root.put("pollTimeout", timeout);
         String mep = (reply || replyFile != null) ? "InOut" : "InOnly";
         root.put("exchangePattern", mep);
         if (body != null) {
@@ -279,7 +279,8 @@ public class CamelSendAction extends ActionBaseCommand {
 
     protected JsonObject waitForOutputFile(File outputFile) {
         StopWatch watch = new StopWatch();
-        while (watch.taken() < timeout) {
+        long wait = timeout + 10000; // wait longer than timeout
+        while (watch.taken() < wait) {
             try {
                 // give time for response to be ready
                 Thread.sleep(20);

Reply via email to