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 4afbb860b864 CAMEL-22654: camel-jbang - Add command for loading and 
adding new routes from source files (#19869)
4afbb860b864 is described below

commit 4afbb860b8646ae99ac4765276a714cc36d9b9e2
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon Nov 10 14:15:07 2025 +0100

    CAMEL-22654: camel-jbang - Add command for loading and adding new routes 
from source files (#19869)
---
 ...rategy.java => LoadOnDemandReloadStrategy.java} |  92 +++++++------
 .../camel/support/RouteOnDemandReloadStrategy.java |  30 ++++-
 .../camel/support/RouteWatcherReloadStrategy.java  |  31 ++---
 .../modules/ROOT/pages/camel-jbang.adoc            |  23 ++++
 .../camel/cli/connector/LocalCliConnector.java     |  29 ++++
 .../dsl/jbang/core/commands/CamelJBangMain.java    |   1 +
 .../core/commands/action/CamelLoadAction.java      | 149 +++++++++++++++++++++
 .../camel/dsl/jbang/core/commands/LoadTest.java    |  81 +++++++++++
 .../camel-jbang-core/src/test/resources/load.yaml  |  26 ++++
 9 files changed, 398 insertions(+), 64 deletions(-)

diff --git 
a/core/camel-support/src/main/java/org/apache/camel/support/RouteOnDemandReloadStrategy.java
 
b/core/camel-support/src/main/java/org/apache/camel/support/LoadOnDemandReloadStrategy.java
similarity index 57%
copy from 
core/camel-support/src/main/java/org/apache/camel/support/RouteOnDemandReloadStrategy.java
copy to 
core/camel-support/src/main/java/org/apache/camel/support/LoadOnDemandReloadStrategy.java
index a0d9a50bb7b6..6cc8f4d79176 100644
--- 
a/core/camel-support/src/main/java/org/apache/camel/support/RouteOnDemandReloadStrategy.java
+++ 
b/core/camel-support/src/main/java/org/apache/camel/support/LoadOnDemandReloadStrategy.java
@@ -17,53 +17,38 @@
 package org.apache.camel.support;
 
 import java.io.File;
-import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.apache.camel.api.management.ManagedOperation;
 import org.apache.camel.api.management.ManagedResource;
+import org.apache.camel.spi.ContextReloadStrategy;
 import org.apache.camel.spi.Resource;
 import org.apache.camel.util.FileUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * Strategy for triggering on-demand reloading of Camel routes in a running 
Camel application. The strategy is triggered
- * on-demand and reload all files from a directory (and subdirectories).
+ * Strategy for triggering on-demand loading of Camel routes in a running 
Camel application. The strategy is triggered
+ * on-demand and reload all files provided from external source such as 
camel-jbang
  */
-@ManagedResource(description = "Managed RouteOnDemandReloadStrategy")
-public class RouteOnDemandReloadStrategy extends RouteWatcherReloadStrategy {
+@ManagedResource(description = "Managed LoadOnDemandReloadStrategy")
+public class LoadOnDemandReloadStrategy extends RouteOnDemandReloadStrategy {
 
-    private static final Logger LOG = 
LoggerFactory.getLogger(RouteOnDemandReloadStrategy.class);
+    private static final Logger LOG = 
LoggerFactory.getLogger(LoadOnDemandReloadStrategy.class);
 
-    public RouteOnDemandReloadStrategy() {
-        setScheduler(false);
-    }
-
-    public RouteOnDemandReloadStrategy(String directory) {
-        super(directory);
-        setScheduler(false);
-    }
-
-    public RouteOnDemandReloadStrategy(String directory, boolean recursive) {
-        super(directory, recursive);
+    public LoadOnDemandReloadStrategy() {
+        setRemoveAllRoutes(false);
         setScheduler(false);
     }
 
     /**
-     * Triggers on-demand reloading
+     * Triggers on-demand loading
+     *
+     * @param source  the source calling this
+     * @param files   a list of file names
+     * @param restart whether to force restart all routes after source files 
are loaded
      */
-    @ManagedOperation(description = "Trigger on-demand reloading")
-    public void onReload() {
-        onReload("JMX Management");
-    }
-
-    /**
-     * Triggers on-demand reloading
-     */
-    @Override
-    public void onReload(Object source) {
+    public void load(Object source, List<String> files, boolean restart) {
         ClassLoader cl = Thread.currentThread().getContextClassLoader();
         try {
             setLastError(null);
@@ -72,12 +57,12 @@ public class RouteOnDemandReloadStrategy extends 
RouteWatcherReloadStrategy {
             if (acl != null) {
                 Thread.currentThread().setContextClassLoader(acl);
             }
-            doOnReload(source);
+            doOnReload(source, files, restart);
             incSucceededCounter();
         } catch (Exception e) {
             setLastError(e);
             incFailedCounter();
-            LOG.warn("Error reloading routes due to {}. This exception is 
ignored.", e.getMessage(), e);
+            LOG.warn("Error loading routes due to {}. This exception is 
ignored.", e.getMessage(), e);
         } finally {
             if (cl != null) {
                 Thread.currentThread().setContextClassLoader(cl);
@@ -85,15 +70,13 @@ public class RouteOnDemandReloadStrategy extends 
RouteWatcherReloadStrategy {
         }
     }
 
-    protected void doOnReload(Object source) throws Exception {
+    protected void doOnReload(Object source, List<String> files, boolean 
restart) throws Exception {
         List<Resource> properties = new ArrayList<>();
         List<Resource> groovy = new ArrayList<>();
         List<Resource> routes = new ArrayList<>();
 
-        File dir = new File(getFolder());
-        for (Path path : ResourceHelper.findInFileSystem(dir.toPath(), 
getPattern())) {
-            Resource res = ResourceHelper.resolveResource(getCamelContext(), 
"file:" + path.toString());
-            String ext = FileUtil.onlyExt(path.getFileName().toString());
+        for (Resource res : findReloadedResources(files)) {
+            String ext = FileUtil.onlyExt(res.getLocation());
             if ("properties".equals(ext)) {
                 properties.add(res);
             } else if ("groovy".equals(ext)) {
@@ -116,14 +99,37 @@ public class RouteOnDemandReloadStrategy extends 
RouteWatcherReloadStrategy {
         for (Resource res : groovy) {
             reloaded |= onGroovyReload(res, false);
         }
-        boolean removeEverything = routes.isEmpty();
-        if (reloaded || !routes.isEmpty()) {
-            // trigger routes to also reload if properties was reloaded
-            onRouteReload(routes, removeEverything);
-        } else {
-            // rare situation where all routes are deleted
-            onRouteReload(null, removeEverything);
+        if (!routes.isEmpty()) {
+            onRouteReload(routes, false);
         }
+        if (restart || reloaded) {
+            ContextReloadStrategy crs = 
getCamelContext().hasService(ContextReloadStrategy.class);
+            if (crs != null) {
+                crs.onReload(source);
+            }
+        }
+    }
+
+    @Override
+    public void onReload(Object source) {
+        // noop
+    }
+
+    @Override
+    protected List<Resource> findReloadedResources(Object source) throws 
Exception {
+        List<Resource> answer = new ArrayList<>();
+
+        if (source instanceof List list) {
+            for (Object l : list) {
+                File f = new File(l.toString());
+                if (f.isFile() && f.exists()) {
+                    Resource res = 
ResourceHelper.resolveResource(getCamelContext(), "file:" + 
f.getAbsolutePath());
+                    answer.add(res);
+                }
+            }
+        }
+
+        return answer;
     }
 
 }
diff --git 
a/core/camel-support/src/main/java/org/apache/camel/support/RouteOnDemandReloadStrategy.java
 
b/core/camel-support/src/main/java/org/apache/camel/support/RouteOnDemandReloadStrategy.java
index a0d9a50bb7b6..19e6b90f3e32 100644
--- 
a/core/camel-support/src/main/java/org/apache/camel/support/RouteOnDemandReloadStrategy.java
+++ 
b/core/camel-support/src/main/java/org/apache/camel/support/RouteOnDemandReloadStrategy.java
@@ -90,10 +90,8 @@ public class RouteOnDemandReloadStrategy extends 
RouteWatcherReloadStrategy {
         List<Resource> groovy = new ArrayList<>();
         List<Resource> routes = new ArrayList<>();
 
-        File dir = new File(getFolder());
-        for (Path path : ResourceHelper.findInFileSystem(dir.toPath(), 
getPattern())) {
-            Resource res = ResourceHelper.resolveResource(getCamelContext(), 
"file:" + path.toString());
-            String ext = FileUtil.onlyExt(path.getFileName().toString());
+        for (Resource res : findReloadedResources(source)) {
+            String ext = FileUtil.onlyExt(res.getLocation());
             if ("properties".equals(ext)) {
                 properties.add(res);
             } else if ("groovy".equals(ext)) {
@@ -116,14 +114,34 @@ public class RouteOnDemandReloadStrategy extends 
RouteWatcherReloadStrategy {
         for (Resource res : groovy) {
             reloaded |= onGroovyReload(res, false);
         }
-        boolean removeEverything = routes.isEmpty();
+        boolean removeEverything = isRemoveEverything(routes);
         if (reloaded || !routes.isEmpty()) {
             // trigger routes to also reload if properties was reloaded
             onRouteReload(routes, removeEverything);
         } else {
             // rare situation where all routes are deleted
-            onRouteReload(null, removeEverything);
+            onRemoveEverything(removeEverything);
         }
     }
 
+    protected boolean isRemoveEverything(List<Resource> routes) {
+        return routes.isEmpty();
+    }
+
+    protected void onRemoveEverything(boolean removeEverything) {
+        onRouteReload(null, removeEverything);
+    }
+
+    protected List<Resource> findReloadedResources(Object source) throws 
Exception {
+        List<Resource> answer = new ArrayList<>();
+
+        File dir = new File(getFolder());
+        for (Path path : ResourceHelper.findInFileSystem(dir.toPath(), 
getPattern())) {
+            Resource res = ResourceHelper.resolveResource(getCamelContext(), 
"file:" + path.toString());
+            answer.add(res);
+        }
+
+        return answer;
+    }
+
 }
diff --git 
a/core/camel-support/src/main/java/org/apache/camel/support/RouteWatcherReloadStrategy.java
 
b/core/camel-support/src/main/java/org/apache/camel/support/RouteWatcherReloadStrategy.java
index 7463f650668f..77791c589521 100644
--- 
a/core/camel-support/src/main/java/org/apache/camel/support/RouteWatcherReloadStrategy.java
+++ 
b/core/camel-support/src/main/java/org/apache/camel/support/RouteWatcherReloadStrategy.java
@@ -40,7 +40,6 @@ import org.apache.camel.spi.Resource;
 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.OrderedLocationProperties;
 import org.apache.camel.util.OrderedProperties;
 import org.apache.camel.util.StringHelper;
@@ -111,8 +110,23 @@ public class RouteWatcherReloadStrategy extends 
FileWatcherResourceReloadStrateg
 
     @Override
     protected void doStart() throws Exception {
-        ObjectHelper.notNull(getFolder(), "folder", this);
+        if (getResourceReload() == null) {
+            // attach listener that triggers the route update
+            setResourceReload((name, resource) -> {
+                if (name.endsWith(".properties")) {
+                    onPropertiesReload(resource, true);
+                } else if (name.endsWith(".groovy")) {
+                    onGroovyReload(resource, true);
+                } else {
+                    onRouteReload(List.of(resource), false);
+                }
+            });
+        }
 
+        // the following is all related to watching files on disk
+        if (folder == null) {
+            return;
+        }
         if (pattern == null || pattern.isBlank()) {
             pattern = DEFAULT_PATTERN;
         } else if ("*".equals(pattern)) {
@@ -146,19 +160,6 @@ public class RouteWatcherReloadStrategy extends 
FileWatcherResourceReloadStrateg
             });
         }
 
-        if (getResourceReload() == null) {
-            // attach listener that triggers the route update
-            setResourceReload((name, resource) -> {
-                if (name.endsWith(".properties")) {
-                    onPropertiesReload(resource, true);
-                } else if (name.endsWith(".groovy")) {
-                    onGroovyReload(resource, true);
-                } else {
-                    onRouteReload(List.of(resource), false);
-                }
-            });
-        }
-
         super.doStart();
     }
 
diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
index b0e4ec0d4755..d69111822c53 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
@@ -448,6 +448,29 @@ and reloaded. You can also delete files to remove routes.
 NOTE: You cannot use both files and source dir together.
 The following is not allowed: `camel run abc.java --source-dir=mycode`.
 
+==== Loading new routes into existing Camel
+
+*Available as of Camel 4.17*
+
+The `camel cmd load` command can be used to load new route(s) into an existing 
running Camel JBang application.
+For example during development to inject a new route for experimentation. This 
can also be used as part
+of testing scenarios using Citrus with the xref:camel-jbang-test.adoc[Camel 
JBang Test] plugin.
+
+For example to load `bar.java` route into a Camel application:
+
+[source,bash]
+----
+camel cmd load --source=bar.java
+----
+
+You can load any of the DSLs such as Java, XML, or YAML.
+
+NOTE: At the moment, the `load` command is only adding new, so if you load the 
same a 2nd time, then Camel
+will add this as a new duplicate route. This may be improved in the future to 
make the `load` command
+able to detect a previous file and do a remote and add operation.
+
+TIP: There is a `--restart` option to tell Camel to restart all routes after 
the new route is loaded.
+
 ==== Uploading files to source directory via HTTP
 
 When running Camel JBang with `--source-dir`, `--console` and `--dev` 
(reloading) then you can
diff --git 
a/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/LocalCliConnector.java
 
b/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/LocalCliConnector.java
index dd1e43add1f2..d4ff037ac3bb 100644
--- 
a/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/LocalCliConnector.java
+++ 
b/dsl/camel-cli-connector/src/main/java/org/apache/camel/cli/connector/LocalCliConnector.java
@@ -72,6 +72,7 @@ import org.apache.camel.spi.Resource;
 import org.apache.camel.spi.ResourceLoader;
 import org.apache.camel.spi.ResourceReloadStrategy;
 import org.apache.camel.spi.RoutesLoader;
+import org.apache.camel.support.LoadOnDemandReloadStrategy;
 import org.apache.camel.support.MessageHelper;
 import org.apache.camel.support.PatternHelper;
 import org.apache.camel.support.PluginHelper;
@@ -259,6 +260,8 @@ public class LocalCliConnector extends ServiceSupport 
implements CliConnector, C
                 doActionLoggerTask(root);
             } else if ("gc".equals(action)) {
                 System.gc();
+            } else if ("load".equals(action)) {
+                doActionLoadTask(root);
             } else if ("reload".equals(action)) {
                 doActionReloadTask();
             } else if ("debug".equals(action)) {
@@ -802,6 +805,32 @@ public class LocalCliConnector extends ServiceSupport 
implements CliConnector, C
         }
     }
 
+    private void doActionLoadTask(JsonObject root) throws Exception {
+        List<String> files = root.getCollection("source");
+        boolean restart = root.getBooleanOrDefault("restart", false);
+        if (files != null) {
+            LoadOnDemandReloadStrategy cr = 
camelContext.hasService(LoadOnDemandReloadStrategy.class);
+            if (cr == null) {
+                cr = new LoadOnDemandReloadStrategy();
+                cr.setCamelContext(camelContext);
+                camelContext.addService(cr);
+            }
+            cr.load("Camel JBang", files, restart);
+            JsonObject jo = new JsonObject();
+            Exception error = cr.getLastError();
+            if (error != null) {
+                jo.put("status", "failed");
+                jo.put("exception",
+                        
MessageHelper.dumpExceptionAsJSonObject(error).getMap("exception"));
+            } else {
+                jo.put("status", "success");
+            }
+            IOHelper.writeText(jo.toJson(), outputFile);
+        } else {
+            IOHelper.writeText("{}", outputFile);
+        }
+    }
+
     private void doActionReloadTask() {
         ContextReloadStrategy cr = 
camelContext.hasService(ContextReloadStrategy.class);
         if (cr != null) {
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
index 2c9e43633764..775e0d880b2f 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
@@ -141,6 +141,7 @@ public class CamelJBangMain implements Callable<Integer> {
                         .addSubcommand("enable-processor", new CommandLine(new 
CamelProcessorEnableAction(main)))
                         .addSubcommand("disable-processor", new 
CommandLine(new CamelProcessorDisableAction(main)))
                         .addSubcommand("reset-stats", new CommandLine(new 
CamelResetStatsAction(main)))
+                        .addSubcommand("load", new CommandLine(new 
CamelLoadAction(main)))
                         .addSubcommand("reload", new CommandLine(new 
CamelReloadAction(main)))
                         .addSubcommand("send", new CommandLine(new 
CamelSendAction(main)))
                         .addSubcommand("receive", new CommandLine(new 
CamelReceiveAction(main)))
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelLoadAction.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelLoadAction.java
new file mode 100644
index 000000000000..4f296cb6da8a
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/action/CamelLoadAction.java
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dsl.jbang.core.commands.action;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+
+import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.apache.camel.dsl.jbang.core.common.PathUtils;
+import org.apache.camel.util.StopWatch;
+import org.apache.camel.util.json.JsonArray;
+import org.apache.camel.util.json.JsonObject;
+import org.apache.camel.util.json.Jsoner;
+import org.fusesource.jansi.Ansi;
+import picocli.CommandLine;
+
[email protected](name = "load",
+                     description = "Loads new source files into an existing 
Camel", sortOptions = false,
+                     showDefaultValues = true)
+public class CamelLoadAction extends ActionBaseCommand {
+
+    @CommandLine.Parameters(description = "Name or pid of running Camel 
integration", arity = "0..1")
+    String name = "*";
+
+    @CommandLine.Option(names = { "--source" },
+                        description = "Source file(s) to load")
+    List<String> source;
+
+    @CommandLine.Option(names = { "--restart" },
+                        description = "To force restart all routes after 
loading source files")
+    boolean restart;
+
+    public CamelLoadAction(CamelJBangMain main) {
+        super(main);
+    }
+
+    @Override
+    public Integer doCall() throws Exception {
+        if (source == null || source.isEmpty()) {
+            printer().printErr("No source files provided. Specify files using 
--source option");
+            return 1;
+        }
+
+        List<Long> pids = findPids(name);
+        if (pids.isEmpty()) {
+            return 0;
+        } else if (pids.size() > 1) {
+            printer().println("Name or pid " + name + " matches " + pids.size()
+                              + " running Camel integrations. Specify a name 
or PID that matches exactly one.");
+            return 0;
+        }
+        long pid = pids.get(0);
+
+        // ensure output file is deleted before executing action
+        Path outputFile = getOutputFile(Long.toString(pid));
+        PathUtils.deleteFile(outputFile);
+
+        JsonObject root = new JsonObject();
+        root.put("action", "load");
+        root.put("restart", restart);
+        // turn into absolute path
+        JsonArray arr = new JsonArray();
+        for (String s : source) {
+            File f = new File(s);
+            if (f.exists() && f.isFile()) {
+                // favour using absolute path to file as the load command can 
be called from another
+                // folder than where camel is running
+                s = f.getAbsolutePath();
+            }
+            arr.add(s);
+        }
+        root.put("source", arr);
+        Path f = getActionFile(Long.toString(pid));
+        Files.writeString(f, root.toJson());
+
+        JsonObject jo = waitForOutputFile(outputFile);
+        if (jo != null) {
+            String status = jo.getString("status");
+            if ("success".equals(status)) {
+                printer().println("Successfully loaded " + source.size() + " 
source files");
+            } else {
+                printer().printErr("Error loading " + source.size() + " source 
files");
+            }
+            JsonObject cause = jo.getMap("exception");
+            if (cause != null) {
+                String msg = cause.getString("message");
+                if (msg != null) {
+                    msg = Jsoner.unescape(msg);
+                }
+                String st = cause.getString("stackTrace");
+                if (st != null) {
+                    st = Jsoner.unescape(st);
+                }
+                if (msg != null) {
+                    String text = 
Ansi.ansi().fgRed().a(msg).reset().toString();
+                    printer().printErr(text);
+                    printer().println();
+                }
+                if (st != null) {
+                    String text = Ansi.ansi().fgRed().a(st).reset().toString();
+                    printer().printErr(text);
+                    printer().println();
+                }
+                return 1;
+            }
+        }
+
+        return 0;
+    }
+
+    protected JsonObject waitForOutputFile(Path outputFile) {
+        StopWatch watch = new StopWatch();
+        long wait = 10000;
+        while (watch.taken() < wait) {
+            File f = outputFile.toFile();
+            try {
+                // give time for response to be ready
+                Thread.sleep(20);
+
+                if (Files.exists(outputFile) && f.length() > 0) {
+                    String text = Files.readString(outputFile);
+                    return (JsonObject) Jsoner.deserialize(text);
+                }
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+            } catch (Exception e) {
+                // ignore
+            }
+        }
+        return null;
+    }
+
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/LoadTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/LoadTest.java
new file mode 100644
index 000000000000..4839eaf27317
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/LoadTest.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dsl.jbang.core.commands;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.apache.camel.dsl.jbang.core.commands.action.CamelLoadAction;
+import org.apache.camel.dsl.jbang.core.common.PathUtils;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import picocli.CommandLine;
+
+import static org.apache.camel.dsl.jbang.core.common.RuntimeUtil.getPid;
+
+class LoadTest {
+
+    private Path workingDir;
+
+    @BeforeEach
+    public void setup() throws IOException {
+        Path base = Paths.get("target");
+        workingDir = Files.createTempDirectory(base, "camel-load");
+    }
+
+    @AfterEach
+    public void end() throws IOException {
+        // force removing, since deleteOnExit is not removing.
+        PathUtils.deleteDirectory(workingDir);
+    }
+
+    @Test
+    public void shouldLoad() throws Exception {
+        Run run = new Run(new CamelJBangMain());
+        CommandLine.populateCommand(run, "src/test/resources/hello.yaml", 
"--name=myload", "--max-messages=5",
+                "--prop=mydir=" + workingDir);
+
+        Runnable r = () -> {
+            try {
+                Thread.sleep(2000);
+                System.out.println("Calling load...");
+                CamelLoadAction load = new CamelLoadAction(new 
CamelJBangMain());
+                CommandLine.populateCommand(load, getPid(), 
"--source=src/test/resources/load.yaml");
+                int exit = load.doCall();
+                Assertions.assertEquals(0, exit);
+            } catch (Exception e) {
+                // ignore
+            }
+        };
+
+        Thread t = new Thread(r);
+        t.start();
+
+        int exit = run.doCall();
+        Assertions.assertEquals(0, exit);
+
+        Path outPath = workingDir.resolve("load.txt");
+        Assertions.assertTrue(Files.exists(outPath));
+        String data = Files.readString(outPath);
+        Assertions.assertEquals("I was loaded", data);
+    }
+
+}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/test/resources/load.yaml 
b/dsl/camel-jbang/camel-jbang-core/src/test/resources/load.yaml
new file mode 100644
index 000000000000..ce9712421e5a
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/test/resources/load.yaml
@@ -0,0 +1,26 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+- from:
+    uri: "timer:load"
+    parameters:
+      period: "1000"
+      repeatCount: 1
+    steps:
+      - setBody:
+          constant: "I was loaded"
+      - to: file:{{mydir}}?fileName=load.txt

Reply via email to