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