This is an automated email from the ASF dual-hosted git repository.
jamesnetherton pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git
The following commit(s) were added to refs/heads/main by this push:
new 988fd126ca Support Camel default route resource locations
988fd126ca is described below
commit 988fd126ca9d3419e2998772a01169d134558e21
Author: James Netherton <[email protected]>
AuthorDate: Mon Mar 24 12:38:21 2025 +0000
Support Camel default route resource locations
Fixes #6733
---
.../deployment/CamelRouteResourcesProcessor.java | 92 ++++++++++++++
.../core/deployment/main/CamelMainHelper.java | 8 +-
.../main/CamelMainHotDeploymentProcessor.java | 54 +++-----
.../main/CamelMainNativeImageProcessor.java | 34 ++---
.../spi/CamelRouteResourceBuildItem.java | 89 +++++++++++++
.../quarkus/core/deployment/util/CamelSupport.java | 36 ++++++
.../camel/quarkus/core/CamelCapabilities.java | 1 +
.../CamelQuarkusPackageScanResourceResolver.java | 122 +++++++++++++++++-
extensions-core/yaml-dsl/runtime/pom.xml | 5 +
.../java/deployment/OpenApiJavaProcessor.java | 6 +-
.../apache/camel/quarkus/core/CoreResource.java | 16 +++
.../core/src/main/resources/application.properties | 2 +-
.../sub-resources-folder/foo/bar/test-1.txt | 7 +-
.../sub-resources-folder/foo/bar/test-2.txt | 7 +-
.../org/apache/camel/quarkus/core/CoreTest.java | 57 +++++++++
integration-tests/main-devmode/pom.xml | 17 +++
...ludePatternWithDefaultLocationsDevModeTest.java | 141 +++++++++++++++++++++
.../camel/quarkus/main/CamelSupportResource.java | 9 ++
.../src/main/resources/application.properties | 1 -
.../resources/{routes => camel-rest}/my-rests.yaml | 0
.../{routes => camel-template}/my-templates.yaml | 0
.../resources/{routes => camel}/my-routes.yaml | 0
22 files changed, 622 insertions(+), 82 deletions(-)
diff --git
a/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelRouteResourcesProcessor.java
b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelRouteResourcesProcessor.java
new file mode 100644
index 0000000000..eb116a29f3
--- /dev/null
+++
b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelRouteResourcesProcessor.java
@@ -0,0 +1,92 @@
+/*
+ * 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.quarkus.core.deployment;
+
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import io.quarkus.deployment.ApplicationArchive;
+import io.quarkus.deployment.Capabilities;
+import io.quarkus.deployment.annotations.BuildProducer;
+import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.builditem.ApplicationArchivesBuildItem;
+import io.quarkus.maven.dependency.ResolvedDependency;
+import io.quarkus.paths.PathVisit;
+import io.quarkus.paths.PathVisitor;
+import org.apache.camel.quarkus.core.deployment.main.CamelMainHelper;
+import
org.apache.camel.quarkus.core.deployment.spi.CamelRouteResourceBuildItem;
+import org.apache.camel.quarkus.core.deployment.util.CamelSupport;
+import org.apache.camel.util.FileUtil;
+
+import static
org.apache.camel.quarkus.core.deployment.util.CamelSupport.CLASSPATH_PREFIX;
+
+class CamelRouteResourcesProcessor {
+ @BuildStep
+ void camelRouteResources(
+ Capabilities capabilities,
+ ApplicationArchivesBuildItem applicationArchives,
+ BuildProducer<CamelRouteResourceBuildItem> routeResource) {
+
+ if (CamelSupport.isRouteResourceDslCapabilitiesPresent(capabilities)) {
+ // Classpath route resources
+ Set<String> classpathIncludePatterns =
CamelMainHelper.routesIncludePattern()
+ .filter(pattern -> !pattern.contains(":") ||
pattern.startsWith(CLASSPATH_PREFIX))
+ .map(CamelSupport::stripClasspathScheme)
+ .collect(Collectors.toSet());
+
+ if (!classpathIncludePatterns.isEmpty()) {
+ Set<String> routeResourceFileExtensions =
CamelSupport.getRouteResourceFileExtensions(capabilities);
+ io.quarkus.paths.PathFilter pathFilter =
io.quarkus.paths.PathFilter.forIncludes(classpathIncludePatterns);
+
+ // Search the root application archive for routes
+ ApplicationArchive rootArchive =
applicationArchives.getRootArchive();
+ ResolvedDependency rootArchiveDependency =
rootArchive.getResolvedDependency();
+ PathVisitor rootArchivePathVisitor =
createPathVisitor(routeResourceFileExtensions, routeResource, true);
+
rootArchiveDependency.getContentTree(pathFilter).walk(rootArchivePathVisitor);
+
+ // Search other application archive for routes
+ PathVisitor appArchivePathVisitor =
createPathVisitor(routeResourceFileExtensions, routeResource, false);
+ for (ApplicationArchive archive :
applicationArchives.getApplicationArchives()) {
+ ResolvedDependency dependency =
archive.getResolvedDependency();
+
dependency.getContentTree(pathFilter).walk(appArchivePathVisitor);
+ }
+ }
+
+ // External file route resources
+ CamelMainHelper.routesIncludePattern()
+ .filter(pattern -> pattern.startsWith("file:"))
+ .map(CamelRouteResourceBuildItem::new)
+ .forEach(routeResource::produce);
+ }
+ }
+
+ private PathVisitor createPathVisitor(
+ Set<String> routeResourceFileExtensions,
+ BuildProducer<CamelRouteResourceBuildItem> routeResource,
+ boolean isHotReloadable) {
+ return new PathVisitor() {
+ @Override
+ public void visitPath(PathVisit visit) {
+ String path = visit.getPath().toString();
+ String extension = FileUtil.onlyExt(path);
+ if (routeResourceFileExtensions.contains(extension)) {
+ routeResource.produce(new
CamelRouteResourceBuildItem(CLASSPATH_PREFIX + path, isHotReloadable));
+ }
+ }
+ };
+ }
+}
diff --git
a/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/main/CamelMainHelper.java
b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/main/CamelMainHelper.java
index 716bbd2b9b..26e077ec2d 100644
---
a/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/main/CamelMainHelper.java
+++
b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/main/CamelMainHelper.java
@@ -17,7 +17,6 @@
package org.apache.camel.quarkus.core.deployment.main;
import java.util.function.Consumer;
-import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.camel.impl.engine.DefaultPackageScanResourceResolver;
@@ -26,6 +25,8 @@ import org.apache.camel.spi.Resource;
import org.apache.camel.util.AntPathMatcher;
public final class CamelMainHelper {
+ private static final String[] DEFAULT_ROUTES_INCLUDE_PATTERN = {
"classpath:camel/*",
+ "classpath:camel-template/*", "classpath:camel-rest/*" };
private static final String[] EMPTY_STRING_ARRAY = new String[0];
private CamelMainHelper() {
@@ -36,9 +37,8 @@ public final class CamelMainHelper {
"camel.main.routes-include-pattern", String[].class,
EMPTY_STRING_ARRAY);
final String[] i2 = CamelSupport.getOptionalConfigValue(
"camel.main.routesIncludePattern", String[].class,
EMPTY_STRING_ARRAY);
-
return i1.length == 0 && i2.length == 0
- ? Stream.empty()
+ ? Stream.of(DEFAULT_ROUTES_INCLUDE_PATTERN)
: Stream.concat(Stream.of(i1), Stream.of(i2)).filter(location
-> !"false".equals(location));
}
@@ -62,7 +62,7 @@ public final class CamelMainHelper {
try (DefaultPackageScanResourceResolver resolver = new
DefaultPackageScanResourceResolver()) {
resolver.setCamelContext(CamelSupport.newBuildTimeCamelContext(true));
String[] excludes = routesExcludePattern().toArray(String[]::new);
- for (String include :
routesIncludePattern().collect(Collectors.toList())) {
+ for (String include : routesIncludePattern().toList()) {
for (Resource resource : resolver.findResources(include)) {
if (AntPathMatcher.INSTANCE.anyMatch(excludes,
resource.getLocation())) {
return;
diff --git
a/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/main/CamelMainHotDeploymentProcessor.java
b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/main/CamelMainHotDeploymentProcessor.java
index fa8b0d313b..f70465e0eb 100644
---
a/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/main/CamelMainHotDeploymentProcessor.java
+++
b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/main/CamelMainHotDeploymentProcessor.java
@@ -16,53 +16,35 @@
*/
package org.apache.camel.quarkus.core.deployment.main;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
import java.util.List;
-import java.util.stream.Collectors;
+import io.quarkus.deployment.IsDevelopment;
+import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.annotations.BuildSteps;
import io.quarkus.deployment.builditem.HotDeploymentWatchedFileBuildItem;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import
org.apache.camel.quarkus.core.deployment.spi.CamelRouteResourceBuildItem;
+import org.jboss.logging.Logger;
+@BuildSteps(onlyIf = { IsDevelopment.class })
class CamelMainHotDeploymentProcessor {
- private static final Logger LOGGER =
LoggerFactory.getLogger(CamelMainHotDeploymentProcessor.class);
- private static final String FILE_PREFIX = "file:";
- private static final String CLASSPATH_PREFIX = "classpath:";
+ private static final Logger LOGGER =
Logger.getLogger(CamelMainHotDeploymentProcessor.class);
@BuildStep
- List<HotDeploymentWatchedFileBuildItem> locations() {
- List<HotDeploymentWatchedFileBuildItem> items =
CamelMainHelper.routesIncludePattern()
-
.map(CamelMainHotDeploymentProcessor::routesIncludePatternToLocation)
- .filter(location -> location != null)
+ void locations(
+ List<CamelRouteResourceBuildItem> camelRouteResources,
+ BuildProducer<HotDeploymentWatchedFileBuildItem>
hotDeploymentWatchedFile) {
+
+ camelRouteResources.stream()
+ .filter(CamelRouteResourceBuildItem::isHotReloadable)
+ .map(CamelRouteResourceBuildItem::getSourcePath)
+ .peek(location -> LOGGER.debugf("Configuring watched file %s",
location))
.distinct()
.map(HotDeploymentWatchedFileBuildItem::new)
- .collect(Collectors.toList());
-
- if (!items.isEmpty()) {
- LOGGER.info("HotDeployment files:");
- for (HotDeploymentWatchedFileBuildItem item : items) {
- LOGGER.info("- {}", item.getLocation());
- }
- }
-
- return items;
- }
+ .forEach(hotDeploymentWatchedFile::produce);
- private static String routesIncludePatternToLocation(String pattern) {
- if (pattern.startsWith(CLASSPATH_PREFIX)) {
- return pattern.substring(CLASSPATH_PREFIX.length());
- } else if (pattern.startsWith(FILE_PREFIX)) {
- String filePattern = pattern.substring(FILE_PREFIX.length());
- Path filePatternPath = Paths.get(filePattern);
- if (Files.exists(filePatternPath)) {
- return filePatternPath.toAbsolutePath().toString();
- }
- } else if (pattern.length() > 0) {
- return pattern;
+ if (!camelRouteResources.isEmpty()) {
+ LOGGER.info("Camel routes live reload enabled");
}
- return null;
}
}
diff --git
a/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/main/CamelMainNativeImageProcessor.java
b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/main/CamelMainNativeImageProcessor.java
index a0ecbe6462..b8e9559b27 100644
---
a/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/main/CamelMainNativeImageProcessor.java
+++
b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/main/CamelMainNativeImageProcessor.java
@@ -16,21 +16,16 @@
*/
package org.apache.camel.quarkus.core.deployment.main;
-import java.util.stream.Collectors;
+import java.util.List;
import java.util.stream.Stream;
-import io.quarkus.deployment.Capabilities;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import
io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
-import org.apache.camel.support.ResourceHelper;
-import org.apache.camel.util.AntPathMatcher;
-import org.jboss.logging.Logger;
+import
org.apache.camel.quarkus.core.deployment.spi.CamelRouteResourceBuildItem;
public class CamelMainNativeImageProcessor {
- private static final Logger LOG =
Logger.getLogger(CamelMainNativeImageProcessor.class);
-
@BuildStep
void reflectiveCLasses(BuildProducer<ReflectiveClassBuildItem> producer) {
// TODO: The classes below are needed to fix
https://github.com/apache/camel-quarkus/issues/1005
@@ -43,26 +38,15 @@ public class CamelMainNativeImageProcessor {
}
@BuildStep
- private void camelNativeImageResources(
- Capabilities capabilities,
+ void camelNativeImageResources(
+ List<CamelRouteResourceBuildItem> camelRouteResources,
BuildProducer<NativeImageResourceBuildItem> nativeResource) {
- for (String path :
CamelMainHelper.routesIncludePattern().collect(Collectors.toList())) {
- String scheme = ResourceHelper.getScheme(path);
-
- // Null scheme is equivalent to classpath scheme
- if (scheme == null || scheme.equals("classpath:")) {
- if (AntPathMatcher.INSTANCE.isPattern(path)) {
- // Classpath directory traversal via wildcard paths does
not work on GraalVM.
- // The exact path to the resource has to be looked up
- // https://github.com/oracle/graal/issues/1108
- LOG.warnf("Classpath wildcards does not work in native
mode. Resources matching %s will not be loaded.",
- path);
- } else {
- nativeResource.produce(new
NativeImageResourceBuildItem(path.replace("classpath:", "")));
- }
- }
- }
+ camelRouteResources.stream()
+ .filter(CamelRouteResourceBuildItem::isClasspathResource)
+ .map(CamelRouteResourceBuildItem::getSourcePath)
+ .map(NativeImageResourceBuildItem::new)
+ .forEach(nativeResource::produce);
String[] resources = Stream.of("components", "dataformats",
"languages")
.map(k -> "org/apache/camel/main/" + k + ".properties")
diff --git
a/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/spi/CamelRouteResourceBuildItem.java
b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/spi/CamelRouteResourceBuildItem.java
new file mode 100644
index 0000000000..c9850ff9dc
--- /dev/null
+++
b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/spi/CamelRouteResourceBuildItem.java
@@ -0,0 +1,89 @@
+/*
+ * 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.quarkus.core.deployment.spi;
+
+import java.nio.file.Paths;
+import java.util.Objects;
+
+import io.quarkus.builder.item.MultiBuildItem;
+import org.apache.camel.quarkus.core.util.FileUtils;
+import org.apache.camel.spi.Resource;
+import org.apache.camel.util.FileUtil;
+import org.apache.camel.util.StringHelper;
+
+import static
org.apache.camel.quarkus.core.deployment.util.CamelSupport.CLASSPATH_PREFIX;
+
+/**
+ * Holds a {@link Resource} relating to discovered Camel DSL route definition
files defined by
+ * route inclusion patterns configuration.
+ */
+public final class CamelRouteResourceBuildItem extends MultiBuildItem {
+ private static final String GRADLE_RESOURCES_PATH =
"build/resources/main/";
+ private static final String MAVEN_CLASSES_PATH = "target/classes/";
+ private final String location;
+ private final String sourcePath;
+ private final boolean isHotReloadable;
+
+ public CamelRouteResourceBuildItem(String location) {
+ this(location, true);
+ }
+
+ public CamelRouteResourceBuildItem(String location, boolean
isHotReloadable) {
+ Objects.requireNonNull(location, "location cannot be null");
+ this.location = FileUtils.nixifyPath(location);
+ this.sourcePath = computeSourcePath();
+ this.isHotReloadable = isHotReloadable;
+ }
+
+ public String getLocation() {
+ return location;
+ }
+
+ public String getSourcePath() {
+ return sourcePath;
+ }
+
+ public boolean isHotReloadable() {
+ return isHotReloadable;
+ }
+
+ public boolean isClasspathResource() {
+ return location.startsWith(CLASSPATH_PREFIX)
+ || location.contains(MAVEN_CLASSES_PATH)
+ || location.contains(GRADLE_RESOURCES_PATH);
+ }
+
+ private String computeSourcePath() {
+ String result = StringHelper.after(location, ":", location);
+
+ if (location.startsWith("file:")) {
+ return Paths.get(result).toAbsolutePath().toString();
+ }
+
+ result = FileUtil.stripLeadingSeparator(result);
+
+ if (location.contains(MAVEN_CLASSES_PATH)) {
+ result = StringHelper.after(location, MAVEN_CLASSES_PATH);
+ }
+
+ if (location.contains(GRADLE_RESOURCES_PATH)) {
+ result = StringHelper.after(location, GRADLE_RESOURCES_PATH);
+ }
+
+ return result;
+ }
+}
diff --git
a/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/util/CamelSupport.java
b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/util/CamelSupport.java
index a267617fed..3429a0b215 100644
---
a/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/util/CamelSupport.java
+++
b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/util/CamelSupport.java
@@ -30,10 +30,12 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import io.quarkus.deployment.ApplicationArchive;
+import io.quarkus.deployment.Capabilities;
import io.quarkus.deployment.builditem.ApplicationArchivesBuildItem;
import org.apache.camel.CamelContext;
import org.apache.camel.impl.DefaultCamelContext;
import org.apache.camel.impl.engine.AbstractCamelContext;
+import org.apache.camel.quarkus.core.CamelCapabilities;
import org.apache.camel.quarkus.core.deployment.spi.CamelServiceBuildItem;
import org.eclipse.microprofile.config.ConfigProvider;
import org.jboss.jandex.ClassInfo;
@@ -41,6 +43,7 @@ import org.jboss.jandex.ClassInfo;
public final class CamelSupport {
public static final String CAMEL_SERVICE_BASE_PATH =
"META-INF/services/org/apache/camel";
public static final String CAMEL_ROOT_PACKAGE_DIRECTORY =
"org/apache/camel";
+ public static final String CLASSPATH_PREFIX = "classpath:";
public static final String COMPILATION_JVM_TARGET = "17";
private CamelSupport() {
@@ -139,4 +142,37 @@ public final class CamelSupport {
}
return context;
}
+
+ public static String stripClasspathScheme(String path) {
+ Objects.requireNonNull(path, "path must not be null");
+ if (path.startsWith(CLASSPATH_PREFIX)) {
+ return path.substring(CLASSPATH_PREFIX.length());
+ }
+ return path;
+ }
+
+ public static boolean isRouteResourceDslCapabilitiesPresent(Capabilities
capabilities) {
+ return capabilities.isPresent(CamelCapabilities.XML_JAXB)
+ || capabilities.isPresent(CamelCapabilities.XML_IO_DSL)
+ || capabilities.isPresent(CamelCapabilities.YAML_DSL)
+ || capabilities.isPresent(CamelCapabilities.JAVA_JOOR_DSL);
+ }
+
+ public static Set<String> getRouteResourceFileExtensions(Capabilities
capabilities) {
+ Set<String> extensions = new HashSet<>();
+ if (capabilities.isPresent(CamelCapabilities.XML_JAXB) ||
capabilities.isPresent(CamelCapabilities.XML_IO_DSL)) {
+ extensions.add("xml");
+ }
+
+ if (capabilities.isPresent(CamelCapabilities.YAML_DSL)) {
+ extensions.add("yaml");
+ extensions.add("yml");
+ }
+
+ if (capabilities.isPresent(CamelCapabilities.JAVA_JOOR_DSL)) {
+ extensions.add("java");
+ }
+
+ return extensions;
+ }
}
diff --git
a/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelCapabilities.java
b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelCapabilities.java
index a625416c79..9f3697d542 100644
---
a/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelCapabilities.java
+++
b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelCapabilities.java
@@ -26,6 +26,7 @@ public final class CamelCapabilities {
public static final String XML_IO_DSL = "org.apache.camel.xml.io.dsl";
public static final String XML_JAXB = "org.apache.camel.xml.jaxb";
public static final String XML_JAXP = "org.apache.camel.xml.jaxp";
+ public static final String YAML_DSL = "org.apache.camel.yaml.dsl";
private CamelCapabilities() {
}
diff --git
a/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelQuarkusPackageScanResourceResolver.java
b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelQuarkusPackageScanResourceResolver.java
index 7d7dde7972..798d7892c5 100644
---
a/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelQuarkusPackageScanResourceResolver.java
+++
b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/CamelQuarkusPackageScanResourceResolver.java
@@ -16,16 +16,136 @@
*/
package org.apache.camel.quarkus.core;
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystemAlreadyExistsException;
+import java.nio.file.FileSystems;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.stream.Stream;
+
+import io.quarkus.runtime.ImageMode;
import org.apache.camel.impl.engine.DefaultPackageScanResourceResolver;
import org.apache.camel.spi.PackageScanResourceResolver;
+import org.apache.camel.spi.Resource;
+import org.apache.camel.spi.ResourceLoader;
+import org.apache.camel.support.PluginHelper;
+import org.apache.camel.support.ResourceHelper;
+import org.apache.camel.util.AntPathMatcher;
+import org.apache.camel.util.ObjectHelper;
+import org.jboss.logging.Logger;
/**
* Custom {@link PackageScanResourceResolver} that adds the specific {@link
ClassLoader} instance
- * that Camel Quarkus requires for resolving resources.
+ * that Camel Quarkus requires for resolving resources. Also performs native
image capable classpath glob pattern
+ * resource resolution.
*/
public class CamelQuarkusPackageScanResourceResolver extends
DefaultPackageScanResourceResolver {
+ private static final Logger LOG =
Logger.getLogger(CamelQuarkusPackageScanResourceResolver.class);
+ private static final URI NATIVE_IMAGE_FILESYSTEM_URI =
URI.create("resource:/");
+ private FileSystem resourceFileSystem;
+
@Override
public void initialize() {
addClassLoader(Thread.currentThread().getContextClassLoader());
}
+
+ @Override
+ protected void doStop() throws Exception {
+ if (resourceFileSystem != null) {
+ resourceFileSystem.close();
+ resourceFileSystem = null;
+ }
+ }
+
+ @Override
+ public Collection<Resource> findResources(String location) throws
Exception {
+ Collection<Resource> resources = super.findResources(location);
+
+ // If no matches were found for the location pattern in native mode,
try to use the resource scheme filesystem
+ if (resources.isEmpty() && ImageMode.current().isNativeImage()) {
+ String scheme = ResourceHelper.getScheme(location);
+ if (isClassPathPattern(location, scheme)) {
+ FileSystem fileSystem = getNativeImageResourceFileSystem();
+ ResourceLoader resourceLoader =
PluginHelper.getResourceLoader(getCamelContext());
+ String root =
AntPathMatcher.INSTANCE.determineRootDir(location);
+ String rootWithoutScheme = scheme != null ?
root.substring(scheme.length()) : root;
+ String subPattern = location.substring(root.length());
+ Path startPath = fileSystem.getPath(rootWithoutScheme);
+
+ if (!Files.exists(startPath)) {
+ LOG.tracef("Failed to find resources for location: %s as
path %s does not exist", location, startPath);
+ return resources;
+ }
+
+ LOG.tracef("Finding native resources for location: %s, sub
pattern %s, under path %s", location, subPattern,
+ rootWithoutScheme);
+
+ // Iterate classpath resources in the native application and
try to find matches
+ Files.walkFileTree(startPath, new SimpleFileVisitor<>() {
+ @Override
+ public FileVisitResult visitFile(Path file,
BasicFileAttributes attrs) {
+ Path pathToMatch = file.getNameCount() > 1 ?
file.subpath(1, file.getNameCount()) : file.getFileName();
+
+ LOG.tracef("Checking for native resource match for:
%s", pathToMatch);
+ if (AntPathMatcher.INSTANCE.match(subPattern,
pathToMatch.toString())) {
+ LOG.tracef("Matched native resource: %s with
pattern: %s", file, subPattern);
+
resources.add(resourceLoader.resolveResource(file.toString()));
+ }
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFileFailed(Path file,
IOException exc) {
+ LOG.tracef(exc, "Failed to process resource: %s",
file);
+ return FileVisitResult.CONTINUE;
+ }
+ });
+
+ // Fallback on matching files explicitly in the resolved
directory path
+ if (resources.isEmpty() && Files.isDirectory(startPath)) {
+ try (Stream<Path> files = Files.list(startPath)) {
+ files.map(Path::getFileName)
+ .map(Path::toString)
+ .filter(path ->
AntPathMatcher.INSTANCE.match(subPattern, path))
+ .map(path ->
startPath.resolve(path).toString())
+ .peek(path -> LOG.tracef("Matched native
resource: %s with pattern: %s", path, subPattern))
+ .map(resourceLoader::resolveResource)
+ .forEach(resources::add);
+ }
+ }
+ }
+ }
+
+ return resources;
+ }
+
+ protected boolean isClassPathPattern(String location, String scheme) {
+ if (ObjectHelper.isNotEmpty(location)) {
+ return (AntPathMatcher.INSTANCE.isPattern(location))
+ && (ObjectHelper.isEmpty(scheme) ||
"classpath:".equals(scheme));
+ }
+ return false;
+ }
+
+ protected FileSystem getNativeImageResourceFileSystem() {
+ // Must lazy init the FileSystem at runtime so that resources are
discoverable
+ if (resourceFileSystem == null) {
+ try {
+ resourceFileSystem =
FileSystems.newFileSystem(NATIVE_IMAGE_FILESYSTEM_URI,
+ Collections.singletonMap("create", "true"));
+ } catch (FileSystemAlreadyExistsException ex) {
+ resourceFileSystem =
FileSystems.getFileSystem(NATIVE_IMAGE_FILESYSTEM_URI);
+ } catch (IOException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+ return resourceFileSystem;
+ }
}
diff --git a/extensions-core/yaml-dsl/runtime/pom.xml
b/extensions-core/yaml-dsl/runtime/pom.xml
index 9c1f4b9760..2187736cb7 100644
--- a/extensions-core/yaml-dsl/runtime/pom.xml
+++ b/extensions-core/yaml-dsl/runtime/pom.xml
@@ -51,6 +51,11 @@
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-extension-maven-plugin</artifactId>
+ <configuration>
+ <capabilities>
+ <provides>org.apache.camel.yaml.dsl</provides>
+ </capabilities>
+ </configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
diff --git
a/extensions/openapi-java/deployment/src/main/java/org/apache/camel/quarkus/component/openapi/java/deployment/OpenApiJavaProcessor.java
b/extensions/openapi-java/deployment/src/main/java/org/apache/camel/quarkus/component/openapi/java/deployment/OpenApiJavaProcessor.java
index 77fd10d25e..981edaf5b2 100644
---
a/extensions/openapi-java/deployment/src/main/java/org/apache/camel/quarkus/component/openapi/java/deployment/OpenApiJavaProcessor.java
+++
b/extensions/openapi-java/deployment/src/main/java/org/apache/camel/quarkus/component/openapi/java/deployment/OpenApiJavaProcessor.java
@@ -24,6 +24,7 @@ import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
+import java.util.stream.Collectors;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonFactory;
@@ -55,6 +56,7 @@ import
org.apache.camel.openapi.DefaultRestDefinitionsResolver;
import org.apache.camel.openapi.RestDefinitionsResolver;
import org.apache.camel.openapi.RestOpenApiReader;
import org.apache.camel.openapi.RestOpenApiSupport;
+import org.apache.camel.quarkus.core.deployment.main.CamelMainHelper;
import
org.apache.camel.quarkus.core.deployment.spi.CamelRoutesBuilderClassBuildItem;
import org.apache.camel.quarkus.core.deployment.util.CamelSupport;
import org.apache.camel.spi.RestConfiguration;
@@ -97,9 +99,9 @@ class OpenApiJavaProcessor {
configurer.setRoutesBuilders(routes);
configurer.setRoutesCollector(new DefaultRoutesCollector());
configurer.setRoutesIncludePattern(
-
CamelSupport.getOptionalConfigValue("camel.main.routes-include-pattern",
String.class, null));
+
CamelMainHelper.routesIncludePattern().collect(Collectors.joining(",")));
configurer.setRoutesExcludePattern(
-
CamelSupport.getOptionalConfigValue("camel.main.routes-exclude-pattern",
String.class, null));
+
CamelMainHelper.routesExcludePattern().collect(Collectors.joining(",")));
final CamelContext ctx =
CamelSupport.newBuildTimeCamelContext(true);
if (!routesBuilderClasses.isEmpty()) {
diff --git
a/integration-test-groups/foundation/core/src/main/java/org/apache/camel/quarkus/core/CoreResource.java
b/integration-test-groups/foundation/core/src/main/java/org/apache/camel/quarkus/core/CoreResource.java
index a4fb5e45c2..2bbffd7ad5 100644
---
a/integration-test-groups/foundation/core/src/main/java/org/apache/camel/quarkus/core/CoreResource.java
+++
b/integration-test-groups/foundation/core/src/main/java/org/apache/camel/quarkus/core/CoreResource.java
@@ -35,6 +35,7 @@ import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import org.apache.camel.CamelContext;
@@ -43,8 +44,11 @@ import org.apache.camel.NoSuchLanguageException;
import org.apache.camel.catalog.RuntimeCamelCatalog;
import org.apache.camel.impl.engine.DefaultHeadersMapFactory;
import org.apache.camel.model.ModelCamelContext;
+import org.apache.camel.quarkus.core.util.FileUtils;
import org.apache.camel.spi.Registry;
+import org.apache.camel.spi.Resource;
import org.apache.camel.support.LRUCacheFactory;
+import org.apache.camel.support.PluginHelper;
import org.apache.camel.support.startup.DefaultStartupStepRecorder;
import org.jboss.logging.Logger;
@@ -284,4 +288,16 @@ public class CoreResource {
return ((MySerializationObject) is.readObject()).isCorrect();
}
+ @Path("/resource/resolve")
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public String resolveResource(@QueryParam("path") String path) throws
Exception {
+ return PluginHelper.getPackageScanResourceResolver(context)
+ .findResources(path)
+ .stream()
+ .filter(Resource::exists)
+ .map(Resource::getLocation)
+ .map(FileUtils::nixifyPath)
+ .collect(Collectors.joining(","));
+ }
}
diff --git
a/integration-test-groups/foundation/core/src/main/resources/application.properties
b/integration-test-groups/foundation/core/src/main/resources/application.properties
index 96499830f5..a46d41abaa 100644
---
a/integration-test-groups/foundation/core/src/main/resources/application.properties
+++
b/integration-test-groups/foundation/core/src/main/resources/application.properties
@@ -27,7 +27,7 @@ quarkus.camel.native.reflection.exclude-patterns =
org.apache.commons.lang3.tupl
# Quarkus :: Camel
#
quarkus.camel.runtime-catalog.languages = false
-quarkus.native.resources.includes = mysimple.txt,include-pattern-folder/*
+quarkus.native.resources.includes =
mysimple.txt,include-pattern-folder/*,sub-resources-folder/foo/bar/*
quarkus.native.resources.excludes =
exclude-pattern-folder/*,include-pattern-folder/excluded.txt
quarkus.camel.native.reflection.serialization-enabled = true
diff --git
a/integration-tests/main-yaml/src/main/resources/application.properties
b/integration-test-groups/foundation/core/src/main/resources/sub-resources-folder/foo/bar/test-1.txt
similarity index 86%
copy from integration-tests/main-yaml/src/main/resources/application.properties
copy to
integration-test-groups/foundation/core/src/main/resources/sub-resources-folder/foo/bar/test-1.txt
index 9abe188ba9..db0337dd5c 100644
--- a/integration-tests/main-yaml/src/main/resources/application.properties
+++
b/integration-test-groups/foundation/core/src/main/resources/sub-resources-folder/foo/bar/test-1.txt
@@ -14,9 +14,4 @@
## See the License for the specific language governing permissions and
## limitations under the License.
## ---------------------------------------------------------------------------
-
-#
-# Main
-#
-camel.main.routes-include-pattern =
routes/my-routes.yaml,routes/my-rests.yaml,routes/my-templates.yaml
-camel.main.dump-routes = yaml
+Test 1
\ No newline at end of file
diff --git
a/integration-tests/main-yaml/src/main/resources/application.properties
b/integration-test-groups/foundation/core/src/main/resources/sub-resources-folder/foo/bar/test-2.txt
similarity index 86%
copy from integration-tests/main-yaml/src/main/resources/application.properties
copy to
integration-test-groups/foundation/core/src/main/resources/sub-resources-folder/foo/bar/test-2.txt
index 9abe188ba9..8f10373c75 100644
--- a/integration-tests/main-yaml/src/main/resources/application.properties
+++
b/integration-test-groups/foundation/core/src/main/resources/sub-resources-folder/foo/bar/test-2.txt
@@ -14,9 +14,4 @@
## See the License for the specific language governing permissions and
## limitations under the License.
## ---------------------------------------------------------------------------
-
-#
-# Main
-#
-camel.main.routes-include-pattern =
routes/my-routes.yaml,routes/my-rests.yaml,routes/my-templates.yaml
-camel.main.dump-routes = yaml
+Test 2
\ No newline at end of file
diff --git
a/integration-test-groups/foundation/core/src/test/java/org/apache/camel/quarkus/core/CoreTest.java
b/integration-test-groups/foundation/core/src/test/java/org/apache/camel/quarkus/core/CoreTest.java
index bd7cc598b6..3c69d00ccc 100644
---
a/integration-test-groups/foundation/core/src/test/java/org/apache/camel/quarkus/core/CoreTest.java
+++
b/integration-test-groups/foundation/core/src/test/java/org/apache/camel/quarkus/core/CoreTest.java
@@ -137,4 +137,61 @@ public class CoreTest {
void testSerialization() {
RestAssured.when().get("/core/serialization").then().body(is("true"));
}
+
+ @Test
+ void classpathPackageScan() {
+ // Path without scheme
+ RestAssured.given()
+ .queryParam("path", "include-pattern-folder/included.txt")
+ .get("/core/resource/resolve")
+ .then()
+ .body(endsWith("include-pattern-folder/included.txt"));
+
+ // Classpath scheme
+ RestAssured.given()
+ .queryParam("path",
"classpath:include-pattern-folder/included.txt")
+ .get("/core/resource/resolve")
+ .then()
+ .body(endsWith("include-pattern-folder/included.txt"));
+
+ // Classpath globbing
+ RestAssured.given()
+ .queryParam("path", "sub-resources-folder/**")
+ .get("/core/resource/resolve")
+ .then()
+ .body(
+
containsString("sub-resources-folder/foo/bar/test-1.txt"),
+
containsString("sub-resources-folder/foo/bar/test-2.txt"));
+
+ RestAssured.given()
+ .queryParam("path", "sub-resources-folder/foo/**")
+ .get("/core/resource/resolve")
+ .then()
+ .body(
+
containsString("sub-resources-folder/foo/bar/test-1.txt"),
+
containsString("sub-resources-folder/foo/bar/test-2.txt"));
+
+ RestAssured.given()
+ .queryParam("path", "**/*.txt")
+ .get("/core/resource/resolve")
+ .then()
+ .body(
+
containsString("sub-resources-folder/foo/bar/test-1.txt"),
+
containsString("sub-resources-folder/foo/bar/test-2.txt"));
+
+ RestAssured.given()
+ .queryParam("path", "sub-resources-folder/foo/bar/*.txt")
+ .get("/core/resource/resolve")
+ .then()
+ .body(
+
containsString("sub-resources-folder/foo/bar/test-1.txt"),
+
containsString("sub-resources-folder/foo/bar/test-2.txt"));
+
+ // Resource that does not exist
+ RestAssured.given()
+ .queryParam("path", "sub-resources-folder/invalid")
+ .get("/core/resource/resolve")
+ .then()
+ .body(emptyOrNullString());
+ }
}
diff --git a/integration-tests/main-devmode/pom.xml
b/integration-tests/main-devmode/pom.xml
index 603590e8fc..91827472de 100644
--- a/integration-tests/main-devmode/pom.xml
+++ b/integration-tests/main-devmode/pom.xml
@@ -43,6 +43,10 @@
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-log</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-rest</artifactId>
+ </dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-timer</artifactId>
@@ -141,6 +145,19 @@
</exclusion>
</exclusions>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-rest-deployment</artifactId>
+ <version>${project.version}</version>
+ <type>pom</type>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>*</groupId>
+ <artifactId>*</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
<dependency>
<groupId>org.apache.camel.quarkus</groupId>
<artifactId>camel-quarkus-timer-deployment</artifactId>
diff --git
a/integration-tests/main-devmode/src/test/java/org/apache/camel/quarkus/main/CamelMainRoutesIncludePatternWithDefaultLocationsDevModeTest.java
b/integration-tests/main-devmode/src/test/java/org/apache/camel/quarkus/main/CamelMainRoutesIncludePatternWithDefaultLocationsDevModeTest.java
new file mode 100644
index 0000000000..f516438058
--- /dev/null
+++
b/integration-tests/main-devmode/src/test/java/org/apache/camel/quarkus/main/CamelMainRoutesIncludePatternWithDefaultLocationsDevModeTest.java
@@ -0,0 +1,141 @@
+/*
+ * 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.quarkus.main;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.Properties;
+import java.util.concurrent.TimeUnit;
+
+import io.quarkus.test.QuarkusDevModeTest;
+import io.restassured.RestAssured;
+import io.restassured.response.Response;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.asset.Asset;
+import org.jboss.shrinkwrap.api.asset.StringAsset;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.awaitility.Awaitility.await;
+
+public class CamelMainRoutesIncludePatternWithDefaultLocationsDevModeTest {
+ @RegisterExtension
+ static final QuarkusDevModeTest TEST = new QuarkusDevModeTest()
+ .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
+ .addClass(CamelSupportResource.class)
+ .addAsResource(routeXml(), "camel/routes.xml")
+ .addAsResource(restsXml(), "camel-rest/rests.xml")
+ .addAsResource(routeTemplateXml(),
"camel-template/templates.xml")
+ .addAsResource(applicationProperties(),
"application.properties"));
+
+ public static Asset routeXml() {
+ String xml = """
+ <?xml version="1.0" encoding="UTF-8"?>
+ <routes>
+ <route id="route1-from-default-location">
+ <from uri="direct:greeting"/>
+ <setBody><constant>Hello World</constant></setBody>
+ </route>
+ </routes>""";
+ return new StringAsset(xml);
+ }
+
+ public static Asset restsXml() {
+ String xml = """
+ <rests xmlns="http://camel.apache.org/schema/spring">
+ <rest id="rest1-from-default-location" path="/greeting">
+ <get path="/hello">
+ <to uri="direct:greeting"/>
+ </get>
+ </rest>
+ </rests>""";
+ return new StringAsset(xml);
+ }
+
+ public static Asset routeTemplateXml() {
+ String xml = """
+ <routeTemplates>
+ <routeTemplate id="template1-from-default-location">
+ <templateParameter name="name"/>
+ <templateParameter name="greeting"/>
+ <templateParameter name="myPeriod" defaultValue="3s"/>
+ <route>
+ <from uri="timer:{{name}}?period={{myPeriod}}"/>
+ <setBody><simple>{{greeting}}
${body}</simple></setBody>
+ <log message="${body}"/>
+ </route>
+ </routeTemplate>
+ </routeTemplates>""";
+ return new StringAsset(xml);
+ }
+
+ public static Asset applicationProperties() {
+ Writer writer = new StringWriter();
+
+ Properties props = new Properties();
+ props.setProperty("quarkus.banner.enabled", "false");
+
+ try {
+ props.store(writer, "");
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ return new StringAsset(writer.toString());
+ }
+
+ @Test
+ public void testRoutesDiscoveryFromDefaultLocation() {
+ await().atMost(10, TimeUnit.SECONDS).untilAsserted(() -> {
+ Response res =
RestAssured.when().get("/test/describe").thenReturn();
+
+ assertThat(res.statusCode()).isEqualTo(200);
+ assertThat(res.body().jsonPath().getList("routes",
String.class)).containsOnly("route1-from-default-location");
+ assertThat(res.body().jsonPath().getList("rests",
String.class)).containsOnly("rest1-from-default-location");
+ assertThat(res.body().jsonPath().getList("templates",
String.class))
+ .containsOnly("template1-from-default-location");
+ });
+
+ TEST.modifyResourceFile("camel/routes.xml", xml ->
xml.replaceAll("route1", "route2"));
+ await().atMost(10, TimeUnit.SECONDS).untilAsserted(() -> {
+ Response res =
RestAssured.when().get("/test/describe").thenReturn();
+
+ assertThat(res.statusCode()).isEqualTo(200);
+ assertThat(res.body().jsonPath().getList("routes",
String.class)).containsOnly("route2-from-default-location");
+ });
+
+ TEST.modifyResourceFile("camel-rest/rests.xml", xml ->
xml.replaceAll("rest1", "rest2"));
+ await().atMost(10, TimeUnit.SECONDS).untilAsserted(() -> {
+ Response res =
RestAssured.when().get("/test/describe").thenReturn();
+
+ assertThat(res.statusCode()).isEqualTo(200);
+ assertThat(res.body().jsonPath().getList("rests",
String.class)).containsOnly("rest2-from-default-location");
+ });
+
+ TEST.modifyResourceFile("camel-template/templates.xml", xml ->
xml.replaceAll("template1", "template2"));
+ await().atMost(10, TimeUnit.SECONDS).untilAsserted(() -> {
+ Response res =
RestAssured.when().get("/test/describe").thenReturn();
+
+ assertThat(res.statusCode()).isEqualTo(200);
+ assertThat(res.body().jsonPath().getList("templates",
String.class))
+ .containsOnly("template2-from-default-location");
+ });
+ }
+}
diff --git
a/integration-tests/main-devmode/src/test/java/org/apache/camel/quarkus/main/CamelSupportResource.java
b/integration-tests/main-devmode/src/test/java/org/apache/camel/quarkus/main/CamelSupportResource.java
index 07aa03ec4b..8702cc89c0 100644
---
a/integration-tests/main-devmode/src/test/java/org/apache/camel/quarkus/main/CamelSupportResource.java
+++
b/integration-tests/main-devmode/src/test/java/org/apache/camel/quarkus/main/CamelSupportResource.java
@@ -26,6 +26,7 @@ import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import org.apache.camel.CamelContext;
+import org.apache.camel.model.Model;
@Path("/test")
@ApplicationScoped
@@ -38,10 +39,18 @@ public class CamelSupportResource {
@Produces(MediaType.APPLICATION_JSON)
public JsonObject describeMain() {
JsonArrayBuilder routes = Json.createArrayBuilder();
+ JsonArrayBuilder rests = Json.createArrayBuilder();
+ JsonArrayBuilder templates = Json.createArrayBuilder();
context.getRoutes().forEach(route -> routes.add(route.getId()));
+ Model model =
context.getCamelContextExtension().getContextPlugin(Model.class);
+ model.getRestDefinitions().forEach(rest -> rests.add(rest.getId()));
+ model.getRouteTemplateDefinitions().forEach(template ->
templates.add(template.getId()));
+
return Json.createObjectBuilder()
.add("routes", routes)
+ .add("rests", rests)
+ .add("templates", templates)
.build();
}
diff --git
a/integration-tests/main-yaml/src/main/resources/application.properties
b/integration-tests/main-yaml/src/main/resources/application.properties
index 9abe188ba9..9c10a36dec 100644
--- a/integration-tests/main-yaml/src/main/resources/application.properties
+++ b/integration-tests/main-yaml/src/main/resources/application.properties
@@ -18,5 +18,4 @@
#
# Main
#
-camel.main.routes-include-pattern =
routes/my-routes.yaml,routes/my-rests.yaml,routes/my-templates.yaml
camel.main.dump-routes = yaml
diff --git
a/integration-tests/main-yaml/src/main/resources/routes/my-rests.yaml
b/integration-tests/main-yaml/src/main/resources/camel-rest/my-rests.yaml
similarity index 100%
rename from integration-tests/main-yaml/src/main/resources/routes/my-rests.yaml
rename to
integration-tests/main-yaml/src/main/resources/camel-rest/my-rests.yaml
diff --git
a/integration-tests/main-yaml/src/main/resources/routes/my-templates.yaml
b/integration-tests/main-yaml/src/main/resources/camel-template/my-templates.yaml
similarity index 100%
rename from
integration-tests/main-yaml/src/main/resources/routes/my-templates.yaml
rename to
integration-tests/main-yaml/src/main/resources/camel-template/my-templates.yaml
diff --git
a/integration-tests/main-yaml/src/main/resources/routes/my-routes.yaml
b/integration-tests/main-yaml/src/main/resources/camel/my-routes.yaml
similarity index 100%
rename from integration-tests/main-yaml/src/main/resources/routes/my-routes.yaml
rename to integration-tests/main-yaml/src/main/resources/camel/my-routes.yaml