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 5de3da5b8d0 CAMEL-17333: camel-console - Output json as response.
5de3da5b8d0 is described below

commit 5de3da5b8d0f2ac523ac87172d45f0890bfc8685
Author: Claus Ibsen <[email protected]>
AuthorDate: Sun May 29 11:05:48 2022 +0200

    CAMEL-17333: camel-console - Output json as response.
---
 .../camel/catalog/console/CatalogConsole.java      |  61 +++++-
 .../platform/http/PlatformHttpConsole.java         |  41 +++-
 core/camel-console/pom.xml                         |   5 +
 .../camel/impl/console/AbstractDevConsole.java     |  20 +-
 .../camel/impl/console/ContextDevConsole.java      |  28 ++-
 .../apache/camel/impl/console/EventConsole.java    |  35 +++-
 .../camel/impl/console/HealthDevConsole.java       |  47 ++++-
 .../apache/camel/impl/console/JvmDevConsole.java   |  34 +++-
 .../camel/impl/console/MemoryDevConsole.java       |  21 ++-
 .../camel/impl/console/PropertiesDevConsole.java   |  21 ++-
 .../apache/camel/impl/console/RouteDevConsole.java |  88 ++++++---
 .../apache/camel/impl/console/TopDevConsole.java   | 210 ++++++++++++++++-----
 .../camel/impl/console/ContextDevConsoleTest.java  |  16 +-
 .../ROOT/pages/camel-3x-upgrade-guide-3_18.adoc    |   5 +
 .../org/apache/camel/main/VertxHttpServer.java     |  79 +++++---
 15 files changed, 589 insertions(+), 122 deletions(-)

diff --git 
a/catalog/camel-catalog-console/src/main/java/org/apache/camel/catalog/console/CatalogConsole.java
 
b/catalog/camel-catalog-console/src/main/java/org/apache/camel/catalog/console/CatalogConsole.java
index 068717ca56f..23c7efffb33 100644
--- 
a/catalog/camel-catalog-console/src/main/java/org/apache/camel/catalog/console/CatalogConsole.java
+++ 
b/catalog/camel-catalog-console/src/main/java/org/apache/camel/catalog/console/CatalogConsole.java
@@ -16,6 +16,8 @@
  */
 package org.apache.camel.catalog.console;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 
 import org.apache.camel.catalog.CamelCatalog;
@@ -24,6 +26,7 @@ import org.apache.camel.impl.console.AbstractDevConsole;
 import org.apache.camel.spi.annotations.DevConsole;
 import org.apache.camel.tooling.model.ArtifactModel;
 import org.apache.camel.tooling.model.OtherModel;
+import org.apache.camel.util.json.JsonObject;
 
 @DevConsole("catalog")
 public class CatalogConsole extends AbstractDevConsole {
@@ -36,8 +39,7 @@ public class CatalogConsole extends AbstractDevConsole {
     }
 
     @Override
-    protected Object doCall(MediaType mediaType, Map<String, Object> options) {
-        // only text is supported
+    protected String doCallText(Map<String, Object> options) {
         StringBuilder sb = new StringBuilder();
 
         sb.append("\nComponents:\n");
@@ -64,6 +66,38 @@ public class CatalogConsole extends AbstractDevConsole {
         return sb.toString();
     }
 
+    @Override
+    protected JsonObject doCallJson(Map<String, Object> options) {
+        JsonObject root = new JsonObject();
+        List<JsonObject> components = new ArrayList<>();
+        root.put("components", components);
+        List<JsonObject> dataformat = new ArrayList<>();
+        root.put("dataformat", dataformat);
+        List<JsonObject> languages = new ArrayList<>();
+        root.put("languages", languages);
+        List<JsonObject> others = new ArrayList<>();
+        root.put("others", others);
+
+        getCamelContext().getComponentNames().forEach(n -> 
appendModel(catalog.componentModel(n), components));
+        getCamelContext().getLanguageNames().forEach(n -> 
appendModel(catalog.languageModel(n), languages));
+        getCamelContext().getDataFormatNames().forEach(n -> 
appendModel(catalog.dataFormatModel(n), dataformat));
+
+        // misc is harder to find as we need to find them via classpath
+        String[] cp = CP.split("[:|;]");
+        String suffix = "-" + getCamelContext().getVersion() + ".jar";
+        for (String c : cp) {
+            if (c.endsWith(suffix)) {
+                int pos = Math.max(c.lastIndexOf("/"), c.lastIndexOf("\\"));
+                if (pos > 0) {
+                    c = c.substring(pos + 1, c.length() - suffix.length());
+                    appendModel(findOtherModel(c), others);
+                }
+            }
+        }
+
+        return root;
+    }
+
     private ArtifactModel findOtherModel(String artifactId) {
         // is it a mist component
         for (String name : catalog.findOtherNames()) {
@@ -81,8 +115,27 @@ public class CatalogConsole extends AbstractDevConsole {
             if (model.isDeprecated()) {
                 level += "-deprecated";
             }
-            sb.append(String.format("\n    %s %s %s %s %s", model.getTitle(), 
model.getArtifactId(), level,
-                    model.getFirstVersionShort(), model.getDescription()));
+            sb.append(String.format("\n    %s %s %s %s: %s", 
model.getArtifactId(), level,
+                    model.getFirstVersionShort(), model.getTitle(), 
model.getDescription()));
+        }
+    }
+
+    private static void appendModel(ArtifactModel<?> model, List<JsonObject> 
list) {
+        if (model != null) {
+            JsonObject jo = new JsonObject();
+            String level = model.getSupportLevel().toString();
+            if (model.isDeprecated()) {
+                level += "-deprecated";
+            }
+            jo.put("groupId", model.getGroupId());
+            jo.put("artifactId", model.getArtifactId());
+            jo.put("version", model.getVersion());
+            jo.put("level", level);
+            jo.put("firstVersion", model.getFirstVersionShort());
+            jo.put("title", model.getTitle());
+            jo.put("description", model.getDescription());
+
+            list.add(jo);
         }
     }
 }
diff --git 
a/components/camel-platform-http/src/main/java/org/apache/camel/component/platform/http/PlatformHttpConsole.java
 
b/components/camel-platform-http/src/main/java/org/apache/camel/component/platform/http/PlatformHttpConsole.java
index 4afcfa7e3f5..16f56ad2ab1 100644
--- 
a/components/camel-platform-http/src/main/java/org/apache/camel/component/platform/http/PlatformHttpConsole.java
+++ 
b/components/camel-platform-http/src/main/java/org/apache/camel/component/platform/http/PlatformHttpConsole.java
@@ -16,11 +16,14 @@
  */
 package org.apache.camel.component.platform.http;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 import org.apache.camel.impl.console.AbstractDevConsole;
 import org.apache.camel.spi.annotations.DevConsole;
+import org.apache.camel.util.json.JsonObject;
 
 @DevConsole("platform-http")
 public class PlatformHttpConsole extends AbstractDevConsole {
@@ -30,8 +33,7 @@ public class PlatformHttpConsole extends AbstractDevConsole {
     }
 
     @Override
-    protected Object doCall(MediaType mediaType, Map<String, Object> options) {
-        // only text is supported
+    protected String doCallText(Map<String, Object> options) {
         StringBuilder sb = new StringBuilder();
 
         PlatformHttpComponent http = 
getCamelContext().getComponent("platform-http", PlatformHttpComponent.class);
@@ -54,4 +56,39 @@ public class PlatformHttpConsole extends AbstractDevConsole {
         return sb.toString();
     }
 
+    @Override
+    protected JsonObject doCallJson(Map<String, Object> options) {
+        JsonObject root = new JsonObject();
+
+        PlatformHttpComponent http = 
getCamelContext().getComponent("platform-http", PlatformHttpComponent.class);
+        if (http != null) {
+            String server = "http://0.0.0.0";;
+            int port = http.getEngine().getServerPort();
+            if (port > 0) {
+                server += ":" + port;
+            }
+            root.put("server", server);
+
+            Set<HttpEndpointModel> models = http.getHttpEndpoints();
+            List<JsonObject> list = new ArrayList<>();
+            for (HttpEndpointModel model : models) {
+                JsonObject jo = new JsonObject();
+                String uri = model.getUri();
+                if (!uri.startsWith("/")) {
+                    uri = "/" + uri;
+                }
+                jo.put("url", server + uri);
+                jo.put("path", model.getUri());
+                if (model.getVerbs() != null) {
+                    jo.put("verbs", model.getVerbs());
+                }
+                list.add(jo);
+            }
+            if (!list.isEmpty()) {
+                root.put("endpoints", list);
+            }
+        }
+
+        return root;
+    }
 }
diff --git a/core/camel-console/pom.xml b/core/camel-console/pom.xml
index 2949d29c991..6288dc95bee 100644
--- a/core/camel-console/pom.xml
+++ b/core/camel-console/pom.xml
@@ -44,6 +44,11 @@
             <groupId>org.apache.camel</groupId>
             <artifactId>camel-core-engine</artifactId>
         </dependency>
+        <!-- json -->
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-util-json</artifactId>
+        </dependency>
 
         <!-- testing -->
         <dependency>
diff --git 
a/core/camel-console/src/main/java/org/apache/camel/impl/console/AbstractDevConsole.java
 
b/core/camel-console/src/main/java/org/apache/camel/impl/console/AbstractDevConsole.java
index 5ead0ac9998..3da644e0252 100644
--- 
a/core/camel-console/src/main/java/org/apache/camel/impl/console/AbstractDevConsole.java
+++ 
b/core/camel-console/src/main/java/org/apache/camel/impl/console/AbstractDevConsole.java
@@ -22,6 +22,7 @@ import org.apache.camel.CamelContext;
 import org.apache.camel.CamelContextAware;
 import org.apache.camel.console.DevConsole;
 import org.apache.camel.support.service.ServiceSupport;
+import org.apache.camel.util.json.JsonObject;
 
 /**
  * Base implementation for {@link DevConsole}.
@@ -55,7 +56,7 @@ public abstract class AbstractDevConsole extends 
ServiceSupport implements DevCo
 
     @Override
     public boolean supportMediaType(MediaType mediaType) {
-        return mediaType == MediaType.TEXT;
+        return true;
     }
 
     @Override
@@ -100,15 +101,26 @@ public abstract class AbstractDevConsole extends 
ServiceSupport implements DevCo
     @Override
     public Object call(MediaType mediaType, Map<String, Object> options) {
         synchronized (lock) {
-            return doCall(mediaType, options);
+            if (mediaType == MediaType.JSON) {
+                return doCallJson(options);
+            } else {
+                return doCallText(options);
+            }
         }
     }
 
     /**
-     * Invokes and gets the output from this console.
+     * Invokes and gets the output from this console in json format.
      *
      * @see DevConsole#call(MediaType, Map)
      */
-    protected abstract Object doCall(MediaType mediaType, Map<String, Object> 
options);
+    protected abstract JsonObject doCallJson(Map<String, Object> options);
+
+    /**
+     * Invokes and gets the output from this console in text format.
+     *
+     * @see DevConsole#call(MediaType, Map)
+     */
+    protected abstract String doCallText(Map<String, Object> options);
 
 }
diff --git 
a/core/camel-console/src/main/java/org/apache/camel/impl/console/ContextDevConsole.java
 
b/core/camel-console/src/main/java/org/apache/camel/impl/console/ContextDevConsole.java
index 8d8da61e27e..8ff177aa693 100644
--- 
a/core/camel-console/src/main/java/org/apache/camel/impl/console/ContextDevConsole.java
+++ 
b/core/camel-console/src/main/java/org/apache/camel/impl/console/ContextDevConsole.java
@@ -22,6 +22,7 @@ import org.apache.camel.api.management.ManagedCamelContext;
 import org.apache.camel.api.management.mbean.ManagedCamelContextMBean;
 import org.apache.camel.spi.annotations.DevConsole;
 import org.apache.camel.util.TimeUtils;
+import org.apache.camel.util.json.JsonObject;
 
 @DevConsole("context")
 public class ContextDevConsole extends AbstractDevConsole {
@@ -30,9 +31,7 @@ public class ContextDevConsole extends AbstractDevConsole {
         super("camel", "context", "CamelContext", "Overall information about 
the CamelContext");
     }
 
-    @Override
-    protected Object doCall(MediaType mediaType, Map<String, Object> options) {
-        // only text is supported
+    protected String doCallText(Map<String, Object> options) {
         StringBuilder sb = new StringBuilder();
 
         sb.append(String.format("Apache Camel %s (%s) uptime %s", 
getCamelContext().getVersion(), getCamelContext().getName(),
@@ -53,4 +52,27 @@ public class ContextDevConsole extends AbstractDevConsole {
 
         return sb.toString();
     }
+
+    protected JsonObject doCallJson(Map<String, Object> options) {
+        JsonObject root = new JsonObject();
+        root.put("name", getCamelContext().getName());
+        root.put("version", getCamelContext().getVersion());
+        root.put("uptime", getCamelContext().getUptime());
+
+        ManagedCamelContext mcc = 
getCamelContext().getExtension(ManagedCamelContext.class);
+        if (mcc != null) {
+            ManagedCamelContextMBean mb = mcc.getManagedCamelContext();
+            JsonObject stats = new JsonObject();
+            stats.put("exchangesTotal", mb.getExchangesTotal());
+            stats.put("exchangesFailed", mb.getExchangesFailed());
+            stats.put("exchangesInflight", mb.getExchangesInflight());
+            stats.put("meanProcessingTime", mb.getMeanProcessingTime());
+            stats.put("maxProcessingTime", mb.getMaxProcessingTime());
+            stats.put("minProcessingTime", mb.getMinProcessingTime());
+            root.put("statistics", stats);
+        }
+
+        return root;
+    }
+
 }
diff --git 
a/core/camel-console/src/main/java/org/apache/camel/impl/console/EventConsole.java
 
b/core/camel-console/src/main/java/org/apache/camel/impl/console/EventConsole.java
index ed09bccf90f..8c03a2a2cd1 100644
--- 
a/core/camel-console/src/main/java/org/apache/camel/impl/console/EventConsole.java
+++ 
b/core/camel-console/src/main/java/org/apache/camel/impl/console/EventConsole.java
@@ -17,6 +17,8 @@
 package org.apache.camel.impl.console;
 
 import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 import java.util.Queue;
 
@@ -25,6 +27,7 @@ import org.apache.camel.spi.Configurer;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.annotations.DevConsole;
 import org.apache.camel.support.EventNotifierSupport;
+import org.apache.camel.util.json.JsonObject;
 
 @DevConsole("event")
 @Configurer(bootstrap = true)
@@ -66,9 +69,7 @@ public class EventConsole extends AbstractDevConsole {
         events.clear();
     }
 
-    @Override
-    protected Object doCall(MediaType mediaType, Map<String, Object> options) {
-        // only text is supported
+    protected String doCallText(Map<String, Object> options) {
         StringBuilder sb = new StringBuilder();
 
         if (!events.isEmpty()) {
@@ -90,6 +91,34 @@ public class EventConsole extends AbstractDevConsole {
         return sb.toString();
     }
 
+    protected JsonObject doCallJson(Map<String, Object> options) {
+        JsonObject root = new JsonObject();
+
+        if (!events.isEmpty()) {
+            List<JsonObject> arr = new ArrayList<>();
+            for (CamelEvent event : events) {
+                JsonObject jo = new JsonObject();
+                jo.put("type", event.getType().toString());
+                jo.put("message", event.toString());
+                arr.add(jo);
+            }
+            root.put("events", arr);
+        }
+        if (!exchangeEvents.isEmpty()) {
+            List<JsonObject> arr = new ArrayList<>();
+            for (CamelEvent.ExchangeEvent event : exchangeEvents) {
+                JsonObject jo = new JsonObject();
+                jo.put("type", event.getType().toString());
+                jo.put("exchangeId", event.getExchange().getExchangeId());
+                jo.put("message", event.toString());
+                arr.add(jo);
+            }
+            root.put("exchangeEvents", arr);
+        }
+
+        return root;
+    }
+
     private class ConsoleEventNotifier extends EventNotifierSupport {
 
         @Override
diff --git 
a/core/camel-console/src/main/java/org/apache/camel/impl/console/HealthDevConsole.java
 
b/core/camel-console/src/main/java/org/apache/camel/impl/console/HealthDevConsole.java
index 914e6d8d7d8..828eb4bcb40 100644
--- 
a/core/camel-console/src/main/java/org/apache/camel/impl/console/HealthDevConsole.java
+++ 
b/core/camel-console/src/main/java/org/apache/camel/impl/console/HealthDevConsole.java
@@ -24,6 +24,7 @@ import java.util.Map;
 import org.apache.camel.health.HealthCheck;
 import org.apache.camel.health.HealthCheckHelper;
 import org.apache.camel.spi.annotations.DevConsole;
+import org.apache.camel.util.json.JsonObject;
 
 @DevConsole("health")
 public class HealthDevConsole extends AbstractDevConsole {
@@ -32,8 +33,7 @@ public class HealthDevConsole extends AbstractDevConsole {
         super("camel", "health", "Health Check", "Health Check Status");
     }
 
-    @Override
-    protected Object doCall(MediaType mediaType, Map<String, Object> options) {
+    protected String doCallText(Map<String, Object> options) {
         // only text is supported
         StringBuilder sb = new StringBuilder();
 
@@ -62,4 +62,47 @@ public class HealthDevConsole extends AbstractDevConsole {
 
         return sb.toString();
     }
+
+    @Override
+    protected JsonObject doCallJson(Map<String, Object> options) {
+        JsonObject root = new JsonObject();
+
+        Collection<HealthCheck.Result> results = 
HealthCheckHelper.invoke(getCamelContext());
+        boolean up = results.stream().allMatch(h -> 
HealthCheck.State.UP.equals(h.getState()));
+        root.put("up", up);
+
+        results.forEach(res -> {
+            JsonObject jo = new JsonObject();
+            jo.put("id", res.getCheck().getId());
+            jo.put("group", res.getCheck().getGroup());
+            jo.put("state", res.getState().toString());
+
+            boolean ok = res.getState().equals(HealthCheck.State.UP);
+            if (ok) {
+                jo.put("up", true);
+            } else {
+                jo.put("up", false);
+                String msg = res.getMessage().orElse("");
+                jo.put("message", msg);
+
+                Throwable cause = res.getError().orElse(null);
+                if (cause != null) {
+                    StringWriter sw = new StringWriter();
+                    PrintWriter pw = new PrintWriter(sw);
+                    cause.printStackTrace(pw);
+                    jo.put("stacktrace", pw.toString());
+                }
+            }
+
+            if (!res.getDetails().isEmpty()) {
+                JsonObject details = new JsonObject();
+                res.getDetails().forEach((k, v) -> {
+                    details.put(k, v.toString());
+                });
+                jo.put("details", details);
+            }
+        });
+
+        return root;
+    }
 }
diff --git 
a/core/camel-console/src/main/java/org/apache/camel/impl/console/JvmDevConsole.java
 
b/core/camel-console/src/main/java/org/apache/camel/impl/console/JvmDevConsole.java
index 5534fcdce1a..e1a5d727d6a 100644
--- 
a/core/camel-console/src/main/java/org/apache/camel/impl/console/JvmDevConsole.java
+++ 
b/core/camel-console/src/main/java/org/apache/camel/impl/console/JvmDevConsole.java
@@ -24,6 +24,7 @@ import org.apache.camel.spi.Configurer;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.annotations.DevConsole;
 import org.apache.camel.util.TimeUtils;
+import org.apache.camel.util.json.JsonObject;
 
 @DevConsole("jvm")
 @Configurer(bootstrap = true)
@@ -45,8 +46,7 @@ public class JvmDevConsole extends AbstractDevConsole {
     }
 
     @Override
-    protected Object doCall(MediaType mediaType, Map<String, Object> options) {
-        // only text is supported
+    protected String doCallText(Map<String, Object> options) {
         StringBuilder sb = new StringBuilder();
 
         RuntimeMXBean mb = ManagementFactory.getRuntimeMXBean();
@@ -58,8 +58,8 @@ public class JvmDevConsole extends AbstractDevConsole {
             sb.append(String.format("PID: %s\n", mb.getPid()));
             if (!mb.getInputArguments().isEmpty()) {
                 sb.append("Input Arguments:");
-                String cp = String.join("\n    ", mb.getInputArguments());
-                sb.append("\n    ").append(cp).append("\n");
+                String arg = String.join("\n    ", mb.getInputArguments());
+                sb.append("\n    ").append(arg).append("\n");
             }
             if (mb.isBootClassPathSupported()) {
                 sb.append("Boot Classpath:");
@@ -73,4 +73,30 @@ public class JvmDevConsole extends AbstractDevConsole {
 
         return sb.toString();
     }
+
+    @Override
+    protected JsonObject doCallJson(Map<String, Object> options) {
+        JsonObject root = new JsonObject();
+
+        RuntimeMXBean mb = ManagementFactory.getRuntimeMXBean();
+        if (mb != null) {
+            root.put("vmName", mb.getVmName());
+            root.put("vmVersion", mb.getVmVersion());
+            root.put("vmVendor", mb.getVmVendor());
+            root.put("vmUptime", TimeUtils.printDuration(mb.getUptime()));
+            root.put("pid", mb.getPid());
+            if (!mb.getInputArguments().isEmpty()) {
+                String arg = String.join(" ", mb.getInputArguments());
+                root.put("inputArguments", arg);
+            }
+            if (mb.isBootClassPathSupported()) {
+                String[] cp = mb.getBootClassPath().split("[:|;]");
+                root.put("bootClasspath", cp);
+            }
+            String[] cp = mb.getClassPath().split("[:|;]");
+            root.put("classpath", cp);
+        }
+
+        return root;
+    }
 }
diff --git 
a/core/camel-console/src/main/java/org/apache/camel/impl/console/MemoryDevConsole.java
 
b/core/camel-console/src/main/java/org/apache/camel/impl/console/MemoryDevConsole.java
index 1fa9c0c1351..760d6f0992e 100644
--- 
a/core/camel-console/src/main/java/org/apache/camel/impl/console/MemoryDevConsole.java
+++ 
b/core/camel-console/src/main/java/org/apache/camel/impl/console/MemoryDevConsole.java
@@ -22,6 +22,7 @@ import java.util.Map;
 
 import org.apache.camel.spi.Configurer;
 import org.apache.camel.spi.annotations.DevConsole;
+import org.apache.camel.util.json.JsonObject;
 
 import static org.apache.camel.util.UnitUtils.printUnitFromBytesDot;
 
@@ -34,7 +35,7 @@ public class MemoryDevConsole extends AbstractDevConsole {
     }
 
     @Override
-    protected Object doCall(MediaType mediaType, Map<String, Object> options) {
+    protected String doCallText(Map<String, Object> options) {
         // only text is supported
         StringBuilder sb = new StringBuilder();
 
@@ -55,4 +56,22 @@ public class MemoryDevConsole extends AbstractDevConsole {
         return sb.toString();
     }
 
+    @Override
+    protected JsonObject doCallJson(Map<String, Object> options) {
+        JsonObject root = new JsonObject();
+
+        MemoryMXBean mb = ManagementFactory.getMemoryMXBean();
+        if (mb != null) {
+            root.put("heapMemoryInit", 
printUnitFromBytesDot(mb.getHeapMemoryUsage().getInit()));
+            root.put("heapMemoryMax", 
printUnitFromBytesDot(mb.getHeapMemoryUsage().getMax()));
+            root.put("heapMemoryUsed", 
printUnitFromBytesDot(mb.getHeapMemoryUsage().getUsed()));
+            root.put("heapMemoryCommitted", 
printUnitFromBytesDot(mb.getHeapMemoryUsage().getCommitted()));
+            root.put("nonHeapMemoryInit", 
printUnitFromBytesDot(mb.getNonHeapMemoryUsage().getInit()));
+            root.put("nonHeapMemoryMax", 
printUnitFromBytesDot(mb.getNonHeapMemoryUsage().getMax()));
+            root.put("nonHeapMemoryUsed", 
printUnitFromBytesDot(mb.getNonHeapMemoryUsage().getUsed()));
+            root.put("nonHeapMemoryCommitted", 
printUnitFromBytesDot(mb.getNonHeapMemoryUsage().getCommitted()));
+        }
+
+        return root;
+    }
 }
diff --git 
a/core/camel-console/src/main/java/org/apache/camel/impl/console/PropertiesDevConsole.java
 
b/core/camel-console/src/main/java/org/apache/camel/impl/console/PropertiesDevConsole.java
index 7a4bde0035f..d3ac4916c9d 100644
--- 
a/core/camel-console/src/main/java/org/apache/camel/impl/console/PropertiesDevConsole.java
+++ 
b/core/camel-console/src/main/java/org/apache/camel/impl/console/PropertiesDevConsole.java
@@ -20,6 +20,7 @@ import java.util.Map;
 
 import org.apache.camel.spi.PropertiesComponent;
 import org.apache.camel.spi.annotations.DevConsole;
+import org.apache.camel.util.json.JsonObject;
 
 @DevConsole("properties")
 public class PropertiesDevConsole extends AbstractDevConsole {
@@ -29,8 +30,7 @@ public class PropertiesDevConsole extends AbstractDevConsole {
     }
 
     @Override
-    protected Object doCall(MediaType mediaType, Map<String, Object> options) {
-        // only text is supported
+    protected String doCallText(Map<String, Object> options) {
         StringBuilder sb = new StringBuilder();
 
         PropertiesComponent pc = getCamelContext().getPropertiesComponent();
@@ -46,4 +46,21 @@ public class PropertiesDevConsole extends AbstractDevConsole 
{
 
         return sb.toString();
     }
+
+    @Override
+    protected JsonObject doCallJson(Map<String, Object> options) {
+        JsonObject root = new JsonObject();
+
+        PropertiesComponent pc = getCamelContext().getPropertiesComponent();
+        root.put("locations", pc.getLocations());
+        JsonObject props = new JsonObject();
+        root.put("properties", props);
+        for (Map.Entry<Object, Object> entry : pc.loadProperties().entrySet()) 
{
+            String k = entry.getKey().toString();
+            Object v = entry.getValue();
+            props.put(k, v);
+        }
+
+        return root;
+    }
 }
diff --git 
a/core/camel-console/src/main/java/org/apache/camel/impl/console/RouteDevConsole.java
 
b/core/camel-console/src/main/java/org/apache/camel/impl/console/RouteDevConsole.java
index 83dcd1407cd..41a9b70e0f1 100644
--- 
a/core/camel-console/src/main/java/org/apache/camel/impl/console/RouteDevConsole.java
+++ 
b/core/camel-console/src/main/java/org/apache/camel/impl/console/RouteDevConsole.java
@@ -16,8 +16,10 @@
  */
 package org.apache.camel.impl.console;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Function;
 
 import org.apache.camel.Exchange;
 import org.apache.camel.Route;
@@ -27,6 +29,7 @@ import org.apache.camel.spi.annotations.DevConsole;
 import org.apache.camel.support.PatternHelper;
 import org.apache.camel.util.StringHelper;
 import org.apache.camel.util.TimeUtils;
+import org.apache.camel.util.json.JsonObject;
 
 @DevConsole("route")
 public class RouteDevConsole extends AbstractDevConsole {
@@ -46,49 +49,82 @@ public class RouteDevConsole extends AbstractDevConsole {
     }
 
     @Override
-    protected Object doCall(MediaType mediaType, Map<String, Object> options) {
+    protected String doCallText(Map<String, Object> options) {
+        final StringBuilder sb = new StringBuilder();
+        Function<ManagedRouteMBean, Object> task = mrb -> {
+            if (sb.length() > 0) {
+                sb.append("\n");
+            }
+            sb.append(String.format("    Id: %s", mrb.getRouteId()));
+            sb.append(String.format("\n    From: %s", mrb.getEndpointUri()));
+            if (mrb.getSourceLocation() != null) {
+                sb.append(String.format("\n    Source: %s", 
mrb.getSourceLocation()));
+            }
+            sb.append(String.format("\n    State: %s", mrb.getState()));
+            sb.append(String.format("\n    Uptime: %s", mrb.getUptime()));
+            sb.append(String.format("\n    Total: %s", 
mrb.getExchangesTotal()));
+            sb.append(String.format("\n    Failed: %s", 
mrb.getExchangesFailed()));
+            sb.append(String.format("\n    Inflight: %s", 
mrb.getExchangesInflight()));
+            sb.append(String.format("\n    Mean Time: %s", 
TimeUtils.printDuration(mrb.getMeanProcessingTime())));
+            sb.append(String.format("\n    Max Time: %s", 
TimeUtils.printDuration(mrb.getMaxProcessingTime())));
+            sb.append(String.format("\n    Min Time: %s", 
TimeUtils.printDuration(mrb.getMinProcessingTime())));
+            sb.append("\n");
+            return null;
+        };
+        doCall(options, task);
+        return sb.toString();
+    }
+
+    @Override
+    protected JsonObject doCallJson(Map<String, Object> options) {
+        final JsonObject root = new JsonObject();
+        final List<JsonObject> list = new ArrayList<>();
+
+        Function<ManagedRouteMBean, Object> task = mrb -> {
+            JsonObject jo = new JsonObject();
+            list.add(jo);
+
+            jo.put("routeId", mrb.getRouteId());
+            jo.put("from", mrb.getEndpointUri());
+            if (mrb.getSourceLocation() != null) {
+                jo.put("source", mrb.getSourceLocation());
+            }
+            jo.put("state", mrb.getState());
+            jo.put("uptime", mrb.getUptime());
+            JsonObject stats = new JsonObject();
+            stats.put("exchangesTotal", mrb.getExchangesTotal());
+            stats.put("exchangesFailed", mrb.getExchangesFailed());
+            stats.put("exchangesInflight", mrb.getExchangesInflight());
+            stats.put("meanProcessingTime", mrb.getMeanProcessingTime());
+            stats.put("maxProcessingTime", mrb.getMaxProcessingTime());
+            stats.put("minProcessingTime", mrb.getMinProcessingTime());
+            jo.put("statistics", stats);
+            return null;
+        };
+        doCall(options, task);
+        root.put("routes", list);
+        return root;
+    }
+
+    protected void doCall(Map<String, Object> options, 
Function<ManagedRouteMBean, Object> task) {
         String path = (String) options.get(Exchange.HTTP_PATH);
         String subPath = path != null ? StringHelper.after(path, "/") : null;
         String filter = (String) options.get(FILTER);
         String limit = (String) options.get(LIMIT);
         final int max = limit == null ? Integer.MAX_VALUE : 
Integer.parseInt(limit);
 
-        // only text is supported
-        StringBuilder sb = new StringBuilder();
-
         ManagedCamelContext mcc = 
getCamelContext().getExtension(ManagedCamelContext.class);
         if (mcc != null) {
             List<Route> routes = getCamelContext().getRoutes();
             routes.sort((o1, o2) -> 
o1.getRouteId().compareToIgnoreCase(o2.getRouteId()));
-
             routes.stream()
                     .map(route -> mcc.getManagedRoute(route.getRouteId()))
                     .filter(r -> accept(r, filter))
                     .filter(r -> accept(r, subPath))
                     .sorted(RouteDevConsole::sort)
                     .limit(max)
-                    .forEach(mrb -> {
-                        if (sb.length() > 0) {
-                            sb.append("\n");
-                        }
-                        sb.append(String.format("    Id: %s", 
mrb.getRouteId()));
-                        sb.append(String.format("\n    From: %s", 
mrb.getEndpointUri()));
-                        if (mrb.getSourceLocation() != null) {
-                            sb.append(String.format("\n    Source: %s", 
mrb.getSourceLocation()));
-                        }
-                        sb.append(String.format("\n    State: %s", 
mrb.getState()));
-                        sb.append(String.format("\n    Uptime: %s", 
mrb.getUptime()));
-                        sb.append(String.format("\n    Total: %s", 
mrb.getExchangesTotal()));
-                        sb.append(String.format("\n    Failed: %s", 
mrb.getExchangesFailed()));
-                        sb.append(String.format("\n    Inflight: %s", 
mrb.getExchangesInflight()));
-                        sb.append(String.format("\n    Mean Time: %s", 
TimeUtils.printDuration(mrb.getMeanProcessingTime())));
-                        sb.append(String.format("\n    Max Time: %s", 
TimeUtils.printDuration(mrb.getMaxProcessingTime())));
-                        sb.append(String.format("\n    Min Time: %s", 
TimeUtils.printDuration(mrb.getMinProcessingTime())));
-                        sb.append("\n");
-                    });
+                    .forEach(task::apply);
         }
-
-        return sb.toString();
     }
 
     private static boolean accept(ManagedRouteMBean mrb, String filter) {
diff --git 
a/core/camel-console/src/main/java/org/apache/camel/impl/console/TopDevConsole.java
 
b/core/camel-console/src/main/java/org/apache/camel/impl/console/TopDevConsole.java
index 1be105ab4c5..1507072bb12 100644
--- 
a/core/camel-console/src/main/java/org/apache/camel/impl/console/TopDevConsole.java
+++ 
b/core/camel-console/src/main/java/org/apache/camel/impl/console/TopDevConsole.java
@@ -21,6 +21,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Function;
 
 import org.apache.camel.Exchange;
 import org.apache.camel.ExtendedCamelContext;
@@ -35,6 +36,8 @@ import org.apache.camel.support.PatternHelper;
 import org.apache.camel.util.IOHelper;
 import org.apache.camel.util.StringHelper;
 import org.apache.camel.util.TimeUtils;
+import org.apache.camel.util.json.JsonObject;
+import org.apache.camel.util.json.Jsoner;
 
 @DevConsole("top")
 public class TopDevConsole extends AbstractDevConsole {
@@ -54,36 +57,18 @@ public class TopDevConsole extends AbstractDevConsole {
     }
 
     @Override
-    protected Object doCall(MediaType mediaType, Map<String, Object> options) {
+    protected String doCallText(Map<String, Object> options) {
         String path = (String) options.get(Exchange.HTTP_PATH);
         String subPath = path != null ? StringHelper.after(path, "/") : null;
         String filter = (String) options.get(FILTER);
         String limit = (String) options.get(LIMIT);
         final int max = limit == null ? Integer.MAX_VALUE : 
Integer.parseInt(limit);
 
-        // only text is supported
-        StringBuilder sb = new StringBuilder();
-
+        final StringBuilder sb = new StringBuilder();
         ManagedCamelContext mcc = 
getCamelContext().getExtension(ManagedCamelContext.class);
         if (mcc != null) {
             if (subPath == null || subPath.isBlank()) {
-                topRoutes(filter, max, sb, mcc);
-            } else {
-                topProcessors(filter, subPath, max, sb, mcc);
-            }
-        }
-
-        return sb.toString();
-    }
-
-    private void topRoutes(String filter, int max, StringBuilder sb, 
ManagedCamelContext mcc) {
-        List<Route> routes = getCamelContext().getRoutes();
-        routes.stream()
-                .map(route -> mcc.getManagedRoute(route.getRouteId()))
-                .filter(r -> acceptRoute(r, filter))
-                .sorted(TopDevConsole::top)
-                .limit(max)
-                .forEach(mrb -> {
+                Function<ManagedRouteMBean, Object> task = mrb -> {
                     if (sb.length() > 0) {
                         sb.append("\n");
                     }
@@ -101,30 +86,11 @@ public class TopDevConsole extends AbstractDevConsole {
                     sb.append(String.format("\n    Delta Time: %s", 
TimeUtils.printDuration(mrb.getDeltaProcessingTime())));
                     sb.append(String.format("\n    Total Time: %s", 
TimeUtils.printDuration(mrb.getTotalProcessingTime())));
                     sb.append("\n");
-                });
-    }
-
-    private void topProcessors(String filter, String subPath, int max, 
StringBuilder sb, ManagedCamelContext mcc) {
-        List<Route> routes = getCamelContext().getRoutes();
-        Collection<String> ids = new ArrayList<>();
-
-        routes.stream()
-                .map(route -> mcc.getManagedRoute(route.getRouteId()))
-                .filter(r -> acceptRoute(r, subPath))
-                .forEach(r -> {
-                    try {
-                        ids.addAll(r.processorIds());
-                    } catch (Exception e) {
-                        // ignore
-                    }
-                });
-
-        ids.stream()
-                .map(mcc::getManagedProcessor)
-                .filter(p -> acceptProcessor(p, filter))
-                .sorted(TopDevConsole::top)
-                .limit(max)
-                .forEach(mpb -> {
+                    return null;
+                };
+                topRoutes(filter, max, mcc, task);
+            } else {
+                Function<ManagedProcessorMBean, Object> task = mpb -> {
                     if (sb.length() > 0) {
                         sb.append("\n");
                     }
@@ -139,11 +105,11 @@ public class TopDevConsole extends AbstractDevConsole {
                                     .resolveResource(loc);
                             if (resource != null) {
                                 LineNumberReader reader = new 
LineNumberReader(resource.getReader());
-                                for (int i = 1; i < line + 2; i++) {
+                                for (int i = 1; i < line + 3; i++) {
                                     String t = reader.readLine();
                                     if (t != null) {
                                         int low = line - 2;
-                                        int high = line + 3;
+                                        int high = line + 4;
                                         if (i >= low && i <= high) {
                                             String arrow = i == line ? "-->" : 
"   ";
                                             code.append(String.format("\n      
  %s #%s %s", arrow, i, t));
@@ -156,8 +122,6 @@ public class TopDevConsole extends AbstractDevConsole {
                         } catch (Exception e) {
                             // ignore
                         }
-                        // load source code line
-
                     }
                     if (loc != null) {
                         sb.append(String.format("\n    Source: %s", loc));
@@ -174,7 +138,155 @@ public class TopDevConsole extends AbstractDevConsole {
                     sb.append(String.format("\n    Delta Time: %s", 
TimeUtils.printDuration(mpb.getDeltaProcessingTime())));
                     sb.append(String.format("\n    Total Time: %s", 
TimeUtils.printDuration(mpb.getTotalProcessingTime())));
                     sb.append("\n");
+                    return null;
+                };
+                topProcessors(filter, subPath, max, mcc, task);
+            }
+        }
+
+        return sb.toString();
+    }
+
+    @Override
+    protected JsonObject doCallJson(Map<String, Object> options) {
+        String path = (String) options.get(Exchange.HTTP_PATH);
+        String subPath = path != null ? StringHelper.after(path, "/") : null;
+        String filter = (String) options.get(FILTER);
+        String limit = (String) options.get(LIMIT);
+        final int max = limit == null ? Integer.MAX_VALUE : 
Integer.parseInt(limit);
+
+        final JsonObject root = new JsonObject();
+        final List<JsonObject> list = new ArrayList<>();
+
+        ManagedCamelContext mcc = 
getCamelContext().getExtension(ManagedCamelContext.class);
+        if (mcc != null) {
+            if (subPath == null || subPath.isBlank()) {
+                Function<ManagedRouteMBean, Object> task = mrb -> {
+                    JsonObject jo = new JsonObject();
+                    list.add(jo);
+
+                    jo.put("routeId", mrb.getRouteId());
+                    jo.put("from", mrb.getEndpointUri());
+                    if (mrb.getSourceLocation() != null) {
+                        jo.put("source", mrb.getSourceLocation());
+                    }
+                    jo.put("state", mrb.getState());
+                    jo.put("uptime", mrb.getUptime());
+                    JsonObject stats = new JsonObject();
+                    stats.put("exchangesTotal", mrb.getExchangesTotal());
+                    stats.put("exchangesFailed", mrb.getExchangesFailed());
+                    stats.put("exchangesInflight", mrb.getExchangesInflight());
+                    stats.put("meanProcessingTime", 
mrb.getMeanProcessingTime());
+                    stats.put("maxProcessingTime", mrb.getMaxProcessingTime());
+                    stats.put("minProcessingTime", mrb.getMinProcessingTime());
+                    stats.put("deltaProcessingTime", 
mrb.getDeltaProcessingTime());
+                    stats.put("totalProcessingTime", 
mrb.getTotalProcessingTime());
+                    jo.put("statistics", stats);
+                    return null;
+                };
+                topRoutes(filter, max, mcc, task);
+                root.put("routes", list);
+            } else {
+                Function<ManagedProcessorMBean, Object> task = mpb -> {
+                    JsonObject jo = new JsonObject();
+                    list.add(jo);
+
+                    jo.put("routeId", mpb.getRouteId());
+                    jo.put("processorId", mpb.getProcessorId());
+                    String loc = mpb.getSourceLocation();
+                    List<JsonObject> code = new ArrayList<>();
+                    if (loc != null && mpb.getSourceLineNumber() != null) {
+                        int line = mpb.getSourceLineNumber();
+                        try {
+                            Resource resource = 
getCamelContext().adapt(ExtendedCamelContext.class).getResourceLoader()
+                                    .resolveResource(loc);
+                            if (resource != null) {
+                                LineNumberReader reader = new 
LineNumberReader(resource.getReader());
+                                for (int i = 1; i < line + 3; i++) {
+                                    String t = reader.readLine();
+                                    if (t != null) {
+                                        int low = line - 2;
+                                        int high = line + 4;
+                                        if (i >= low && i <= high) {
+                                            JsonObject c = new JsonObject();
+                                            c.put("line", i);
+                                            if (line == i) {
+                                                c.put("match", true);
+                                            }
+                                            c.put("code", Jsoner.escape(t));
+                                            code.add(c);
+                                        }
+                                    }
+                                }
+                                IOHelper.close(reader);
+                            }
+                            loc += ":" + mpb.getSourceLineNumber();
+                        } catch (Exception e) {
+                            // ignore
+                        }
+                    }
+                    if (loc != null) {
+                        jo.put("location", loc);
+                        if (!code.isEmpty()) {
+                            jo.put("code", code);
+                        }
+                    }
+
+                    JsonObject stats = new JsonObject();
+                    stats.put("exchangesTotal", mpb.getExchangesTotal());
+                    stats.put("exchangesFailed", mpb.getExchangesFailed());
+                    stats.put("exchangesInflight", mpb.getExchangesInflight());
+                    stats.put("meanProcessingTime", 
mpb.getMeanProcessingTime());
+                    stats.put("maxProcessingTime", mpb.getMaxProcessingTime());
+                    stats.put("minProcessingTime", mpb.getMinProcessingTime());
+                    stats.put("deltaProcessingTime", 
mpb.getDeltaProcessingTime());
+                    stats.put("totalProcessingTime", 
mpb.getTotalProcessingTime());
+                    jo.put("statistics", stats);
+                    return null;
+                };
+                topProcessors(filter, subPath, max, mcc, task);
+                root.put("processors", list);
+            }
+        }
+
+        return root;
+    }
+
+    private void topRoutes(
+            String filter, int max, ManagedCamelContext mcc,
+            Function<ManagedRouteMBean, Object> task) {
+        List<Route> routes = getCamelContext().getRoutes();
+        routes.stream()
+                .map(route -> mcc.getManagedRoute(route.getRouteId()))
+                .filter(r -> acceptRoute(r, filter))
+                .sorted(TopDevConsole::top)
+                .limit(max)
+                .forEach(task::apply);
+    }
+
+    private void topProcessors(
+            String filter, String subPath, int max, ManagedCamelContext mcc,
+            Function<ManagedProcessorMBean, Object> task) {
+        List<Route> routes = getCamelContext().getRoutes();
+        Collection<String> ids = new ArrayList<>();
+
+        routes.stream()
+                .map(route -> mcc.getManagedRoute(route.getRouteId()))
+                .filter(r -> acceptRoute(r, subPath))
+                .forEach(r -> {
+                    try {
+                        ids.addAll(r.processorIds());
+                    } catch (Exception e) {
+                        // ignore
+                    }
                 });
+
+        ids.stream()
+                .map(mcc::getManagedProcessor)
+                .filter(p -> acceptProcessor(p, filter))
+                .sorted(TopDevConsole::top)
+                .limit(max)
+                .forEach(task::apply);
     }
 
     private static boolean acceptRoute(ManagedRouteMBean mrb, String filter) {
diff --git 
a/core/camel-console/src/test/java/org/apache/camel/impl/console/ContextDevConsoleTest.java
 
b/core/camel-console/src/test/java/org/apache/camel/impl/console/ContextDevConsoleTest.java
index ff0d9e2277f..0b389d11586 100644
--- 
a/core/camel-console/src/test/java/org/apache/camel/impl/console/ContextDevConsoleTest.java
+++ 
b/core/camel-console/src/test/java/org/apache/camel/impl/console/ContextDevConsoleTest.java
@@ -19,13 +19,14 @@ package org.apache.camel.impl.console;
 import org.apache.camel.ContextTestSupport;
 import org.apache.camel.ExtendedCamelContext;
 import org.apache.camel.console.DevConsole;
+import org.apache.camel.util.json.JsonObject;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
 public class ContextDevConsoleTest extends ContextTestSupport {
 
     @Test
-    public void testContext() throws Exception {
+    public void testContextTest() throws Exception {
         DevConsole con = 
context.adapt(ExtendedCamelContext.class).getDevConsoleResolver().resolveDevConsole("context");
         Assertions.assertNotNull(con);
         Assertions.assertEquals("camel", con.getGroup());
@@ -36,4 +37,17 @@ public class ContextDevConsoleTest extends 
ContextTestSupport {
         log.info(out);
         Assertions.assertTrue(out.contains(context.getName()));
     }
+
+    @Test
+    public void testContextJson() throws Exception {
+        DevConsole con = 
context.adapt(ExtendedCamelContext.class).getDevConsoleResolver().resolveDevConsole("context");
+        Assertions.assertNotNull(con);
+        Assertions.assertEquals("camel", con.getGroup());
+        Assertions.assertEquals("context", con.getId());
+
+        JsonObject out = (JsonObject) con.call(DevConsole.MediaType.JSON);
+        Assertions.assertNotNull(out);
+        Assertions.assertEquals(context.getName(), out.getString("name"));
+    }
+
 }
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-3x-upgrade-guide-3_18.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-3x-upgrade-guide-3_18.adoc
index 55287f244a9..51db9e10ebd 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-3x-upgrade-guide-3_18.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-3x-upgrade-guide-3_18.adoc
@@ -6,6 +6,11 @@ from both 3.0 to 3.1 and 3.1 to 3.2.
 
 == Upgrading Camel 3.17 to 3.18
 
+=== camel-console
+
+The `AbstractDevConsole` has changed the method `doCall` into two separate 
methods `doCallText` and `doCallJson`
+to better separate output between text and json based.
+
 === camel-karaf
 
 The `camel-milo` feature has been removed.
diff --git 
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/VertxHttpServer.java
 
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/VertxHttpServer.java
index a9be053cf6c..27912e6bc1c 100644
--- 
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/VertxHttpServer.java
+++ 
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/VertxHttpServer.java
@@ -52,6 +52,7 @@ import org.apache.camel.spi.CamelEvent;
 import org.apache.camel.support.SimpleEventNotifierSupport;
 import org.apache.camel.util.ObjectHelper;
 import org.apache.camel.util.StringHelper;
+import org.apache.camel.util.json.JsonObject;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -168,15 +169,27 @@ public final class VertxHttpServer {
         Route dev = router.route("/q/dev");
         dev.method(HttpMethod.GET);
         dev.produces("text/plain");
+        dev.produces("application/json");
         Route devSub = router.route("/q/dev/*");
         devSub.method(HttpMethod.GET);
         devSub.produces("text/plain");
+        devSub.produces("application/json");
 
         Handler<RoutingContext> handler = new Handler<RoutingContext>() {
             @Override
             public void handle(RoutingContext ctx) {
                 String acp = ctx.request().getHeader("Accept");
-                final boolean html = acp != null && acp.contains("html");
+                int pos1 = acp != null ? acp.indexOf("html") : 
Integer.MAX_VALUE;
+                if (pos1 == -1) {
+                    pos1 = Integer.MAX_VALUE;
+                }
+                int pos2 = acp != null ? acp.indexOf("json") : 
Integer.MAX_VALUE;
+                if (pos2 == -1) {
+                    pos2 = Integer.MAX_VALUE;
+                }
+                final boolean html = pos1 < pos2;
+                final boolean json = pos2 < pos1;
+                final DevConsole.MediaType mediaType = json ? 
DevConsole.MediaType.JSON : DevConsole.MediaType.TEXT;
 
                 ctx.response().putHeader("content-type", "text/plain");
 
@@ -193,32 +206,50 @@ public final class VertxHttpServer {
                 }
                 String id = s;
 
-                StringBuilder sb = new StringBuilder();
-
                 // index/home should list each console
                 if (id == null || id.isEmpty() || id.equals("index")) {
+                    StringBuilder sb = new StringBuilder();
+                    JsonObject root = new JsonObject();
+
                     dcr.stream().forEach(c -> {
-                        String link = c.getId();
-                        String eol = "\n";
-                        if (html) {
-                            link = "<a href=\"" + link + "\">" + c.getId() + 
"</a>";
-                            eol = "<br/>\n";
-                        }
-                        sb.append(link).append(": 
").append(c.getDescription()).append(eol);
-                        // special for top in processor mode
-                        if ("top".equals(c.getId())) {
-                            link = link.replace("top", "top/*");
-                            sb.append(link).append(": ").append("Display the 
top processors").append(eol);
+                        if (json) {
+                            JsonObject jo = new JsonObject();
+                            jo.put("id", c.getId());
+                            jo.put("displayName", c.getDisplayName());
+                            jo.put("description", c.getDescription());
+                            root.put(c.getId(), jo);
+                        } else {
+                            String link = c.getId();
+                            String eol = "\n";
+                            if (html) {
+                                link = "<a href=\"" + link + "\">" + c.getId() 
+ "</a>";
+                                eol = "<br/>\n";
+                            }
+                            sb.append(link).append(": 
").append(c.getDescription()).append(eol);
+                            // special for top in processor mode
+                            if ("top".equals(c.getId())) {
+                                link = link.replace("top", "top/*");
+                                sb.append(link).append(": ").append("Display 
the top processors").append(eol);
+                            }
                         }
                     });
-                    if (html) {
-                        ctx.response().putHeader("content-type", "text/html");
+                    if (sb.length() > 0) {
+                        String out = sb.toString();
+                        if (html) {
+                            ctx.response().putHeader("content-type", 
"text/html");
+                        }
+                        ctx.end(out);
+                    } else if (!root.isEmpty()) {
+                        ctx.response().putHeader("content-type", 
"application/json");
+                        String out = root.toJson();
+                        ctx.end(out);
                     }
-                    ctx.end(sb.toString());
                 } else {
                     Map<String, Object> params = new HashMap<>();
                     ctx.queryParams().forEach(params::put);
                     params.put(Exchange.HTTP_PATH, path);
+                    StringBuilder sb = new StringBuilder();
+                    JsonObject root = new JsonObject();
 
                     // sort according to index by given id
                     dcr.stream().sorted((o1, o2) -> {
@@ -227,19 +258,25 @@ public final class VertxHttpServer {
                         return Integer.compare(p1, p2);
                     }).forEach(c -> {
                         boolean include = "all".equals(id) || 
id.contains(c.getId());
-                        if (include && 
c.supportMediaType(DevConsole.MediaType.TEXT)) {
-                            String text = (String) 
c.call(DevConsole.MediaType.TEXT, params);
-                            if (text != null) {
+                        if (include && c.supportMediaType(mediaType)) {
+                            Object out = c.call(mediaType, params);
+                            if (out != null && mediaType == 
DevConsole.MediaType.TEXT) {
                                 sb.append(c.getDisplayName()).append(":");
                                 sb.append("\n\n");
-                                sb.append(text);
+                                sb.append(out);
                                 sb.append("\n\n");
+                            } else if (out != null && mediaType == 
DevConsole.MediaType.JSON) {
+                                root.put(c.getId(), out);
                             }
                         }
                     });
                     if (sb.length() > 0) {
                         String out = sb.toString();
                         ctx.end(out);
+                    } else if (!root.isEmpty()) {
+                        ctx.response().putHeader("content-type", 
"application/json");
+                        String out = root.toJson();
+                        ctx.end(out);
                     } else {
                         ctx.end("Developer Console not found: " + id);
                     }

Reply via email to