You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2021/12/30 12:04:28 UTC

[camel] 12/30: CAMEL-17384: Developer Console SPI

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

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

commit b27f2c403779f97924699b5a9779e08c1f8450f5
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon Dec 27 16:41:08 2021 +0100

    CAMEL-17384: Developer Console SPI
---
 .../main/java/org/apache/camel/CamelContext.java   | 10 +++
 .../apache/camel/console/DevConsoleRegistry.java   |  2 +-
 .../camel/impl/engine/AbstractCamelContext.java    | 19 +++++
 .../impl/console/DefaultDevConsoleRegistry.java    |  5 +-
 .../impl/console/DefaultDevConsolesLoader.java     |  5 ++
 .../camel/impl/ExtendedCamelContextConfigurer.java |  6 ++
 .../camel/impl/lw/LightweightCamelContext.java     | 10 +++
 .../impl/lw/LightweightRuntimeCamelContext.java    | 10 +++
 .../apache/camel/dsl/jbang/core/commands/Run.java  |  7 +-
 dsl/camel-kamelet-main/pom.xml                     |  8 ++
 .../java/org/apache/camel/main/KameletMain.java    | 10 +++
 .../org/apache/camel/main/VertxHttpServer.java     | 86 +++++++++++++++-------
 12 files changed, 149 insertions(+), 29 deletions(-)

diff --git a/core/camel-api/src/main/java/org/apache/camel/CamelContext.java b/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
index 74138f6..3193799 100644
--- a/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
+++ b/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
@@ -1187,6 +1187,16 @@ public interface CamelContext extends CamelContextLifecycle, RuntimeConfiguratio
     void setLoadHealthChecks(Boolean loadHealthChecks);
 
     /**
+     * Whether to load custom dev consoles by scanning classpath.
+     */
+    Boolean isLoadDevConsoles();
+
+    /**
+     * Whether to load custom dev consoles by scanning classpath.
+     */
+    void setLoadDevConsoles(Boolean loadDevConsoles);
+
+    /**
      * Whether or not type converter statistics is enabled.
      * <p/>
      * By default the type converter utilization statistics is disabled. <b>Notice:</b> If enabled then there is a
diff --git a/core/camel-api/src/main/java/org/apache/camel/console/DevConsoleRegistry.java b/core/camel-api/src/main/java/org/apache/camel/console/DevConsoleRegistry.java
index 03ecf79..4a160b9 100644
--- a/core/camel-api/src/main/java/org/apache/camel/console/DevConsoleRegistry.java
+++ b/core/camel-api/src/main/java/org/apache/camel/console/DevConsoleRegistry.java
@@ -40,7 +40,7 @@ public interface DevConsoleRegistry extends CamelContextAware, StaticService, Id
     /**
      * Service factory key.
      */
-    String FACTORY = "console/" + NAME;
+    String FACTORY = "dev-console/" + NAME;
 
     /**
      * Whether dev console is enabled globally
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
index 31306c3..99e7ae1 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
@@ -263,6 +263,7 @@ public abstract class AbstractCamelContext extends BaseService
     private Boolean disableJMX = Boolean.FALSE;
     private Boolean loadTypeConverters = Boolean.FALSE;
     private Boolean loadHealthChecks = Boolean.FALSE;
+    private Boolean loadDevConsoles = Boolean.FALSE;
     private Boolean typeConverterStatisticsEnabled = Boolean.FALSE;
     private Boolean dumpRoutes = Boolean.FALSE;
     private Boolean useMDCLogging = Boolean.FALSE;
@@ -2768,6 +2769,15 @@ public abstract class AbstractCamelContext extends BaseService
             }
             startupStepRecorder.endStep(step3);
         }
+        // ensure additional dev consoles is loaded
+        if (loadDevConsoles) {
+            StartupStep step4 = startupStepRecorder.beginStep(CamelContext.class, null, "Scan DevConsoles");
+            DevConsoleRegistry dcr = getExtension(DevConsoleRegistry.class);
+            if (dcr != null) {
+                dcr.loadDevConsoles();
+            }
+            startupStepRecorder.endStep(step4);
+        }
 
         // custom properties may use property placeholders so resolve those
         // early on
@@ -4218,6 +4228,15 @@ public abstract class AbstractCamelContext extends BaseService
         this.loadHealthChecks = loadHealthChecks;
     }
 
+    public Boolean isLoadDevConsoles() {
+        return loadDevConsoles != null && loadDevConsoles;
+    }
+
+    @Override
+    public void setLoadDevConsoles(Boolean loadDevConsoles) {
+        this.loadDevConsoles = loadDevConsoles;
+    }
+
     @Override
     public Boolean isTypeConverterStatisticsEnabled() {
         return typeConverterStatisticsEnabled != null && typeConverterStatisticsEnabled;
diff --git a/core/camel-console/src/main/java/org/apache/camel/impl/console/DefaultDevConsoleRegistry.java b/core/camel-console/src/main/java/org/apache/camel/impl/console/DefaultDevConsoleRegistry.java
index eeb2301..14eb111 100644
--- a/core/camel-console/src/main/java/org/apache/camel/impl/console/DefaultDevConsoleRegistry.java
+++ b/core/camel-console/src/main/java/org/apache/camel/impl/console/DefaultDevConsoleRegistry.java
@@ -153,8 +153,11 @@ public class DefaultDevConsoleRegistry extends ServiceSupport implements DevCons
             DefaultDevConsolesLoader loader = new DefaultDevConsolesLoader(camelContext);
             Collection<DevConsole> col = loader.loadDevConsoles();
 
-            // report how many health checks we have loaded
             if (col.size() > 0) {
+                // register the loaded consoles
+                for (DevConsole console : col) {
+                    register(console);
+                }
                 String time = TimeUtils.printDuration(watch.taken());
                 LOG.info("Dev consoles (scanned: {}) loaded in {}", col.size(), time);
             }
diff --git a/core/camel-console/src/main/java/org/apache/camel/impl/console/DefaultDevConsolesLoader.java b/core/camel-console/src/main/java/org/apache/camel/impl/console/DefaultDevConsolesLoader.java
index 0226551..da2c848 100644
--- a/core/camel-console/src/main/java/org/apache/camel/impl/console/DefaultDevConsolesLoader.java
+++ b/core/camel-console/src/main/java/org/apache/camel/impl/console/DefaultDevConsolesLoader.java
@@ -82,6 +82,11 @@ public class DefaultDevConsolesLoader {
         if (loc == null) {
             return false;
         }
+        if (loc.endsWith("default-registry")) {
+            // this is the registry so should be skipped
+            return false;
+        }
+
         return true;
     }
 
diff --git a/core/camel-core-engine/src/generated/java/org/apache/camel/impl/ExtendedCamelContextConfigurer.java b/core/camel-core-engine/src/generated/java/org/apache/camel/impl/ExtendedCamelContextConfigurer.java
index 0df43cb..31ab8e8 100644
--- a/core/camel-core-engine/src/generated/java/org/apache/camel/impl/ExtendedCamelContextConfigurer.java
+++ b/core/camel-core-engine/src/generated/java/org/apache/camel/impl/ExtendedCamelContextConfigurer.java
@@ -95,6 +95,8 @@ public class ExtendedCamelContextConfigurer extends org.apache.camel.support.com
         case "LanguageResolver": target.setLanguageResolver(property(camelContext, org.apache.camel.spi.LanguageResolver.class, value)); return true;
         case "lightweight":
         case "Lightweight": target.setLightweight(property(camelContext, boolean.class, value)); return true;
+        case "loaddevconsoles":
+        case "LoadDevConsoles": target.setLoadDevConsoles(property(camelContext, java.lang.Boolean.class, value)); return true;
         case "loadhealthchecks":
         case "LoadHealthChecks": target.setLoadHealthChecks(property(camelContext, java.lang.Boolean.class, value)); return true;
         case "loadtypeconverters":
@@ -280,6 +282,8 @@ public class ExtendedCamelContextConfigurer extends org.apache.camel.support.com
         case "LanguageResolver": return org.apache.camel.spi.LanguageResolver.class;
         case "lightweight":
         case "Lightweight": return boolean.class;
+        case "loaddevconsoles":
+        case "LoadDevConsoles": return java.lang.Boolean.class;
         case "loadhealthchecks":
         case "LoadHealthChecks": return java.lang.Boolean.class;
         case "loadtypeconverters":
@@ -466,6 +470,8 @@ public class ExtendedCamelContextConfigurer extends org.apache.camel.support.com
         case "LanguageResolver": return target.getLanguageResolver();
         case "lightweight":
         case "Lightweight": return target.isLightweight();
+        case "loaddevconsoles":
+        case "LoadDevConsoles": return target.isLoadDevConsoles();
         case "loadhealthchecks":
         case "LoadHealthChecks": return target.isLoadHealthChecks();
         case "loadtypeconverters":
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java
index ecc68de..41e15c4 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightCamelContext.java
@@ -901,6 +901,16 @@ public class LightweightCamelContext implements ExtendedCamelContext, CatalogCam
     }
 
     @Override
+    public Boolean isLoadDevConsoles() {
+        return delegate.isLoadDevConsoles();
+    }
+
+    @Override
+    public void setLoadDevConsoles(Boolean loadDevConsoles) {
+        delegate.setLoadDevConsoles(loadDevConsoles);
+    }
+
+    @Override
     public Boolean isDumpRoutes() {
         return delegate.isDumpRoutes();
     }
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java
index 0601169..49cf2d8 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/lw/LightweightRuntimeCamelContext.java
@@ -1201,6 +1201,16 @@ public class LightweightRuntimeCamelContext implements ExtendedCamelContext, Cat
     }
 
     @Override
+    public Boolean isLoadDevConsoles() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setLoadDevConsoles(Boolean loadDevConsoles) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public void setLoadHealthChecks(Boolean loadHealthChecks) {
         throw new UnsupportedOperationException();
     }
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java
index 655f73d..6fbfb1b 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java
@@ -85,6 +85,9 @@ class Run implements Callable<Integer> {
     @Option(names = { "--port" }, description = "Embeds a local HTTP server on this port")
     private int port;
 
+    @Option(names = { "--console" }, description = "Developer console at /dev on local HTTP server (port 8080 by default)")
+    private boolean console;
+
     @Override
     public Integer call() throws Exception {
         if (stopRequested) {
@@ -128,7 +131,6 @@ class Run implements Callable<Integer> {
         // turn off lightweight if we have routes reload enabled
         main.addInitialProperty("camel.main.routesReloadEnabled", reload ? "true" : "false");
 
-        // durations
         if (maxMessages > 0) {
             main.addInitialProperty("camel.main.durationMaxMessages", String.valueOf(maxMessages));
         }
@@ -141,6 +143,9 @@ class Run implements Callable<Integer> {
         if (port > 0) {
             main.addInitialProperty("camel.jbang.platform-http.port", String.valueOf(port));
         }
+        if (console) {
+            main.addInitialProperty("camel.jbang.console", "true");
+        }
 
         if (fileLock) {
             lockFile = createLockFile();
diff --git a/dsl/camel-kamelet-main/pom.xml b/dsl/camel-kamelet-main/pom.xml
index f70c5cd..daf5105 100644
--- a/dsl/camel-kamelet-main/pom.xml
+++ b/dsl/camel-kamelet-main/pom.xml
@@ -74,6 +74,14 @@
             <groupId>org.apache.camel</groupId>
             <artifactId>camel-catalog</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-platform-http-vertx</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-console</artifactId>
+        </dependency>
 
         <dependency>
             <groupId>org.junit.jupiter</groupId>
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java
index 9ade32a..924ba23 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java
@@ -166,6 +166,16 @@ public class KameletMain extends MainCommandLineSupport {
         if (port != null) {
             VertxHttpServer.registerServer(answer, Integer.parseInt(port.toString()));
         }
+        boolean console = "true".equals(getInitialProperties().get("camel.jbang.console"));
+        if (console && port == null) {
+            // use default port 8080 if console is enabled
+            VertxHttpServer.registerServer(answer, 8080);
+        }
+        if (console) {
+            // turn on developer console
+            answer.setLoadDevConsoles(true);
+            VertxHttpServer.registerConsole(answer);
+        }
 
         if (download) {
             try {
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 6aaf136..e2c9257 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
@@ -16,20 +16,25 @@
  */
 package org.apache.camel.main;
 
-import java.lang.reflect.Method;
 import java.util.HashSet;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
 
+import io.vertx.core.Handler;
+import io.vertx.core.http.HttpMethod;
+import io.vertx.ext.web.Route;
+import io.vertx.ext.web.RoutingContext;
 import org.apache.camel.CamelContext;
-import org.apache.camel.Component;
-import org.apache.camel.ExtendedCamelContext;
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.StartupListener;
+import org.apache.camel.component.platform.http.PlatformHttpComponent;
+import org.apache.camel.component.platform.http.vertx.VertxPlatformHttpRouter;
+import org.apache.camel.component.platform.http.vertx.VertxPlatformHttpServer;
+import org.apache.camel.component.platform.http.vertx.VertxPlatformHttpServerConfiguration;
+import org.apache.camel.console.DevConsole;
+import org.apache.camel.console.DevConsoleRegistry;
 import org.apache.camel.spi.CamelEvent;
-import org.apache.camel.support.ObjectHelper;
 import org.apache.camel.support.SimpleEventNotifierSupport;
-import org.apache.camel.util.ReflectionHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -41,6 +46,11 @@ public final class VertxHttpServer {
     private static final Logger LOG = LoggerFactory.getLogger(VertxHttpServer.class);
 
     private static final AtomicBoolean REGISTERED = new AtomicBoolean();
+    private static final AtomicBoolean CONSOLE = new AtomicBoolean();
+
+    private static VertxPlatformHttpRouter router;
+    private static VertxPlatformHttpServer server;
+    private static PlatformHttpComponent phc;
 
     private VertxHttpServer() {
     }
@@ -59,20 +69,13 @@ public final class VertxHttpServer {
 
     private static void doRegisterServer(CamelContext camelContext, int port) {
         try {
-            // must load via the classloader set on camel context that will have the classes on its classpath
-            Class<?> clazz = camelContext.getClassResolver()
-                    .resolveMandatoryClass(
-                            "org.apache.camel.component.platform.http.vertx.VertxPlatformHttpServerConfiguration");
-            Object config = clazz.getConstructors()[0].newInstance();
-            camelContext.adapt(ExtendedCamelContext.class).getBeanIntrospection()
-                    .setProperty(camelContext, config, "port", port);
-
-            clazz = camelContext.getClassResolver()
-                    .resolveMandatoryClass(
-                            "org.apache.camel.component.platform.http.vertx.VertxPlatformHttpServer");
-            Object server = clazz.getConstructors()[0].newInstance(config);
-
+            VertxPlatformHttpServerConfiguration config = new VertxPlatformHttpServerConfiguration();
+            config.setPort(port);
+            server = new VertxPlatformHttpServer(config);
             camelContext.addService(server);
+            server.start();
+            router = VertxPlatformHttpRouter.lookup(camelContext);
+            phc = camelContext.getComponent("platform-http", PlatformHttpComponent.class);
 
             // after camel is started then add event notifier
             camelContext.addStartupListener(new StartupListener() {
@@ -80,8 +83,6 @@ public final class VertxHttpServer {
                 public void onCamelContextStarted(CamelContext context, boolean alreadyStarted) throws Exception {
                     camelContext.getManagementStrategy().addEventNotifier(new SimpleEventNotifierSupport() {
 
-                        private volatile Component phc;
-                        private volatile Method method;
                         private Set<String> last;
 
                         @Override
@@ -92,11 +93,6 @@ public final class VertxHttpServer {
 
                         @Override
                         public void notify(CamelEvent event) throws Exception {
-                            if (method == null) {
-                                phc = camelContext.getComponent("platform-http", Component.class);
-                                method = ReflectionHelper.findMethod(phc.getClass(), "getHttpEndpoints");
-                            }
-
                             // when reloading then there may be more routes in the same batch, so we only want
                             // to log the summary at the end
                             if (event instanceof CamelEvent.RouteReloadedEvent) {
@@ -106,7 +102,7 @@ public final class VertxHttpServer {
                                 }
                             }
 
-                            Set<String> endpoints = (Set<String>) ObjectHelper.invokeMethodSafe(method, phc);
+                            Set<String> endpoints = phc.getHttpEndpoints();
                             if (endpoints.isEmpty()) {
                                 return;
                             }
@@ -131,4 +127,42 @@ public final class VertxHttpServer {
         }
     }
 
+    public static void registerConsole(CamelContext camelContext) {
+        if (CONSOLE.compareAndSet(false, true)) {
+            doRegisterConsole(camelContext);
+        }
+    }
+
+    private static void doRegisterConsole(CamelContext context) {
+        Route dev = router.route("/dev");
+        dev.method(HttpMethod.GET);
+        dev.handler(router.bodyHandler());
+        dev.handler(new Handler<RoutingContext>() {
+            @Override
+            public void handle(RoutingContext ctx) {
+                DevConsoleRegistry dcr = context.getExtension(DevConsoleRegistry.class);
+                if (dcr != null && dcr.isEnabled()) {
+                    StringBuilder sb = new StringBuilder();
+                    dcr.stream().forEach(c -> {
+                        if (c.supportMediaType(DevConsole.MediaType.TEXT)) {
+                            String text = (String) c.call(DevConsole.MediaType.TEXT);
+                            if (text != null) {
+                                sb.append(text);
+                                sb.append("\n\n");
+                            }
+                        }
+                    });
+                    if (sb.length() > 0) {
+                        ctx.end(sb.toString());
+                    } else {
+                        ctx.end("Developer Console is not enabled");
+                    }
+                } else {
+                    ctx.end("Developer Console is not enabled");
+                }
+            }
+        });
+        phc.addHttpEndpoint("/dev");
+    }
+
 }