This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch load in repository https://gitbox.apache.org/repos/asf/camel.git
commit 083444b798c7bd92a682c572ad22aeeca36a29cd Author: Claus Ibsen <[email protected]> AuthorDate: Mon Nov 10 13:33:55 2025 +0100 CAMEL-22654: camel-jbang - Add command for loading and adding new routes from source files --- ...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
