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 <claus.ib...@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"); + } + }