This is an automated email from the ASF dual-hosted git repository. fmariani pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel.git
commit 15c6bef81e00a6f13ae5c0317be5d8f1e042281f Author: Croway <[email protected]> AuthorDate: Tue Apr 7 12:21:23 2026 +0200 CAMEL-23276: Add PluginRunCustomizer to JBang Plugin SPI --- .../apache/camel/dsl/jbang/core/commands/Run.java | 10 ++- .../apache/camel/dsl/jbang/core/common/Plugin.java | 10 +++ .../{Plugin.java => PluginRunCustomizer.java} | 35 +++++------ .../jbang/core/common/PluginRunCustomizerTest.java | 73 ++++++++++++++++++++++ 4 files changed, 107 insertions(+), 21 deletions(-) diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java index 864199a38804..5794c634601a 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java @@ -967,8 +967,11 @@ public class Run extends CamelCommand { addRuntimeSpecificDependenciesFromProperties(profileProperties); // Add plugin dependencies + Map<String, Plugin> activePlugins = Collections.emptyMap(); if (!skipPlugins) { - Set<PluginExporter> exporters = PluginHelper.getActivePlugins(getMain(), repositories).values() + activePlugins = PluginHelper.getActivePlugins(getMain(), repositories); + + Set<PluginExporter> exporters = activePlugins.values() .stream() .map(Plugin::getExporter) .filter(Optional::isPresent) @@ -991,6 +994,11 @@ public class Run extends CamelCommand { writeSettings(DEPENDENCIES, joined); } + // Let plugins customize the run before KameletMain starts + for (Plugin plugin : activePlugins.values()) { + plugin.getRunCustomizer().ifPresent(customizer -> customizer.beforeRun(main, files)); + } + // Block --camel-version when running from camel-launcher if (camelVersion != null && LauncherHelper.isRunningFromLauncher()) { printer().printErr("The --camel-version option is not supported when running from camel-launcher."); diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/Plugin.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/Plugin.java index 12db1df2eee9..8571418b5f2d 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/Plugin.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/Plugin.java @@ -42,4 +42,14 @@ public interface Plugin { default Optional<PluginExporter> getExporter() { return Optional.empty(); } + + /** + * The plugin may provide an optional run customizer that is called after the Run command has resolved file + * arguments and configured dependencies, but before KameletMain.run() builds the CamelContext. + * + * @return the plugin specific run customizer implementation, otherwise empty + */ + default Optional<PluginRunCustomizer> getRunCustomizer() { + return Optional.empty(); + } } diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/Plugin.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/PluginRunCustomizer.java similarity index 50% copy from dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/Plugin.java copy to dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/PluginRunCustomizer.java index 12db1df2eee9..b0c64f653324 100644 --- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/Plugin.java +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/PluginRunCustomizer.java @@ -16,30 +16,25 @@ */ package org.apache.camel.dsl.jbang.core.common; -import java.util.Optional; +import java.util.List; -import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain; -import picocli.CommandLine; +import org.apache.camel.main.KameletMain; -@FunctionalInterface -public interface Plugin { - - /** - * Customize given command line adding sub-commands in particular. - * - * @param commandLine the command line to adjust. - * @param main the current JBang main. - */ - void customize(CommandLine commandLine, CamelJBangMain main); +/** + * Plugin hook that runs after the Run command has resolved file arguments and configured dependencies, but before + * {@link KameletMain#run()} builds the CamelContext. + * + * This allows plugins to customize the environment (system properties, config directories, initial properties) based on + * the file arguments passed to the run command. + */ +public interface PluginRunCustomizer { /** - * The plugin may provide an optional project exporter implementation that is able to participate in an export - * performed by Camel JBang. Project exporter implementations may add properties and dependencies to the generated - * export. + * Called after the Run command has resolved file arguments and configured dependencies, but before + * KameletMain.run() builds the CamelContext. * - * @return the plugin specific exporter implementation, otherwise empty + * @param main the KameletMain instance (for adding initial properties) + * @param files the resolved file arguments passed to the run command */ - default Optional<PluginExporter> getExporter() { - return Optional.empty(); - } + void beforeRun(KameletMain main, List<String> files); } diff --git a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/common/PluginRunCustomizerTest.java b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/common/PluginRunCustomizerTest.java new file mode 100644 index 000000000000..9fc851b7db94 --- /dev/null +++ b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/common/PluginRunCustomizerTest.java @@ -0,0 +1,73 @@ +/* + * 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.common; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain; +import org.apache.camel.main.KameletMain; +import org.junit.jupiter.api.Test; +import picocli.CommandLine; + +import static org.junit.jupiter.api.Assertions.*; + +public class PluginRunCustomizerTest { + + @Test + public void testPluginDefaultReturnsEmpty() { + Plugin plugin = (commandLine, main) -> { + // no-op + }; + + assertTrue(plugin.getRunCustomizer().isEmpty()); + } + + @Test + public void testPluginWithRunCustomizer() { + List<String> capturedFiles = new ArrayList<>(); + boolean[] called = { false }; + + PluginRunCustomizer customizer = (main, files) -> { + called[0] = true; + capturedFiles.addAll(files); + }; + + Plugin plugin = new Plugin() { + @Override + public void customize(CommandLine commandLine, CamelJBangMain main) { + // no-op + } + + @Override + public Optional<PluginRunCustomizer> getRunCustomizer() { + return Optional.of(customizer); + } + }; + + Optional<PluginRunCustomizer> result = plugin.getRunCustomizer(); + assertTrue(result.isPresent()); + + // Simulate invoking the customizer + List<String> testFiles = List.of("route.yaml", "beans.xml"); + result.get().beforeRun(new KameletMain("test"), testFiles); + + assertTrue(called[0]); + assertEquals(testFiles, capturedFiles); + } +}
