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

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

commit 8fc7653ceda00f14eb7228b25305ea73aaf6b026
Author: Claus Ibsen <[email protected]>
AuthorDate: Tue Jul 29 16:01:37 2025 +0200

    CAMEL-22285: platform-http-main - Dev consoles should be registered as 
management endpoints
---
 .../http/main/DefaultMainHttpServerFactory.java    |  19 +-
 .../platform/http/main/MainHttpServer.java         |   2 +
 .../platform/http/main/ManagementHttpServer.java   | 254 +++++++++++++++++++++
 .../http/main/MainHttpFakeHealthCheck.java         |   2 +-
 .../http/main/MainHttpServerRouteTest.java         |   1 -
 ...rverTest.java => ManagementHttpServerTest.java} |   5 +-
 ...entServerConfigurationPropertiesConfigurer.java |  21 ++
 .../camel-main-configuration-metadata.json         |   5 +-
 core/camel-main/src/main/docs/main.adoc            |   7 +-
 .../org/apache/camel/main/BaseMainSupport.java     |  12 +-
 ...ttpManagementServerConfigurationProperties.java |  74 +++++-
 11 files changed, 372 insertions(+), 30 deletions(-)

diff --git 
a/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/DefaultMainHttpServerFactory.java
 
b/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/DefaultMainHttpServerFactory.java
index faf85922e4f..0ae2a43f927 100644
--- 
a/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/DefaultMainHttpServerFactory.java
+++ 
b/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/DefaultMainHttpServerFactory.java
@@ -67,20 +67,9 @@ public class DefaultMainHttpServerFactory implements 
CamelContextAware, MainHttp
             dir = TempDirHelper.resolveTempDir(camelContext, null, dir);
             server.setFileUploadDirectory(dir);
         }
-        server.setInfoEnabled(configuration.isInfoEnabled());
         server.setStaticEnabled(configuration.isStaticEnabled());
         server.setStaticContextPath(configuration.getStaticContextPath());
         server.setStaticSourceDir(configuration.getStaticSourceDir());
-        server.setDevConsoleEnabled(configuration.isDevConsoleEnabled());
-        server.setHealthCheckEnabled(configuration.isHealthCheckEnabled());
-        server.setHealthPath(configuration.getHealthPath());
-        server.setJolokiaEnabled(configuration.isJolokiaEnabled());
-        server.setJolokiaPath(configuration.getJolokiaPath());
-        server.setMetricsEnabled(configuration.isMetricsEnabled());
-        server.setUploadEnabled(configuration.isUploadEnabled());
-        server.setUploadSourceDir(configuration.getUploadSourceDir());
-        server.setDownloadEnabled(configuration.isDownloadEnabled());
-        server.setSendEnabled(configuration.isSendEnabled());
 
         if (configuration.isAuthenticationEnabled()) {
             configureAuthentication(server, configuration);
@@ -98,9 +87,7 @@ public class DefaultMainHttpServerFactory implements 
CamelContextAware, MainHttp
         server.setHost(configuration.getHost());
         server.setPort(configuration.getPort());
         server.setPath(configuration.getPath());
-        if (configuration.getMaxBodySize() != null) {
-            server.setMaxBodySize(configuration.getMaxBodySize());
-        }
+
         
server.setUseGlobalSslContextParameters(configuration.isUseGlobalSslContextParameters());
         server.setInfoEnabled(configuration.isInfoEnabled());
         server.setDevConsoleEnabled(configuration.isDevConsoleEnabled());
@@ -109,6 +96,10 @@ public class DefaultMainHttpServerFactory implements 
CamelContextAware, MainHttp
         server.setJolokiaEnabled(configuration.isJolokiaEnabled());
         server.setJolokiaPath(configuration.getJolokiaPath());
         server.setMetricsEnabled(configuration.isMetricsEnabled());
+        server.setUploadEnabled(configuration.isUploadEnabled());
+        server.setUploadSourceDir(configuration.getUploadSourceDir());
+        server.setDownloadEnabled(configuration.isDownloadEnabled());
+        server.setSendEnabled(configuration.isSendEnabled());
 
         if (configuration.isAuthenticationEnabled()) {
             configureAuthentication(server, configuration);
diff --git 
a/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/MainHttpServer.java
 
b/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/MainHttpServer.java
index d05de720fc9..e18de965004 100644
--- 
a/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/MainHttpServer.java
+++ 
b/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/MainHttpServer.java
@@ -38,6 +38,7 @@ import 
org.apache.camel.component.platform.http.vertx.VertxPlatformHttpServer;
 import 
org.apache.camel.component.platform.http.vertx.VertxPlatformHttpServerConfiguration;
 import org.apache.camel.support.ResolverHelper;
 import org.apache.camel.support.jsse.SSLContextParameters;
+import org.apache.camel.support.service.ServiceHelper;
 import org.apache.camel.support.service.ServiceSupport;
 import org.apache.camel.util.FileUtil;
 import org.apache.camel.util.IOHelper;
@@ -214,6 +215,7 @@ public class MainHttpServer extends ServiceSupport 
implements CamelContextAware,
     @Override
     protected void doStart() throws Exception {
         ObjectHelper.notNull(camelContext, "CamelContext");
+        ServiceHelper.startService(server);
         String routerName = 
VertxPlatformHttpRouter.getRouterNameFromPort(getPort());
         router = VertxPlatformHttpRouter.lookup(camelContext, routerName);
         platformHttpComponent = camelContext.getComponent("platform-http", 
PlatformHttpComponent.class);
diff --git 
a/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/ManagementHttpServer.java
 
b/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/ManagementHttpServer.java
index 9b873b7f6d1..a4dc1104dbd 100644
--- 
a/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/ManagementHttpServer.java
+++ 
b/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/ManagementHttpServer.java
@@ -16,6 +16,9 @@
  */
 package org.apache.camel.component.platform.http.main;
 
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
 import java.lang.management.ManagementFactory;
 import java.lang.management.RuntimeMXBean;
 import java.util.ArrayList;
@@ -28,12 +31,14 @@ import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
+import java.util.StringJoiner;
 import java.util.TreeSet;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
 import io.vertx.core.Handler;
 import io.vertx.core.http.HttpMethod;
+import io.vertx.ext.web.RequestBody;
 import io.vertx.ext.web.Route;
 import io.vertx.ext.web.RoutingContext;
 import io.vertx.ext.web.handler.BodyHandler;
@@ -64,15 +69,23 @@ import org.apache.camel.health.HealthCheckHelper;
 import org.apache.camel.health.HealthCheckRegistry;
 import org.apache.camel.http.base.HttpProtocolHeaderFilterStrategy;
 import org.apache.camel.spi.HeaderFilterStrategy;
+import org.apache.camel.spi.PackageScanResourceResolver;
 import org.apache.camel.spi.ReloadStrategy;
+import org.apache.camel.spi.Resource;
+import org.apache.camel.spi.ResourceLoader;
 import org.apache.camel.support.CamelContextHelper;
 import org.apache.camel.support.EndpointHelper;
 import org.apache.camel.support.ExceptionHelper;
+import org.apache.camel.support.LoggerHelper;
 import org.apache.camel.support.MessageHelper;
+import org.apache.camel.support.PluginHelper;
 import org.apache.camel.support.ResolverHelper;
 import org.apache.camel.support.jsse.SSLContextParameters;
 import org.apache.camel.support.service.ServiceHelper;
 import org.apache.camel.support.service.ServiceSupport;
+import org.apache.camel.util.AntPathMatcher;
+import org.apache.camel.util.FileUtil;
+import org.apache.camel.util.IOHelper;
 import org.apache.camel.util.ObjectHelper;
 import org.apache.camel.util.StopWatch;
 import org.apache.camel.util.StringHelper;
@@ -110,6 +123,9 @@ public class ManagementHttpServer extends ServiceSupport 
implements CamelContext
     private boolean metricsEnabled;
     private String healthPath;
     private String jolokiaPath;
+    private boolean uploadEnabled;
+    private String uploadSourceDir;
+    private boolean downloadEnabled;
     private boolean sendEnabled;
 
     @Override
@@ -282,6 +298,42 @@ public class ManagementHttpServer extends ServiceSupport 
implements CamelContext
         
configuration.setUseGlobalSslContextParameters(useGlobalSslContextParameters);
     }
 
+    @ManagedAttribute(description = "Whether file upload is enabled (only for 
development) (q/upload)")
+    public boolean isUploadEnabled() {
+        return uploadEnabled;
+    }
+
+    /**
+     * Whether file upload is enabled (only for development) (q/upload)
+     */
+    public void setUploadEnabled(boolean uploadEnabled) {
+        this.uploadEnabled = uploadEnabled;
+    }
+
+    @ManagedAttribute(description = "Directory for upload.")
+    public String getUploadSourceDir() {
+        return uploadSourceDir;
+    }
+
+    /**
+     * Directory for upload.
+     */
+    public void setUploadSourceDir(String uploadSourceDir) {
+        this.uploadSourceDir = uploadSourceDir;
+    }
+
+    @ManagedAttribute(description = "Whether file download is enabled 
(q/download)")
+    public boolean isDownloadEnabled() {
+        return downloadEnabled;
+    }
+
+    /**
+     * Whether file download is enabled (q/download)
+     */
+    public void setDownloadEnabled(boolean downloadEnabled) {
+        this.downloadEnabled = downloadEnabled;
+    }
+
     @ManagedAttribute(description = "Whether send message is enabled (q/send)")
     public boolean isSendEnabled() {
         return sendEnabled;
@@ -379,6 +431,15 @@ public class ManagementHttpServer extends ServiceSupport 
implements CamelContext
         if (jolokiaEnabled) {
             setupJolokia();
         }
+        if (uploadEnabled) {
+            if (uploadSourceDir == null) {
+                throw new IllegalArgumentException("UploadSourceDir must be 
configured when uploadEnabled=true");
+            }
+            setupUploadConsole(uploadSourceDir);
+        }
+        if (downloadEnabled) {
+            setupDownloadConsole();
+        }
         if (sendEnabled) {
             setupSendConsole();
         }
@@ -597,6 +658,199 @@ public class ManagementHttpServer extends ServiceSupport 
implements CamelContext
                 "text/plain,application/json", null);
     }
 
+    protected void setupUploadConsole(final String dir) {
+        final Route upload = router.route("/q/upload/:filename")
+                .method(HttpMethod.PUT)
+                // need body handler to handle file uploads
+                .handler(BodyHandler.create(true));
+
+        final Route uploadDelete = router.route("/q/upload/:filename");
+        uploadDelete.method(HttpMethod.DELETE);
+
+        Handler<RoutingContext> handler = new Handler<RoutingContext>() {
+            @Override
+            public void handle(RoutingContext ctx) {
+                String name = ctx.pathParam("filename");
+                if (name == null) {
+                    ctx.response().setStatusCode(400);
+                    ctx.end();
+                    return;
+                }
+
+                int status = 200;
+                boolean delete = HttpMethod.DELETE == ctx.request().method();
+                if (delete) {
+                    if (name.contains("*")) {
+                        if (name.equals("*")) {
+                            name = "**";
+                        }
+                        AntPathMatcher match = AntPathMatcher.INSTANCE;
+                        File[] files = new File(dir).listFiles();
+                        if (files != null) {
+                            for (File f : files) {
+                                if (f.getName().startsWith(".") || 
f.isHidden()) {
+                                    continue;
+                                }
+                                if (match.match(name, f.getName())) {
+                                    LOG.info("Deleting file: {}/{}", dir, 
name);
+                                    FileUtil.deleteFile(f);
+                                }
+                            }
+                        }
+                    } else {
+                        File f = new File(dir, name);
+                        if (f.exists() && f.isFile()) {
+                            LOG.info("Deleting file: {}/{}", dir, name);
+                            FileUtil.deleteFile(f);
+                        }
+                    }
+                } else {
+                    File f = new File(dir, name);
+                    boolean exists = f.isFile() && f.exists();
+                    LOG.info("{} file: {}/{}", exists ? "Updating" : 
"Creating", dir, name);
+
+                    File tmp = new File(dir, name + ".tmp");
+                    FileOutputStream fos = null;
+                    try {
+                        fos = new FileOutputStream(tmp, false);
+                        RequestBody rb = ctx.body();
+                        IOHelper.writeText(rb.asString(), fos);
+
+                        FileUtil.renameFileUsingCopy(tmp, f);
+                        FileUtil.deleteFile(tmp);
+                    } catch (Exception e) {
+                        // some kind of error
+                        LOG.warn("Error saving file: {}/{} due to: {}", dir, 
name, e.getMessage(), e);
+                        status = 500;
+                    } finally {
+                        IOHelper.close(fos);
+                        FileUtil.deleteFile(tmp);
+                    }
+                }
+
+                ctx.response().setStatusCode(status);
+                ctx.end();
+            }
+        };
+        // use blocking handler as the task can take longer time to complete
+        upload.handler(new BlockingHandlerDecorator(handler, true));
+        uploadDelete.handler(new BlockingHandlerDecorator(handler, true));
+
+        platformHttpComponent.addHttpManagementEndpoint("/q/upload", 
"PUT,DELETE",
+                "multipart/form-data", null, null);
+    }
+
+    protected void setupDownloadConsole() {
+        final Route download = router.route("/q/download/*")
+                .produces("text/plain")
+                .produces("application/octet-stream")
+                .method(HttpMethod.GET);
+
+        final AntPathMatcher matcher = AntPathMatcher.INSTANCE;
+        Handler<RoutingContext> handler = new Handler<RoutingContext>() {
+            @Override
+            public void handle(RoutingContext ctx) {
+                String name = StringHelper.after(ctx.normalizedPath(), 
"/q/download/");
+                boolean cp = "true".equals(ctx.queryParams().get("classpath"));
+                if (name == null || name.isBlank() || matcher.isPattern(name)) 
{
+                    Set<String> names = new TreeSet<>();
+                    if (cp) {
+                        // also look inside classpath
+                        PackageScanResourceResolver resolver = 
PluginHelper.getPackageScanResourceResolver(camelContext);
+                        
resolver.addClassLoader(camelContext.getApplicationContextClassLoader());
+                        try {
+                            String pattern = "**/*";
+                            if (name != null && !name.isBlank()) {
+                                pattern = "**/" + name;
+                            }
+                            for (Resource res : 
resolver.findResources(pattern)) {
+                                String loc = res.getLocation();
+                                loc = LoggerHelper.sourceNameOnly(loc);
+                                names.add(loc);
+                            }
+                        } catch (Exception e) {
+                            // ignore
+                        }
+                    }
+                    // always include routes
+                    for (org.apache.camel.Route route : 
camelContext.getRoutes()) {
+                        String loc = route.getSourceLocation();
+                        if (loc != null) {
+                            loc = LoggerHelper.sourceNameOnly(loc);
+                            if (name == null || name.isBlank() || 
matcher.match(name, loc)) {
+                                names.add(loc);
+                            }
+                        }
+                    }
+
+                    String acp = ctx.request().getHeader("Accept");
+                    boolean html = acp != null && acp.contains("html");
+                    StringJoiner sj;
+                    if (html) {
+                        String prefix = 
StringHelper.after(ctx.normalizedPath(), "/q/download/");
+                        if (prefix == null) {
+                            prefix = "/q/download/";
+                        } else {
+                            prefix = "";
+                        }
+                        ctx.response().putHeader("Content-Type", "text/html");
+                        sj = new StringJoiner("<br/>");
+                        for (String n : names) {
+                            sj.add("<a href=" + prefix + n + ">" + n + "</a>");
+                        }
+                    } else {
+                        ctx.response().putHeader("Content-Type", "text/plain");
+                        sj = new StringJoiner("\n");
+                        names.forEach(sj::add);
+                    }
+                    ctx.response().setStatusCode(200);
+                    ctx.end(sj.toString());
+                } else {
+                    // load file as resource (try both classpath and file)
+                    ResourceLoader loader = 
PluginHelper.getResourceLoader(camelContext);
+                    Resource res = loader.resolveResource("classpath:" + name);
+                    if (res == null || !res.exists()) {
+                        // attempt without path
+                        res = loader.resolveResource("classpath:" + 
FileUtil.stripPath(name));
+                    }
+                    if (res == null || !res.exists()) {
+                        for (org.apache.camel.Route route : 
camelContext.getRoutes()) {
+                            String loc = route.getSourceLocation();
+                            if (loc != null) {
+                                loc = LoggerHelper.sourceNameOnly(loc);
+                                if (matcher.match(name, loc)) {
+                                    res = route.getSourceResource();
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                    if (res != null && res.exists()) {
+                        ctx.response().putHeader("Content-Type", 
"application/octet-stream");
+                        ctx.response().putHeader("Content-Disposition",
+                                "attachment; filename=\"" + 
FileUtil.stripPath(name) + "\"");
+                        ctx.response().setStatusCode(200);
+                        String data = null;
+                        try {
+                            data = IOHelper.loadText(res.getInputStream());
+                        } catch (IOException e) {
+                            // ignore
+                        }
+                        ctx.end(data);
+                    } else {
+                        ctx.response().setStatusCode(204);
+                        ctx.end();
+                    }
+                }
+            }
+        };
+        // use blocking handler as the task can take longer time to complete
+        download.handler(new BlockingHandlerDecorator(handler, true));
+
+        platformHttpComponent.addHttpManagementEndpoint("/q/download", "GET",
+                null, "text/plain,application/octet-stream", null);
+    }
+
     protected void setupSendConsole() {
         final Route send = router.route("/q/send/")
                 .produces("application/json")
diff --git 
a/components/camel-platform-http-main/src/test/java/org/apache/camel/component/platform/http/main/MainHttpFakeHealthCheck.java
 
b/components/camel-platform-http-main/src/test/java/org/apache/camel/component/platform/http/main/MainHttpFakeHealthCheck.java
index 5165c1f0284..e63537c399e 100644
--- 
a/components/camel-platform-http-main/src/test/java/org/apache/camel/component/platform/http/main/MainHttpFakeHealthCheck.java
+++ 
b/components/camel-platform-http-main/src/test/java/org/apache/camel/component/platform/http/main/MainHttpFakeHealthCheck.java
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.camel.component.platform.http.main;
 
 import java.util.Map;
@@ -23,6 +22,7 @@ import org.apache.camel.health.HealthCheckResultBuilder;
 import org.apache.camel.impl.health.AbstractHealthCheck;
 
 public class MainHttpFakeHealthCheck extends AbstractHealthCheck {
+
     protected MainHttpFakeHealthCheck() {
         super("camel", "consumer:fake");
     }
diff --git 
a/components/camel-platform-http-main/src/test/java/org/apache/camel/component/platform/http/main/MainHttpServerRouteTest.java
 
b/components/camel-platform-http-main/src/test/java/org/apache/camel/component/platform/http/main/MainHttpServerRouteTest.java
index 640ee0b0278..2998a7b3bca 100644
--- 
a/components/camel-platform-http-main/src/test/java/org/apache/camel/component/platform/http/main/MainHttpServerRouteTest.java
+++ 
b/components/camel-platform-http-main/src/test/java/org/apache/camel/component/platform/http/main/MainHttpServerRouteTest.java
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.camel.component.platform.http.main;
 
 import java.net.URI;
diff --git 
a/components/camel-platform-http-main/src/test/java/org/apache/camel/component/platform/http/main/MainHttpServerTest.java
 
b/components/camel-platform-http-main/src/test/java/org/apache/camel/component/platform/http/main/ManagementHttpServerTest.java
similarity index 95%
rename from 
components/camel-platform-http-main/src/test/java/org/apache/camel/component/platform/http/main/MainHttpServerTest.java
rename to 
components/camel-platform-http-main/src/test/java/org/apache/camel/component/platform/http/main/ManagementHttpServerTest.java
index 7c5a552079c..46600a4aeae 100644
--- 
a/components/camel-platform-http-main/src/test/java/org/apache/camel/component/platform/http/main/MainHttpServerTest.java
+++ 
b/components/camel-platform-http-main/src/test/java/org/apache/camel/component/platform/http/main/ManagementHttpServerTest.java
@@ -14,7 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.camel.component.platform.http.main;
 
 import java.io.IOException;
@@ -30,7 +29,7 @@ import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
-class MainHttpServerTest {
+class ManagementHttpServerTest {
 
     private CamelContext camelContext;
 
@@ -38,7 +37,7 @@ class MainHttpServerTest {
 
     @Test
     public void statusIsNotSatisfied() throws IOException, 
InterruptedException {
-        MainHttpServer server = new MainHttpServer();
+        ManagementHttpServer server = new ManagementHttpServer();
 
         camelContext = new DefaultCamelContext();
         server.setCamelContext(camelContext);
diff --git 
a/core/camel-main/src/generated/java/org/apache/camel/main/HttpManagementServerConfigurationPropertiesConfigurer.java
 
b/core/camel-main/src/generated/java/org/apache/camel/main/HttpManagementServerConfigurationPropertiesConfigurer.java
index a2f420a87d2..97418f57cfa 100644
--- 
a/core/camel-main/src/generated/java/org/apache/camel/main/HttpManagementServerConfigurationPropertiesConfigurer.java
+++ 
b/core/camel-main/src/generated/java/org/apache/camel/main/HttpManagementServerConfigurationPropertiesConfigurer.java
@@ -26,6 +26,7 @@ public class 
HttpManagementServerConfigurationPropertiesConfigurer extends org.a
         map.put("AuthenticationPath", java.lang.String.class);
         map.put("BasicPropertiesFile", java.lang.String.class);
         map.put("DevConsoleEnabled", boolean.class);
+        map.put("DownloadEnabled", boolean.class);
         map.put("Enabled", boolean.class);
         map.put("HealthCheckEnabled", boolean.class);
         map.put("HealthPath", java.lang.String.class);
@@ -40,6 +41,8 @@ public class 
HttpManagementServerConfigurationPropertiesConfigurer extends org.a
         map.put("Path", java.lang.String.class);
         map.put("Port", int.class);
         map.put("SendEnabled", boolean.class);
+        map.put("UploadEnabled", boolean.class);
+        map.put("UploadSourceDir", java.lang.String.class);
         map.put("UseGlobalSslContextParameters", boolean.class);
         ALL_OPTIONS = map;
     }
@@ -56,6 +59,8 @@ public class 
HttpManagementServerConfigurationPropertiesConfigurer extends org.a
         case "basicPropertiesFile": 
target.setBasicPropertiesFile(property(camelContext, java.lang.String.class, 
value)); return true;
         case "devconsoleenabled":
         case "devConsoleEnabled": 
target.setDevConsoleEnabled(property(camelContext, boolean.class, value)); 
return true;
+        case "downloadenabled":
+        case "downloadEnabled": 
target.setDownloadEnabled(property(camelContext, boolean.class, value)); return 
true;
         case "enabled": target.setEnabled(property(camelContext, 
boolean.class, value)); return true;
         case "healthcheckenabled":
         case "healthCheckEnabled": 
target.setHealthCheckEnabled(property(camelContext, boolean.class, value)); 
return true;
@@ -80,6 +85,10 @@ public class 
HttpManagementServerConfigurationPropertiesConfigurer extends org.a
         case "port": target.setPort(property(camelContext, int.class, value)); 
return true;
         case "sendenabled":
         case "sendEnabled": target.setSendEnabled(property(camelContext, 
boolean.class, value)); return true;
+        case "uploadenabled":
+        case "uploadEnabled": target.setUploadEnabled(property(camelContext, 
boolean.class, value)); return true;
+        case "uploadsourcedir":
+        case "uploadSourceDir": 
target.setUploadSourceDir(property(camelContext, java.lang.String.class, 
value)); return true;
         case "useglobalsslcontextparameters":
         case "useGlobalSslContextParameters": 
target.setUseGlobalSslContextParameters(property(camelContext, boolean.class, 
value)); return true;
         default: return false;
@@ -102,6 +111,8 @@ public class 
HttpManagementServerConfigurationPropertiesConfigurer extends org.a
         case "basicPropertiesFile": return java.lang.String.class;
         case "devconsoleenabled":
         case "devConsoleEnabled": return boolean.class;
+        case "downloadenabled":
+        case "downloadEnabled": return boolean.class;
         case "enabled": return boolean.class;
         case "healthcheckenabled":
         case "healthCheckEnabled": return boolean.class;
@@ -126,6 +137,10 @@ public class 
HttpManagementServerConfigurationPropertiesConfigurer extends org.a
         case "port": return int.class;
         case "sendenabled":
         case "sendEnabled": return boolean.class;
+        case "uploadenabled":
+        case "uploadEnabled": return boolean.class;
+        case "uploadsourcedir":
+        case "uploadSourceDir": return java.lang.String.class;
         case "useglobalsslcontextparameters":
         case "useGlobalSslContextParameters": return boolean.class;
         default: return null;
@@ -144,6 +159,8 @@ public class 
HttpManagementServerConfigurationPropertiesConfigurer extends org.a
         case "basicPropertiesFile": return target.getBasicPropertiesFile();
         case "devconsoleenabled":
         case "devConsoleEnabled": return target.isDevConsoleEnabled();
+        case "downloadenabled":
+        case "downloadEnabled": return target.isDownloadEnabled();
         case "enabled": return target.isEnabled();
         case "healthcheckenabled":
         case "healthCheckEnabled": return target.isHealthCheckEnabled();
@@ -168,6 +185,10 @@ public class 
HttpManagementServerConfigurationPropertiesConfigurer extends org.a
         case "port": return target.getPort();
         case "sendenabled":
         case "sendEnabled": return target.isSendEnabled();
+        case "uploadenabled":
+        case "uploadEnabled": return target.isUploadEnabled();
+        case "uploadsourcedir":
+        case "uploadSourceDir": return target.getUploadSourceDir();
         case "useglobalsslcontextparameters":
         case "useGlobalSslContextParameters": return 
target.isUseGlobalSslContextParameters();
         default: return null;
diff --git 
a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
 
b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
index 0fe6ab967ee..66eff52bf6b 100644
--- 
a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
+++ 
b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
@@ -195,6 +195,7 @@
     { "name": "camel.management.authenticationPath", "description": "Set HTTP 
url path of embedded server that is protected by authentication 
configuration.", "sourceType": 
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type": 
"string", "javaType": "java.lang.String" },
     { "name": "camel.management.basicPropertiesFile", "description": "Name of 
the file that contains basic authentication info for Vert.x file auth 
provider.", "sourceType": 
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type": 
"string", "javaType": "java.lang.String" },
     { "name": "camel.management.devConsoleEnabled", "description": "Whether to 
enable developer console (not intended for production use). Dev console must 
also be enabled on CamelContext. For example by setting 
camel.context.dev-console=true in application.properties, or via code 
camelContext.setDevConsole(true); If enabled then you can access a basic 
developer console on context-path: \/q\/dev.", "sourceType": 
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type": 
[...]
+    { "name": "camel.management.downloadEnabled", "description": "Whether to 
enable file download via HTTP. This makes it possible to browse and download 
resource source files such as Camel XML or YAML routes. Only enable this for 
development, troubleshooting or special situations for management and 
monitoring.", "sourceType": 
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type": 
"boolean", "javaType": "boolean", "defaultValue": "false" },
     { "name": "camel.management.enabled", "description": "Whether embedded 
HTTP server is enabled. By default, the server is not enabled.", "sourceType": 
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type": 
"boolean", "javaType": "boolean", "defaultValue": "false" },
     { "name": "camel.management.healthCheckEnabled", "description": "Whether 
to enable health-check console. If enabled then you can access health-check 
status on context-path: \/q\/health (default)", "sourceType": 
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type": 
"boolean", "javaType": "boolean", "defaultValue": "false" },
     { "name": "camel.management.healthPath", "description": "The path endpoint 
used to expose the health status", "sourceType": 
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type": 
"string", "javaType": "java.lang.String", "defaultValue": "\/observe\/health" },
@@ -207,8 +208,10 @@
     { "name": "camel.management.jwtKeystoreType", "description": "Type of the 
keystore used for JWT tokens validation (jks, pkcs12, etc.).", "sourceType": 
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type": 
"string", "javaType": "java.lang.String" },
     { "name": "camel.management.metricsEnabled", "description": "Whether to 
enable metrics. If enabled then you can access metrics on context-path: 
\/q\/metrics (default)", "sourceType": 
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type": 
"boolean", "javaType": "boolean", "defaultValue": "false" },
     { "name": "camel.management.path", "description": "Context-path to use for 
embedded HTTP server", "sourceType": 
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type": 
"string", "javaType": "java.lang.String", "defaultValue": "\/" },
-    { "name": "camel.management.port", "description": "Port to use for binding 
embedded HTTP server", "sourceType": 
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type": 
"integer", "javaType": "int", "defaultValue": 9876 },
+    { "name": "camel.management.port", "description": "Port to use for binding 
embedded HTTP server", "sourceType": 
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type": 
"integer", "javaType": "int", "defaultValue": 8080 },
     { "name": "camel.management.sendEnabled", "description": "Whether to 
enable sending messages to Camel via HTTP. This makes it possible to use Camel 
to send messages to Camel endpoint URIs via HTTP.", "sourceType": 
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type": 
"boolean", "javaType": "boolean", "defaultValue": "false" },
+    { "name": "camel.management.uploadEnabled", "description": "Whether to 
enable file upload via HTTP (not intended for production use). This 
functionality is for development to be able to reload Camel routes and code 
with source changes (if reload is enabled). If enabled then you can 
upload\/delete files via HTTP PUT\/DELETE on context-path: \/q\/upload\/{name}. 
You must also configure the uploadSourceDir option.", "sourceType": 
"org.apache.camel.main.HttpManagementServerConfigurationP [...]
+    { "name": "camel.management.uploadSourceDir", "description": "Source 
directory when upload is enabled.", "sourceType": 
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type": 
"string", "javaType": "java.lang.String" },
     { "name": "camel.management.useGlobalSslContextParameters", "description": 
"Whether to use global SSL configuration for securing the embedded HTTP 
server.", "sourceType": 
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type": 
"boolean", "javaType": "boolean", "defaultValue": "false" },
     { "name": "camel.metrics.baseEndpointURIExchangeEventNotifier", 
"description": "Whether to use static or dynamic values for Endpoint Name tags 
in captured metrics. By default, static values are used. When using dynamic 
tags, then a dynamic to (toD) can compute many different endpoint URIs that, 
can lead to many tags as the URI is dynamic, so use this with care if setting 
this option to false.", "sourceType": 
"org.apache.camel.main.MetricsConfigurationProperties", "type": "boolean", " 
[...]
     { "name": "camel.metrics.binders", "description": "Additional Micrometer 
binders to include such as jvm-memory, processor, jvm-thread, and so forth. 
Multiple binders can be separated by comma. The following binders currently is 
available from Micrometer: class-loader, commons-object-pool2, file-descriptor, 
hystrix-metrics-binder, jvm-compilation, jvm-gc, jvm-heap-pressure, jvm-info, 
jvm-memory, jvm-thread, log4j2, logback, processor, uptime", "sourceType": 
"org.apache.camel.main.Metr [...]
diff --git a/core/camel-main/src/main/docs/main.adoc 
b/core/camel-main/src/main/docs/main.adoc
index f50aa19a745..fdeffb691d2 100644
--- a/core/camel-main/src/main/docs/main.adoc
+++ b/core/camel-main/src/main/docs/main.adoc
@@ -215,7 +215,7 @@ The camel.server supports 17 options, which are listed 
below.
 
 
 === Camel Embedded HTTP management Server (only for standalone; not Spring 
Boot or Quarkus) configurations
-The camel.management supports 19 options, which are listed below.
+The camel.management supports 22 options, which are listed below.
 
 [width="100%",cols="2,5,^1,2",options="header"]
 |===
@@ -224,6 +224,7 @@ The camel.management supports 19 options, which are listed 
below.
 | *camel.management.authentication{zwsp}Path* | Set HTTP url path of embedded 
server that is protected by authentication configuration. |  | String
 | *camel.management.basic{zwsp}PropertiesFile* | Name of the file that 
contains basic authentication info for Vert.x file auth provider. |  | String
 | *camel.management.devConsole{zwsp}Enabled* | Whether to enable developer 
console (not intended for production use). Dev console must also be enabled on 
CamelContext. For example by setting camel.context.dev-console=true in 
application.properties, or via code camelContext.setDevConsole(true); If 
enabled then you can access a basic developer console on context-path: /q/dev. 
| false | boolean
+| *camel.management.download{zwsp}Enabled* | Whether to enable file download 
via HTTP. This makes it possible to browse and download resource source files 
such as Camel XML or YAML routes. Only enable this for development, 
troubleshooting or special situations for management and monitoring. | false | 
boolean
 | *camel.management.enabled* | Whether embedded HTTP server is enabled. By 
default, the server is not enabled. | false | boolean
 | *camel.management.healthCheck{zwsp}Enabled* | Whether to enable health-check 
console. If enabled then you can access health-check status on context-path: 
/q/health (default) | false | boolean
 | *camel.management.healthPath* | The path endpoint used to expose the health 
status | /observe/health | String
@@ -236,8 +237,10 @@ The camel.management supports 19 options, which are listed 
below.
 | *camel.management.jwtKeystore{zwsp}Type* | Type of the keystore used for JWT 
tokens validation (jks, pkcs12, etc.). |  | String
 | *camel.management.metrics{zwsp}Enabled* | Whether to enable metrics. If 
enabled then you can access metrics on context-path: /q/metrics (default) | 
false | boolean
 | *camel.management.path* | Context-path to use for embedded HTTP server | / | 
String
-| *camel.management.port* | Port to use for binding embedded HTTP server | 
9876 | int
+| *camel.management.port* | Port to use for binding embedded HTTP server | 
8080 | int
 | *camel.management.sendEnabled* | Whether to enable sending messages to Camel 
via HTTP. This makes it possible to use Camel to send messages to Camel 
endpoint URIs via HTTP. | false | boolean
+| *camel.management.uploadEnabled* | Whether to enable file upload via HTTP 
(not intended for production use). This functionality is for development to be 
able to reload Camel routes and code with source changes (if reload is 
enabled). If enabled then you can upload/delete files via HTTP PUT/DELETE on 
context-path: /q/upload/\{name}. You must also configure the uploadSourceDir 
option. | false | boolean
+| *camel.management.uploadSource{zwsp}Dir* | Source directory when upload is 
enabled. |  | String
 | *camel.management.useGlobalSsl{zwsp}ContextParameters* | Whether to use 
global SSL configuration for securing the embedded HTTP server. | false | 
boolean
 |===
 
diff --git 
a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java 
b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
index 1aa95e34c7b..757ed18f023 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
@@ -1444,6 +1444,12 @@ public abstract class BaseMainSupport extends 
BaseService {
                     mainConfigurationProperties.isAutoConfigurationFailFast(), 
true, autoConfiguredProperties);
             camelContext.setRestConfiguration(rest);
         }
+        if (!httpServerProperties.isEmpty() || 
mainConfigurationProperties.hasHttpServerConfiguration()) {
+            LOG.debug("Auto-configuring HTTP Server from loaded properties: 
{}", httpServerProperties.size());
+            setHttpServerProperties(camelContext, httpServerProperties,
+                    mainConfigurationProperties.isAutoConfigurationFailFast(),
+                    autoConfiguredProperties);
+        }
         if (!httpManagementServerProperties.isEmpty() || 
mainConfigurationProperties.hasHttpManagementServerConfiguration()) {
             LOG.debug("Auto-configuring HTTP Management Server from loaded 
properties: {}",
                     httpManagementServerProperties.size());
@@ -1451,12 +1457,6 @@ public abstract class BaseMainSupport extends 
BaseService {
                     mainConfigurationProperties.isAutoConfigurationFailFast(),
                     autoConfiguredProperties);
         }
-        if (!httpServerProperties.isEmpty() || 
mainConfigurationProperties.hasHttpServerConfiguration()) {
-            LOG.debug("Auto-configuring HTTP Server from loaded properties: 
{}", httpServerProperties.size());
-            setHttpServerProperties(camelContext, httpServerProperties,
-                    mainConfigurationProperties.isAutoConfigurationFailFast(),
-                    autoConfiguredProperties);
-        }
         if (!threadPoolProperties.isEmpty() || 
mainConfigurationProperties.hasThreadPoolConfiguration()) {
             LOG.debug("Auto-configuring Thread Pool from loaded properties: 
{}", threadPoolProperties.size());
             MainSupportModelConfigurer.setThreadPoolProperties(camelContext, 
mainConfigurationProperties, threadPoolProperties,
diff --git 
a/core/camel-main/src/main/java/org/apache/camel/main/HttpManagementServerConfigurationProperties.java
 
b/core/camel-main/src/main/java/org/apache/camel/main/HttpManagementServerConfigurationProperties.java
index a157c0e35a2..a18d01e078c 100644
--- 
a/core/camel-main/src/main/java/org/apache/camel/main/HttpManagementServerConfigurationProperties.java
+++ 
b/core/camel-main/src/main/java/org/apache/camel/main/HttpManagementServerConfigurationProperties.java
@@ -32,8 +32,8 @@ public class HttpManagementServerConfigurationProperties 
implements BootstrapClo
     private boolean enabled;
     @Metadata(defaultValue = "0.0.0.0")
     private String host = "0.0.0.0";
-    @Metadata(defaultValue = "9876")
-    private int port = 9876;
+    @Metadata(defaultValue = "8080")
+    private int port = 8080;
     @Metadata(defaultValue = "/")
     private String path = "/";
     @Metadata(defaultValue = "/observe/health")
@@ -46,6 +46,9 @@ public class HttpManagementServerConfigurationProperties 
implements BootstrapClo
     private boolean healthCheckEnabled;
     private boolean jolokiaEnabled;
     private boolean metricsEnabled;
+    private boolean uploadEnabled;
+    private String uploadSourceDir;
+    private boolean downloadEnabled;
     private boolean sendEnabled;
 
     @Metadata(label = "security")
@@ -212,6 +215,44 @@ public class HttpManagementServerConfigurationProperties 
implements BootstrapClo
         this.jolokiaPath = jolokiaPath;
     }
 
+    public boolean isUploadEnabled() {
+        return uploadEnabled;
+    }
+
+    /**
+     * Whether to enable file upload via HTTP (not intended for production 
use). This functionality is for development
+     * to be able to reload Camel routes and code with source changes (if 
reload is enabled). If enabled then you can
+     * upload/delete files via HTTP PUT/DELETE on context-path: 
/q/upload/{name}. You must also configure the
+     * uploadSourceDir option.
+     */
+    public void setUploadEnabled(boolean uploadEnabled) {
+        this.uploadEnabled = uploadEnabled;
+    }
+
+    public String getUploadSourceDir() {
+        return uploadSourceDir;
+    }
+
+    /**
+     * Source directory when upload is enabled.
+     */
+    public void setUploadSourceDir(String uploadSourceDir) {
+        this.uploadSourceDir = uploadSourceDir;
+    }
+
+    public boolean isDownloadEnabled() {
+        return downloadEnabled;
+    }
+
+    /**
+     * Whether to enable file download via HTTP. This makes it possible to 
browse and download resource source files
+     * such as Camel XML or YAML routes. Only enable this for development, 
troubleshooting or special situations for
+     * management and monitoring.
+     */
+    public void setDownloadEnabled(boolean downloadEnabled) {
+        this.downloadEnabled = downloadEnabled;
+    }
+
     public boolean isSendEnabled() {
         return sendEnabled;
     }
@@ -376,6 +417,35 @@ public class HttpManagementServerConfigurationProperties 
implements BootstrapClo
         return this;
     }
 
+    /**
+     * Whether to enable file upload via HTTP (not intended for production 
use). This functionality is for development
+     * to be able to reload Camel routes and code with source changes (if 
reload is enabled). If enabled then you can
+     * upload/delete files via HTTP PUT/DELETE on context-path: 
/q/upload/{name}. You must also configure the
+     * uploadSourceDir option.
+     */
+    public HttpManagementServerConfigurationProperties 
withUploadEnabled(boolean uploadEnabled) {
+        this.uploadEnabled = uploadEnabled;
+        return this;
+    }
+
+    /**
+     * Source directory when upload is enabled.
+     */
+    public HttpManagementServerConfigurationProperties 
withUploadSourceDir(String uploadSourceDir) {
+        this.uploadSourceDir = uploadSourceDir;
+        return this;
+    }
+
+    /**
+     * Whether to enable file download via HTTP. This makes it possible to 
browse and download resource source files
+     * such as Camel XML or YAML routes. Only enable this for development, 
troubleshooting or special situations for
+     * management and monitoring.
+     */
+    public HttpManagementServerConfigurationProperties 
withDownloadEnabled(boolean downloadEnabled) {
+        this.downloadEnabled = downloadEnabled;
+        return this;
+    }
+
     /**
      * Whether to enable sending messages to Camel via HTTP. This makes it 
possible to use Camel to send messages to
      * Camel endpoint URIs via HTTP.


Reply via email to