This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch camel-4.22.x
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/camel-4.22.x by this push:
new a157a9e572d2 [backport camel-4.22.x] CAMEL-25528: camel-jbang - camel
run adds camel.jbang.dependencies of the properties files given on the command
line (#27658)
a157a9e572d2 is described below
commit a157a9e572d20b3fa33c3297829ecad16ccd4025
Author: Federico Mariani <[email protected]>
AuthorDate: Sat Oct 10 13:31:24 2026 +0200
[backport camel-4.22.x] CAMEL-25528: camel-jbang - camel run adds
camel.jbang.dependencies of the properties files given on the command line
(#27658)
CAMEL-25528: camel-jbang - camel run adds camel.jbang.dependencies of the
properties files given on the command line
camel run read camel.jbang.dependencies (and the runtime-specific variants)
only from the application.properties of
the current directory or --source-dir, so the dependencies declared in
camel/application.properties were ignored
when running camel run camel/*.yaml camel/application.properties from the
parent directory (or with --properties),
without any message. They are now added after the ones of the profile
properties, which are not read twice.
Map the Spring transaction classes of a transacted route
(DataSourceTransactionManager, JdbcTransactionManager,
DriverManagerDataSource, PlatformTransactionManager, TransactionTemplate
and SpringTransactionPolicy) in
camel-main-known-dependencies.properties, so they are downloaded on demand.
---
.../modules/ROOT/pages/camel-jbang-running.adoc | 14 +++
.../apache/camel/dsl/jbang/core/commands/Run.java | 43 ++++++++
.../RunPropertiesFilesDependenciesTest.java | 122 +++++++++++++++++++++
.../camel-main-known-dependencies.properties | 6 +
.../download/KnownDependenciesResolverTest.java | 18 +++
5 files changed, 203 insertions(+)
diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang-running.adoc
b/docs/user-manual/modules/ROOT/pages/camel-jbang-running.adoc
index d561f88dd6fb..eaa5b97da9ee 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-jbang-running.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-jbang-running.adoc
@@ -152,6 +152,20 @@ Multiple dependencies can be separated by comma:
camel run foo.java --dep=camel-saxon,com.foo:acme:1.0
----
+The dependencies can also be declared in `application.properties` with
`camel.jbang.dependencies`
+(or `camel.jbang.dependencies.main`, `camel.jbang.dependencies.spring-boot`
and `camel.jbang.dependencies.quarkus`
+for one runtime only):
+
+[source,properties]
+----
+camel.jbang.dependencies=camel:sql,com.foo:acme:1.0
+----
+
+They are read from the `application.properties` (and
`application-<profile>.properties`) of the current directory
+or of `--source-dir`, and from the properties files given on the command line
or with `--properties`,
+for example `camel run camel/*.yaml camel/application.properties` run from the
parent directory of `camel`.
+They are added to the dependencies given with `--dep`.
+
== Including resource directories
To include entire directories of resource files (such as XSD schemas, WSDL
files, etc.)
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 d9a773a89a65..780076bac691 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
@@ -299,6 +299,9 @@ public class Run extends CamelCommand {
" (ex.
/path/to/file.properties,/path/to/other.properties")
public String propertiesFiles;
+ // the profile properties files that are loaded (application.properties
and application-<profile>.properties)
+ final Set<Path> profilePropertiesFiles = new HashSet<>();
+
@Option(names = { "--prop", "--property" }, description = "Additional
properties (override existing)")
public String[] property;
@@ -1231,6 +1234,9 @@ public class Run extends CamelCommand {
// Add runtime-specific dependencies
addRuntimeSpecificDependenciesFromProperties(profileProperties);
+ // and the dependencies of the properties files given on the command
line, such as camel/application.properties
+ addDependenciesFromPropertiesFiles(propertiesFiles);
+
// Add plugin dependencies
Map<String, Plugin> activePlugins = Collections.emptyMap();
if (!skipPlugins) {
@@ -1368,6 +1374,42 @@ public class Run extends CamelCommand {
}
}
+ /**
+ * Adds the dependencies ({@code camel.jbang.dependencies} and the
runtime-specific variants) declared in the local
+ * properties files given on the command line or with --properties, such
as {@code camel/application.properties} run
+ * from the parent directory. The profile properties files
(application.properties in the current directory or the
+ * source dir) are skipped, as their dependencies are already added.
+ */
+ void addDependenciesFromPropertiesFiles(String locations) throws Exception
{
+ if (ObjectHelper.isEmpty(locations)) {
+ return;
+ }
+ for (String location : locations.split(",")) {
+ location = location.trim();
+ if (location.startsWith("file:")) {
+ location = location.substring(5);
+ if (location.startsWith("//")) {
+ location = location.substring(2);
+ }
+ } else if (ResourceHelper.hasScheme(location) ||
location.startsWith("github:")
+ || location.startsWith("gist:")) {
+ // only local files
+ continue;
+ }
+ if (location.isEmpty()) {
+ continue;
+ }
+ Path path = Paths.get(location).toAbsolutePath().normalize();
+ if (profilePropertiesFiles.contains(path) ||
!Files.isRegularFile(path)) {
+ continue;
+ }
+ Properties prop = new CamelCaseOrderedProperties();
+ RuntimeUtil.loadProperties(prop, path);
+ addDependencies(RuntimeUtil.getDependenciesAsArray(prop));
+ addRuntimeSpecificDependenciesFromProperties(prop);
+ }
+ }
+
protected void addDependencies(String... deps) {
var depsArray = Optional.ofNullable(deps).orElse(new String[0]);
var depsList = Arrays.stream(depsArray).filter(tok ->
!tok.isEmpty()).toList();
@@ -2113,6 +2155,7 @@ public class Run extends CamelCommand {
private Properties doLoadAndInitProfileProperties(Path
profilePropertiesPath) throws Exception {
Properties answer = null;
if (Files.exists(profilePropertiesPath)) {
+
profilePropertiesFiles.add(profilePropertiesPath.toAbsolutePath().normalize());
answer = loadProfilePropertiesFile(profilePropertiesPath);
// logging level/color may be configured in the properties file
loggingOptions.loggingLevel = answer.getProperty("loggingLevel",
loggingOptions.loggingLevel);
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/RunPropertiesFilesDependenciesTest.java
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/RunPropertiesFilesDependenciesTest.java
new file mode 100644
index 000000000000..1b1942bc5b6b
--- /dev/null
+++
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/RunPropertiesFilesDependenciesTest.java
@@ -0,0 +1,122 @@
+/*
+ * 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.nio.file.Files;
+import java.nio.file.Path;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+import picocli.CommandLine;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * CAMEL-25528: camel.jbang.dependencies in a properties file given on the
command line, such as
+ * camel/application.properties run from the parent directory, adds the
dependencies as the application.properties of
+ * the current directory does.
+ */
+class RunPropertiesFilesDependenciesTest {
+
+ private static Run run(String... args) {
+ Run command = new Run(new CamelJBangMain());
+ CommandLine.populateCommand(command, args);
+ return command;
+ }
+
+ private static Path properties(Path dir) throws Exception {
+ Path camel = Files.createDirectories(dir.resolve("camel"));
+ return Files.writeString(camel.resolve("application.properties"), """
+ camel.jbang.dependencies=camel:spring,org.example:shared:1.0
+ camel.jbang.dependencies.main=org.example:main-only:1.0
+
camel.jbang.dependencies.spring-boot=org.example:spring-boot-only:1.0
+ camel.jbang.dependencies.quarkus=org.example:quarkus-only:1.0
+ greeting=Hello
+ """);
+ }
+
+ @Test
+ void dependenciesOfAPropertiesFileOnTheCommandLine(@TempDir Path dir)
throws Exception {
+ Path file = properties(dir);
+ Run run = run("--dep=org.example:from-option:1.0", "route.camel.yaml");
+
+ // as the run command passes the files it found among the files to run
+ run.addDependenciesFromPropertiesFiles("file:" + file);
+
+
assertThat(run.dependencies).containsExactly("org.example:from-option:1.0",
"camel:spring",
+ "org.example:shared:1.0", "org.example:main-only:1.0");
+ }
+
+ @Test
+ void runtimeSpecificDependencies(@TempDir Path dir) throws Exception {
+ Path file = properties(dir);
+
+ Run springBoot = run("--runtime=spring-boot", "route.camel.yaml");
+ springBoot.addDependenciesFromPropertiesFiles(file.toString());
+ assertThat(springBoot.dependencies).containsExactly("camel:spring",
"org.example:shared:1.0",
+ "org.example:spring-boot-only:1.0");
+
+ Run quarkus = run("--runtime=quarkus", "route.camel.yaml");
+ quarkus.addDependenciesFromPropertiesFiles(file.toUri().toString());
+ assertThat(quarkus.dependencies).containsExactly("camel:spring",
"org.example:shared:1.0",
+ "org.example:quarkus-only:1.0");
+ }
+
+ @Test
+ void dependenciesOfThePropertiesOption(@TempDir Path dir) throws Exception
{
+ Path file = properties(dir);
+ Run run = run("--properties=" + file, "route.camel.yaml");
+
+ run.addDependenciesFromPropertiesFiles(run.propertiesFiles);
+
+ assertThat(run.dependencies).containsExactly("camel:spring",
"org.example:shared:1.0",
+ "org.example:main-only:1.0");
+ }
+
+ @Test
+ void theProfilePropertiesAreNotAddedTwice(@TempDir Path dir) throws
Exception {
+ Path file = properties(dir);
+ Run run = run("route.camel.yaml");
+ // the application.properties of the current directory, whose
dependencies are added already
+ run.profilePropertiesFiles.add(file.toAbsolutePath().normalize());
+
+ run.addDependenciesFromPropertiesFiles("file:" + file);
+
+ assertThat(run.dependencies).isEmpty();
+ }
+
+ @Test
+ void remoteAndMissingFilesAreSkipped(@TempDir Path dir) throws Exception {
+ Run run = run("route.camel.yaml");
+
+ run.addDependenciesFromPropertiesFiles(
+
"github:apache:camel-kamelets-examples:jbang/hello-java/application.properties,classpath:app.properties,file:"
+ +
dir.resolve("missing.properties"));
+
+ assertThat(run.dependencies).isEmpty();
+ }
+
+ @Test
+ void aFileWithoutDependencies(@TempDir Path dir) throws Exception {
+ Path file = Files.writeString(dir.resolve("other.properties"),
"greeting=Hello\n");
+ Run run = run("route.camel.yaml");
+
+ run.addDependenciesFromPropertiesFiles("file:" + file);
+
+ assertThat(run.dependencies).isEmpty();
+ }
+}
diff --git
a/dsl/camel-kamelet-main/src/main/resources/camel-main-known-dependencies.properties
b/dsl/camel-kamelet-main/src/main/resources/camel-main-known-dependencies.properties
index 9b1946ae1f53..e8671780865b 100644
---
a/dsl/camel-kamelet-main/src/main/resources/camel-main-known-dependencies.properties
+++
b/dsl/camel-kamelet-main/src/main/resources/camel-main-known-dependencies.properties
@@ -23,6 +23,12 @@ org.springframework.stereotype.Service = camel:spring
org.springframework.beans.factory.annotation.Value = camel:spring
org.springframework.amqp.rabbit.connection.CachingConnectionFactory =
camel:spring-rabbitmq
org.springframework.jdbc.datasource.SimpleDriverDataSource = camel:sql
+org.springframework.jdbc.datasource.DriverManagerDataSource = camel:sql
+org.springframework.jdbc.datasource.DataSourceTransactionManager = camel:sql
+org.springframework.jdbc.support.JdbcTransactionManager = camel:sql
+org.springframework.transaction.PlatformTransactionManager = camel:spring
+org.springframework.transaction.support.TransactionTemplate = camel:spring
+org.apache.camel.spring.spi.SpringTransactionPolicy = camel:spring
spring.datasource.url =
org.springframework.boot:spring-boot-starter-jdbc:${spring-boot-version}
quarkus.datasource.db-kind\=db2 =
io.quarkus:quarkus-jdbc-db2:${quarkus-version}
diff --git
a/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/download/KnownDependenciesResolverTest.java
b/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/download/KnownDependenciesResolverTest.java
index 8b3594ca7e21..fbe5b767eae8 100644
---
a/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/download/KnownDependenciesResolverTest.java
+++
b/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/download/KnownDependenciesResolverTest.java
@@ -55,6 +55,24 @@ public class KnownDependenciesResolverTest {
public static class SomeClass {
}
+ @Test
+ void theShippedMappingResolvesSpringTransactionClasses() {
+ // the beans of a transacted route: the Spring JDBC transaction
managers and datasources come with camel-sql
+ // (spring-jdbc), the Spring transaction policy and spring-tx come
with camel-spring
+ KnownDependenciesResolver resolver = new KnownDependenciesResolver(new
SimpleCamelContext(), null, null);
+ resolver.loadKnownDependencies();
+
+ assertGav(resolver,
"org.springframework.jdbc.datasource.DataSourceTransactionManager",
"org.apache.camel",
+ "camel-sql");
+ assertGav(resolver,
"org.springframework.jdbc.support.JdbcTransactionManager", "org.apache.camel",
"camel-sql");
+ assertGav(resolver,
"org.springframework.jdbc.datasource.DriverManagerDataSource",
"org.apache.camel", "camel-sql");
+ assertGav(resolver,
"org.springframework.transaction.PlatformTransactionManager",
"org.apache.camel",
+ "camel-spring");
+ assertGav(resolver,
"org.springframework.transaction.support.TransactionTemplate",
"org.apache.camel",
+ "camel-spring");
+ assertGav(resolver,
"org.apache.camel.spring.spi.SpringTransactionPolicy", "org.apache.camel",
"camel-spring");
+ }
+
@Test
void anImportResolvesAnyClassOfAComponent() {
// CAMEL-25239: any class of a component a source imports, not only
the component class itself, such as the