You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by gg...@apache.org on 2023/03/14 13:24:12 UTC

[camel] branch main updated (ee2df1d95b2 -> b15fbe60572)

This is an automated email from the ASF dual-hosted git repository.

ggrzybek pushed a change to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


    from ee2df1d95b2 Sync deps
     new a47c5971232 [CAMEL-19123] Upgrade to maven-resolver 1.9.7 and move away from wagon transport
     new 8ed744ebad8 [CAMEL-11767] Fix dummy-component used in @Disabled tests
     new c19abe7db63 [CAMEL-11767] Fix MavenVersionManagerManualTest#testEndpointOptions218OrNewer()
     new b15fbe60572 [CAMEL-11767] Create camel-tooling-maven module that provides Maven downloader for camel-catalog-maven and camel-kamelet-main

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 bom/camel-bom/pom.xml                              |   10 +
 camel-dependencies/pom.xml                         |    3 +-
 catalog/camel-catalog-maven/pom.xml                |   12 +-
 .../maven/DefaultMavenArtifactProvider.java        |   68 +-
 .../camel/catalog/maven/MavenVersionManager.java   |  121 ++-
 .../camel/catalog/maven/OpenURLClassLoader.java    |   28 +-
 .../catalog/maven/TimeoutHttpClientHandler.java    |   72 --
 .../maven/MavenArtifactProviderManualTest.java     |    8 +-
 .../maven/MavenVersionManagerManualTest.java       |    2 +
 catalog/dummy-component/pom.xml                    |   45 +-
 .../component/dummy/DummyComponentConfigurer.java  |   55 +
 .../component/dummy/DummyEndpointConfigurer.java   |   55 +
 .../component/dummy/DummyEndpointUriFactory.java   |   71 ++
 .../services/org/apache/camel/component.properties |    7 +
 .../services/org/apache/camel/component/dummy      |    2 +
 .../org/apache/camel/configurer/dummy-component    |    2 +
 .../org/apache/camel/configurer/dummy-endpoint     |    2 +
 .../org/apache/camel/urifactory/dummy-endpoint     |    2 +
 .../org/apache/camel/component/dummy/dummy.json    |   34 +
 .../src/main/docs/dummy-component.adoc             |   29 +
 .../camel/component/dummy/DummyEndpoint.java       |    4 +-
 .../dsl/jbang/core/commands/DependencyList.java    |    2 +-
 .../camel/dsl/jbang/core/commands/Export.java      |    2 +-
 .../dsl/jbang/core/commands/ExportBaseCommand.java |    2 +-
 .../dsl/jbang/core/commands/ExportCamelMain.java   |    2 +-
 .../dsl/jbang/core/commands/ExportQuarkus.java     |    2 +-
 .../dsl/jbang/core/commands/ExportSpringBoot.java  |    2 +-
 .../core/commands/catalog/CatalogBaseCommand.java  |    2 +-
 .../jbang/core/commands/catalog/CatalogDoc.java    |    2 +-
 .../dsl/jbang/core/commands/process/Hawtio.java    |    2 +-
 .../jbang/core/commands/version/VersionList.java   |    2 +-
 .../camel/dsl/jbang/core/common/CatalogLoader.java |    2 +-
 dsl/camel-kamelet-main/pom.xml                     |   66 +-
 .../download/AutoConfigureDownloadListener.java    |    1 +
 .../download/CommandLineDependencyDownloader.java  |    1 +
 .../camel/main/download/DependencyDownloader.java  |    3 +-
 .../DependencyDownloaderClassResolver.java         |    1 +
 .../main/download/DependencyDownloaderKamelet.java |    1 +
 ...ependencyDownloaderPropertyBindingListener.java |    1 +
 .../download/DependencyDownloaderStrategy.java     |    1 +
 .../main/download/KnownDependenciesResolver.java   |    1 +
 .../main/download/MavenDependencyDownloader.java   | 1135 ++------------------
 .../camel/main/MavenDependencyResolverTest.java    |  245 +----
 parent/pom.xml                                     |   13 +-
 tooling/camel-tooling-maven/pom.xml                |  126 +++
 .../apache/camel/tooling/maven}/MavenArtifact.java |    5 +-
 .../camel/tooling/maven/MavenDownloader.java       |   67 ++
 .../camel/tooling/maven/MavenDownloaderImpl.java   | 1059 ++++++++----------
 .../org/apache/camel/tooling/maven}/MavenGav.java  |   57 +-
 .../tooling/maven/MavenResolutionException.java    |   28 +-
 .../apache/camel/tooling/maven/package-info.java   |   36 +-
 .../camel/tooling/maven/support}/DIRegistry.java   |    9 +-
 .../camel/tooling/maven/support/package-info.java  |   30 +-
 .../apache/camel/tooling/maven}/MavenGavTest.java  |    3 +-
 .../camel/tooling/maven/MavenResolverTest.java     |   64 +-
 .../org/apache/camel/tooling/maven/MavenTest.java  |   44 +
 .../tooling/maven/support}/DIRegistryTest.java     |    2 +-
 .../src/test/resources/.m2/settings-security.xml   |    0
 .../src/test/resources/.m2/settings.xml            |    0
 .../src/test/resources/log4j2.properties           |   28 +
 tooling/pom.xml                                    |    1 +
 61 files changed, 1360 insertions(+), 2322 deletions(-)
 copy dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenArtifact.java => catalog/camel-catalog-maven/src/main/java/org/apache/camel/catalog/maven/OpenURLClassLoader.java (66%)
 delete mode 100644 catalog/camel-catalog-maven/src/main/java/org/apache/camel/catalog/maven/TimeoutHttpClientHandler.java
 create mode 100644 catalog/dummy-component/src/generated/java/org/apache/camel/component/dummy/DummyComponentConfigurer.java
 create mode 100644 catalog/dummy-component/src/generated/java/org/apache/camel/component/dummy/DummyEndpointConfigurer.java
 create mode 100644 catalog/dummy-component/src/generated/java/org/apache/camel/component/dummy/DummyEndpointUriFactory.java
 create mode 100644 catalog/dummy-component/src/generated/resources/META-INF/services/org/apache/camel/component.properties
 create mode 100644 catalog/dummy-component/src/generated/resources/META-INF/services/org/apache/camel/component/dummy
 create mode 100644 catalog/dummy-component/src/generated/resources/META-INF/services/org/apache/camel/configurer/dummy-component
 create mode 100644 catalog/dummy-component/src/generated/resources/META-INF/services/org/apache/camel/configurer/dummy-endpoint
 create mode 100644 catalog/dummy-component/src/generated/resources/META-INF/services/org/apache/camel/urifactory/dummy-endpoint
 create mode 100644 catalog/dummy-component/src/generated/resources/org/apache/camel/component/dummy/dummy.json
 create mode 100644 catalog/dummy-component/src/main/docs/dummy-component.adoc
 create mode 100644 tooling/camel-tooling-maven/pom.xml
 copy {dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download => tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven}/MavenArtifact.java (89%)
 create mode 100644 tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/MavenDownloader.java
 copy dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenDependencyDownloader.java => tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/MavenDownloaderImpl.java (62%)
 rename {dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download => tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven}/MavenGav.java (80%)
 copy dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenArtifact.java => tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/MavenResolutionException.java (61%)
 copy dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenArtifact.java => tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/package-info.java (63%)
 rename {dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/injection => tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/support}/DIRegistry.java (96%)
 rename dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenArtifact.java => tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/support/package-info.java (63%)
 rename {dsl/camel-kamelet-main/src/test/java/org/apache/camel/main => tooling/camel-tooling-maven/src/test/java/org/apache/camel/tooling/maven}/MavenGavTest.java (95%)
 copy dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/MavenDependencyResolverTest.java => tooling/camel-tooling-maven/src/test/java/org/apache/camel/tooling/maven/MavenResolverTest.java (83%)
 create mode 100644 tooling/camel-tooling-maven/src/test/java/org/apache/camel/tooling/maven/MavenTest.java
 rename {dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/injection => tooling/camel-tooling-maven/src/test/java/org/apache/camel/tooling/maven/support}/DIRegistryTest.java (99%)
 rename {dsl/camel-kamelet-main => tooling/camel-tooling-maven}/src/test/resources/.m2/settings-security.xml (100%)
 rename {dsl/camel-kamelet-main => tooling/camel-tooling-maven}/src/test/resources/.m2/settings.xml (100%)
 create mode 100644 tooling/camel-tooling-maven/src/test/resources/log4j2.properties


[camel] 03/04: [CAMEL-11767] Fix MavenVersionManagerManualTest#testEndpointOptions218OrNewer()

Posted by gg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ggrzybek pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git

commit c19abe7db63c2a725b081a563929e7a3b845f308
Author: Grzegorz Grzybek <gr...@gmail.com>
AuthorDate: Tue Mar 7 13:40:06 2023 +0100

    [CAMEL-11767] Fix MavenVersionManagerManualTest#testEndpointOptions218OrNewer()
---
 .../org/apache/camel/catalog/maven/MavenVersionManagerManualTest.java   | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/catalog/camel-catalog-maven/src/test/java/org/apache/camel/catalog/maven/MavenVersionManagerManualTest.java b/catalog/camel-catalog-maven/src/test/java/org/apache/camel/catalog/maven/MavenVersionManagerManualTest.java
index edacc1c119a..93a82165ebc 100644
--- a/catalog/camel-catalog-maven/src/test/java/org/apache/camel/catalog/maven/MavenVersionManagerManualTest.java
+++ b/catalog/camel-catalog-maven/src/test/java/org/apache/camel/catalog/maven/MavenVersionManagerManualTest.java
@@ -79,6 +79,8 @@ public class MavenVersionManagerManualTest {
     @Test
     public void testEndpointOptions218OrNewer() {
         CamelCatalog catalog = new DefaultCamelCatalog(false);
+        catalog.setVersionManager(new MavenVersionManager());
+        catalog.loadVersion("2.18.3");
 
         String json = catalog.componentJSonSchema("ahc");
         assertNotNull(json);


[camel] 04/04: [CAMEL-11767] Create camel-tooling-maven module that provides Maven downloader for camel-catalog-maven and camel-kamelet-main

Posted by gg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ggrzybek pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git

commit b15fbe605729b7371485d936e4683c2fe589f8b1
Author: Grzegorz Grzybek <gr...@gmail.com>
AuthorDate: Mon Mar 13 14:14:40 2023 +0100

    [CAMEL-11767] Create camel-tooling-maven module that provides Maven downloader for camel-catalog-maven and camel-kamelet-main
---
 bom/camel-bom/pom.xml                              |    5 +
 camel-dependencies/pom.xml                         |    1 +
 catalog/camel-catalog-maven/pom.xml                |   12 +-
 .../maven/DefaultMavenArtifactProvider.java        |   68 +-
 .../camel/catalog/maven/MavenVersionManager.java   |  121 +-
 .../camel/catalog/maven/OpenURLClassLoader.java    |   28 +-
 .../catalog/maven/TimeoutHttpClientHandler.java    |   72 --
 .../maven/MavenArtifactProviderManualTest.java     |    8 +-
 .../dsl/jbang/core/commands/DependencyList.java    |    2 +-
 .../camel/dsl/jbang/core/commands/Export.java      |    2 +-
 .../dsl/jbang/core/commands/ExportBaseCommand.java |    2 +-
 .../dsl/jbang/core/commands/ExportCamelMain.java   |    2 +-
 .../dsl/jbang/core/commands/ExportQuarkus.java     |    2 +-
 .../dsl/jbang/core/commands/ExportSpringBoot.java  |    2 +-
 .../core/commands/catalog/CatalogBaseCommand.java  |    2 +-
 .../jbang/core/commands/catalog/CatalogDoc.java    |    2 +-
 .../dsl/jbang/core/commands/process/Hawtio.java    |    2 +-
 .../jbang/core/commands/version/VersionList.java   |    2 +-
 .../camel/dsl/jbang/core/common/CatalogLoader.java |    2 +-
 dsl/camel-kamelet-main/pom.xml                     |   51 +-
 .../download/AutoConfigureDownloadListener.java    |    1 +
 .../download/CommandLineDependencyDownloader.java  |    1 +
 .../camel/main/download/DependencyDownloader.java  |    3 +-
 .../DependencyDownloaderClassResolver.java         |    1 +
 .../main/download/DependencyDownloaderKamelet.java |    1 +
 ...ependencyDownloaderPropertyBindingListener.java |    1 +
 .../download/DependencyDownloaderStrategy.java     |    1 +
 .../main/download/KnownDependenciesResolver.java   |    1 +
 .../main/download/MavenDependencyDownloader.java   | 1171 ++------------------
 .../camel/main/MavenDependencyResolverTest.java    |  245 +---
 parent/pom.xml                                     |    6 +
 tooling/camel-tooling-maven/pom.xml                |  126 +++
 .../apache/camel/tooling/maven}/MavenArtifact.java |    5 +-
 .../camel/tooling/maven/MavenDownloader.java       |   67 ++
 .../camel/tooling/maven/MavenDownloaderImpl.java   |  925 ++++++----------
 .../org/apache/camel/tooling/maven}/MavenGav.java  |   57 +-
 .../tooling/maven/MavenResolutionException.java    |   28 +-
 .../apache/camel/tooling/maven/package-info.java   |   36 +-
 .../camel/tooling/maven/support}/DIRegistry.java   |    9 +-
 .../camel/tooling/maven/support/package-info.java  |   30 +-
 .../apache/camel/tooling/maven}/MavenGavTest.java  |    3 +-
 .../camel/tooling/maven/MavenResolverTest.java     |   62 +-
 .../org/apache/camel/tooling/maven/MavenTest.java  |   44 +
 .../tooling/maven/support}/DIRegistryTest.java     |    2 +-
 .../src/test/resources/.m2/settings-security.xml   |    0
 .../src/test/resources/.m2/settings.xml            |    0
 .../src/test/resources/log4j2.properties           |   28 +
 tooling/pom.xml                                    |    1 +
 48 files changed, 950 insertions(+), 2293 deletions(-)

diff --git a/bom/camel-bom/pom.xml b/bom/camel-bom/pom.xml
index 448af304d5a..6be233b8cdd 100644
--- a/bom/camel-bom/pom.xml
+++ b/bom/camel-bom/pom.xml
@@ -1872,6 +1872,11 @@
         <artifactId>camel-timer</artifactId>
         <version>${project.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>camel-tooling-maven</artifactId>
+        <version>${project.version}</version>
+      </dependency>
       <dependency>
         <groupId>org.apache.camel</groupId>
         <artifactId>camel-tooling-model</artifactId>
diff --git a/camel-dependencies/pom.xml b/camel-dependencies/pom.xml
index fae851941b0..bd17292761b 100644
--- a/camel-dependencies/pom.xml
+++ b/camel-dependencies/pom.xml
@@ -258,6 +258,7 @@
         <jakarta-enterprise-cdi-api-version>4.0.1</jakarta-enterprise-cdi-api-version>
         <jakarta-api-version>2.1.5</jakarta-api-version>
         <jakarta.el-version>3.0.3</jakarta.el-version>
+        <jakarta-inject-version>2.0.1</jakarta-inject-version>
         <jakarta-xml-bind-api-version>4.0.0</jakarta-xml-bind-api-version>
         <jakarta-xml-soap-api-version>3.0.0</jakarta-xml-soap-api-version>
         <jakarta-xml-ws-api-version>4.0.0</jakarta-xml-ws-api-version>
diff --git a/catalog/camel-catalog-maven/pom.xml b/catalog/camel-catalog-maven/pom.xml
index 9ef12b787cc..283aba6503d 100644
--- a/catalog/camel-catalog-maven/pom.xml
+++ b/catalog/camel-catalog-maven/pom.xml
@@ -91,16 +91,10 @@
             </exclusions>
         </dependency>
 
-        <!-- use groovy grape to download JARs as that is easy to use -->
+        <!-- use camel-tooling-maven for artifact downloading -->
         <dependency>
-            <groupId>org.apache.groovy</groupId>
-            <artifactId>groovy</artifactId>
-            <version>${groovy-version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.ivy</groupId>
-            <artifactId>ivy</artifactId>
-            <version>${ivy-version}</version>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-tooling-maven</artifactId>
         </dependency>
 
         <!-- testing -->
diff --git a/catalog/camel-catalog-maven/src/main/java/org/apache/camel/catalog/maven/DefaultMavenArtifactProvider.java b/catalog/camel-catalog-maven/src/main/java/org/apache/camel/catalog/maven/DefaultMavenArtifactProvider.java
index 97e41203e23..429a218a752 100644
--- a/catalog/camel-catalog-maven/src/main/java/org/apache/camel/catalog/maven/DefaultMavenArtifactProvider.java
+++ b/catalog/camel-catalog-maven/src/main/java/org/apache/camel/catalog/maven/DefaultMavenArtifactProvider.java
@@ -16,15 +16,19 @@
  */
 package org.apache.camel.catalog.maven;
 
-import java.util.HashMap;
+import java.util.Collections;
+import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
 
-import groovy.grape.Grape;
-import groovy.lang.GroovyClassLoader;
 import org.apache.camel.catalog.CamelCatalog;
+import org.apache.camel.tooling.maven.MavenArtifact;
+import org.apache.camel.tooling.maven.MavenDownloader;
+import org.apache.camel.tooling.maven.MavenDownloaderImpl;
+import org.eclipse.aether.ConfigurationProperties;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -38,9 +42,18 @@ import static org.apache.camel.catalog.maven.ComponentArtifactHelper.loadCompone
 public class DefaultMavenArtifactProvider implements MavenArtifactProvider {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(DefaultMavenArtifactProvider.class);
-    private String cacheDirectory;
+    private String localRepository;
     private boolean log;
 
+    private final MavenDownloader downloader;
+
+    private final Map<String, String> repositories = new LinkedHashMap<>();
+
+    public DefaultMavenArtifactProvider() {
+        downloader = new MavenDownloaderImpl();
+        ((MavenDownloaderImpl) downloader).build();
+    }
+
     /**
      * Sets whether to log errors and warnings to System.out. By default nothing is logged.
      */
@@ -50,15 +63,12 @@ public class DefaultMavenArtifactProvider implements MavenArtifactProvider {
 
     @Override
     public void setCacheDirectory(String directory) {
-        this.cacheDirectory = directory;
+        this.localRepository = directory;
     }
 
     @Override
     public void addMavenRepository(String name, String url) {
-        Map<String, Object> repo = new HashMap<>();
-        repo.put("name", name);
-        repo.put("root", url);
-        Grape.addResolver(repo);
+        repositories.put(name, url);
     }
 
     @Override
@@ -68,30 +78,34 @@ public class DefaultMavenArtifactProvider implements MavenArtifactProvider {
         final Set<String> names = new LinkedHashSet<>();
 
         try {
-            if (cacheDirectory != null) {
+            MavenDownloader mavenDownloader = downloader;
+            if (localRepository != null) {
                 if (log) {
-                    LOGGER.debug("Using cache directory: {}", cacheDirectory);
+                    LOGGER.debug("Using cache directory: {}", localRepository);
                 }
-                System.setProperty("grape.root", cacheDirectory);
+                // customize only local repository
+                mavenDownloader = mavenDownloader.customize(localRepository,
+                        ConfigurationProperties.DEFAULT_CONNECT_TIMEOUT,
+                        ConfigurationProperties.DEFAULT_REQUEST_TIMEOUT);
             }
 
-            Grape.setEnableAutoDownload(true);
-
-            try (final GroovyClassLoader classLoader = new GroovyClassLoader()) {
-
-                Map<String, Object> param = new HashMap<>();
-                param.put("classLoader", classLoader);
-                param.put("group", groupId);
-                param.put("module", artifactId);
-                param.put("version", version);
-                // no need to download transitive dependencies as we only need to check the component itself
-                param.put("validate", false);
-                param.put("transitive", false);
+            if (log) {
+                LOGGER.info("Downloading {}:{}:{}", groupId, artifactId, version);
+            }
 
-                if (log) {
-                    LOGGER.info("Downloading {}:{}:{}", groupId, artifactId, version);
+            try (OpenURLClassLoader classLoader = new OpenURLClassLoader()) {
+                if (version == null || "".equals(version.trim())) {
+                    version = "LATEST";
+                }
+                String gav = String.format("%s:%s:%s", groupId, artifactId, version);
+                Set<String> extraRepositories = new LinkedHashSet<>(repositories.values());
+                List<MavenArtifact> artifacts
+                        = mavenDownloader.resolveArtifacts(Collections.singletonList(gav), extraRepositories,
+                                false, version.contains("SNAPSHOT"));
+
+                for (MavenArtifact ma : artifacts) {
+                    classLoader.addURL(ma.getFile().toURI().toURL());
                 }
-                Grape.grab(param);
 
                 // the classloader can load content from the downloaded JAR
                 if (camelCatalog != null) {
diff --git a/catalog/camel-catalog-maven/src/main/java/org/apache/camel/catalog/maven/MavenVersionManager.java b/catalog/camel-catalog-maven/src/main/java/org/apache/camel/catalog/maven/MavenVersionManager.java
index e41858f5ff9..fb41f62f809 100644
--- a/catalog/camel-catalog-maven/src/main/java/org/apache/camel/catalog/maven/MavenVersionManager.java
+++ b/catalog/camel-catalog-maven/src/main/java/org/apache/camel/catalog/maven/MavenVersionManager.java
@@ -19,15 +19,22 @@ package org.apache.camel.catalog.maven;
 import java.io.Closeable;
 import java.io.IOException;
 import java.io.InputStream;
+import java.net.MalformedURLException;
 import java.net.URL;
+import java.util.Collections;
 import java.util.Enumeration;
-import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
-import groovy.grape.Grape;
-import groovy.lang.GroovyClassLoader;
 import org.apache.camel.catalog.VersionManager;
-import org.apache.ivy.util.url.URLHandlerRegistry;
+import org.apache.camel.tooling.maven.MavenArtifact;
+import org.apache.camel.tooling.maven.MavenDownloader;
+import org.apache.camel.tooling.maven.MavenDownloaderImpl;
+import org.apache.camel.tooling.maven.MavenResolutionException;
+import org.eclipse.aether.ConfigurationProperties;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -35,20 +42,34 @@ import org.slf4j.LoggerFactory;
  * A {@link VersionManager} that can load the resources using Maven to download needed artifacts from a local or remote
  * Maven repository.
  * <p/>
- * This implementation uses Groovy Grape to download the Maven JARs.
+ * This implementation uses Maven Resolver to download the Maven JARs.
  */
 public class MavenVersionManager implements VersionManager, Closeable {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(MavenVersionManager.class);
 
     private ClassLoader classLoader;
-    private final ClassLoader groovyClassLoader = new GroovyClassLoader();
-    private final TimeoutHttpClientHandler httpClient = new TimeoutHttpClientHandler();
+    private final OpenURLClassLoader helperClassLoader = new OpenURLClassLoader();
+
     private String version;
     private String runtimeProviderVersion;
-    private String cacheDirectory;
+    private String localRepository;
     private boolean log;
 
+    private final MavenDownloader downloader;
+
+    private final Map<String, String> repositories = new LinkedHashMap<>();
+
+    private int connectTimeout = ConfigurationProperties.DEFAULT_CONNECT_TIMEOUT;
+    private int requestTimeout = ConfigurationProperties.DEFAULT_REQUEST_TIMEOUT;
+
+    private boolean customized;
+
+    public MavenVersionManager() {
+        downloader = new MavenDownloaderImpl();
+        ((MavenDownloaderImpl) downloader).build();
+    }
+
     @Override
     public void setClassLoader(ClassLoader classLoader) {
         this.classLoader = classLoader;
@@ -57,12 +78,13 @@ public class MavenVersionManager implements VersionManager, Closeable {
     /**
      * Configures the directory for the download cache.
      * <p/>
-     * The default folder is <tt>USER_HOME/.groovy/grape</tt>
+     * The default folder is <tt>USER_HOME/.m2/repository</tt>
      *
      * @param directory the directory.
      */
     public void setCacheDirectory(String directory) {
-        this.cacheDirectory = directory;
+        this.localRepository = directory;
+        this.customized = true;
     }
 
     /**
@@ -73,12 +95,23 @@ public class MavenVersionManager implements VersionManager, Closeable {
     }
 
     /**
-     * Sets the timeout in millis (http.socket.timeout) when downloading via http/https protocols.
+     * Sets the connection timeout in millis when downloading via http/https protocols.
      * <p/>
      * The default value is 10000
      */
     public void setHttpClientTimeout(int timeout) {
-        httpClient.setTimeout(timeout);
+        this.connectTimeout = timeout;
+        this.customized = true;
+    }
+
+    /**
+     * Sets the read timeout in millis when downloading via http/https protocols.
+     * <p/>
+     * The default value is 1800000
+     */
+    public void setHttpClientRequestTimeout(int timeout) {
+        this.requestTimeout = timeout;
+        this.customized = true;
     }
 
     /**
@@ -88,10 +121,7 @@ public class MavenVersionManager implements VersionManager, Closeable {
      * @param url  the repository url
      */
     public void addMavenRepository(String name, String url) {
-        Map<String, Object> repo = new HashMap<>();
-        repo.put("name", name);
-        repo.put("root", url);
-        Grape.addResolver(repo);
+        repositories.put(name, url);
     }
 
     @Override
@@ -102,21 +132,13 @@ public class MavenVersionManager implements VersionManager, Closeable {
     @Override
     public boolean loadVersion(String version) {
         try {
-            URLHandlerRegistry.setDefault(httpClient);
-
-            if (cacheDirectory != null) {
-                System.setProperty("grape.root", cacheDirectory);
+            MavenDownloader mavenDownloader = downloader;
+            if (customized) {
+                mavenDownloader = mavenDownloader.customize(localRepository, connectTimeout, requestTimeout);
             }
 
-            Grape.setEnableAutoDownload(true);
-
-            Map<String, Object> param = new HashMap<>();
-            param.put("classLoader", groovyClassLoader);
-            param.put("group", "org.apache.camel");
-            param.put("module", "camel-catalog");
-            param.put("version", version);
-
-            Grape.grab(param);
+            String camelCatalogGAV = String.format("org.apache.camel:camel-catalog:%s", version);
+            resolve(mavenDownloader, camelCatalogGAV, version.contains("SNAPSHOT"));
 
             this.version = version;
             return true;
@@ -136,17 +158,13 @@ public class MavenVersionManager implements VersionManager, Closeable {
     @Override
     public boolean loadRuntimeProviderVersion(String groupId, String artifactId, String version) {
         try {
-            URLHandlerRegistry.setDefault(httpClient);
-
-            Grape.setEnableAutoDownload(true);
-
-            Map<String, Object> param = new HashMap<>();
-            param.put("classLoader", groovyClassLoader);
-            param.put("group", groupId);
-            param.put("module", artifactId);
-            param.put("version", version);
+            MavenDownloader mavenDownloader = downloader;
+            if (customized) {
+                mavenDownloader = mavenDownloader.customize(localRepository, connectTimeout, requestTimeout);
+            }
 
-            Grape.grab(param);
+            String gav = String.format("%s:%s:%s", groupId, artifactId, version);
+            resolve(mavenDownloader, gav, version.contains("SNAPSHOT"));
 
             this.runtimeProviderVersion = version;
             return true;
@@ -158,6 +176,27 @@ public class MavenVersionManager implements VersionManager, Closeable {
         }
     }
 
+    /**
+     * Resolves Maven artifact using passed coordinates and use downloaded artifact as one of the URLs in the
+     * helperClassLoader, so further Catalog access may load resources from it.
+     *
+     * @param mavenDownloader
+     * @param gav
+     * @param useSnapshots
+     */
+    private void resolve(MavenDownloader mavenDownloader, String gav, boolean useSnapshots)
+            throws MavenResolutionException, MalformedURLException {
+        Set<String> extraRepositories = new LinkedHashSet<>(repositories.values());
+
+        // non-transitive resolve, because we load static data from the catalog artifacts
+        List<MavenArtifact> artifacts = mavenDownloader.resolveArtifacts(Collections.singletonList(gav),
+                extraRepositories, false, useSnapshots);
+
+        for (MavenArtifact ma : artifacts) {
+            helperClassLoader.addURL(ma.getFile().toURI().toURL());
+        }
+    }
+
     @Override
     public InputStream getResourceAsStream(String name) {
         InputStream is = null;
@@ -175,7 +214,7 @@ public class MavenVersionManager implements VersionManager, Closeable {
             is = MavenVersionManager.class.getClassLoader().getResourceAsStream(name);
         }
         if (is == null) {
-            is = groovyClassLoader.getResourceAsStream(name);
+            is = helperClassLoader.getResourceAsStream(name);
         }
 
         return is;
@@ -188,7 +227,7 @@ public class MavenVersionManager implements VersionManager, Closeable {
 
         try {
             URL found = null;
-            Enumeration<URL> urls = groovyClassLoader.getResources(name);
+            Enumeration<URL> urls = helperClassLoader.getResources(name);
             while (urls.hasMoreElements()) {
                 URL url = urls.nextElement();
                 if (url.getPath().contains(version)) {
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenArtifact.java b/catalog/camel-catalog-maven/src/main/java/org/apache/camel/catalog/maven/OpenURLClassLoader.java
similarity index 66%
copy from dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenArtifact.java
copy to catalog/camel-catalog-maven/src/main/java/org/apache/camel/catalog/maven/OpenURLClassLoader.java
index d9ca9c07ecd..027aba4e971 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenArtifact.java
+++ b/catalog/camel-catalog-maven/src/main/java/org/apache/camel/catalog/maven/OpenURLClassLoader.java
@@ -14,30 +14,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.main.download;
+package org.apache.camel.catalog.maven;
 
-import java.io.File;
+import java.net.URL;
+import java.net.URLClassLoader;
 
-public class MavenArtifact {
+class OpenURLClassLoader extends URLClassLoader {
 
-    private final MavenGav gav;
-    private final File file;
-
-    public MavenArtifact(MavenGav gav, File file) {
-        this.gav = gav;
-        this.file = file;
-    }
-
-    public MavenGav getGav() {
-        return gav;
-    }
-
-    public File getFile() {
-        return file;
+    public OpenURLClassLoader() {
+        super(new URL[0]);
     }
 
     @Override
-    public String toString() {
-        return gav.toString();
+    public void addURL(URL url) {
+        super.addURL(url);
     }
+
 }
diff --git a/catalog/camel-catalog-maven/src/main/java/org/apache/camel/catalog/maven/TimeoutHttpClientHandler.java b/catalog/camel-catalog-maven/src/main/java/org/apache/camel/catalog/maven/TimeoutHttpClientHandler.java
deleted file mode 100644
index cd1b743ed88..00000000000
--- a/catalog/camel-catalog-maven/src/main/java/org/apache/camel/catalog/maven/TimeoutHttpClientHandler.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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.catalog.maven;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-
-import org.apache.ivy.util.url.BasicURLHandler;
-import org.apache.ivy.util.url.HttpClientHandler;
-
-/**
- * A {@link HttpClientHandler} which uses HttpClient for downloading via http/https and have support for connection
- * timeouts which otherwise is not supported by default in Apache Ivy.
- */
-public class TimeoutHttpClientHandler extends HttpClientHandler {
-
-    // use basic handler for non http/https as it can load from jar/file etc
-    private BasicURLHandler basic = new BasicURLHandler();
-
-    private int timeout = 10000;
-
-    public int getTimeout() {
-        return timeout;
-    }
-
-    /**
-     * Sets the timeout in millis (http.socket.timeout) when downloading via http/https protocols.
-     * <p/>
-     * The default value is 10000
-     */
-    public void setTimeout(int timeout) {
-        this.timeout = timeout;
-    }
-
-    @Override
-    public URLInfo getURLInfo(URL url) {
-        // ensure we always use a timeout
-        String protocol = url.getProtocol();
-        if ("http".equals(protocol) || "https".equals(protocol)) {
-            return super.getURLInfo(url, timeout);
-        } else {
-            // use basic for non http
-            return basic.getURLInfo(url, timeout);
-        }
-    }
-
-    @Override
-    public InputStream openStream(URL url) throws IOException {
-        String protocol = url.getProtocol();
-        if ("http".equals(protocol) || "https".equals(protocol)) {
-            return super.openStream(url);
-        } else {
-            // use basic for non http
-            return basic.openStream(url);
-        }
-    }
-}
diff --git a/catalog/camel-catalog-maven/src/test/java/org/apache/camel/catalog/maven/MavenArtifactProviderManualTest.java b/catalog/camel-catalog-maven/src/test/java/org/apache/camel/catalog/maven/MavenArtifactProviderManualTest.java
index d52bdac2ae6..c03a928dc78 100644
--- a/catalog/camel-catalog-maven/src/test/java/org/apache/camel/catalog/maven/MavenArtifactProviderManualTest.java
+++ b/catalog/camel-catalog-maven/src/test/java/org/apache/camel/catalog/maven/MavenArtifactProviderManualTest.java
@@ -16,6 +16,8 @@
  */
 package org.apache.camel.catalog.maven;
 
+import java.io.File;
+import java.net.MalformedURLException;
 import java.util.Set;
 
 import org.apache.camel.catalog.CamelCatalog;
@@ -30,13 +32,17 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 public class MavenArtifactProviderManualTest {
 
     @Test
-    public void testAddComponent() {
+    public void testAddComponent() throws MalformedURLException {
         CamelCatalog camelCatalog = new DefaultCamelCatalog();
         MavenArtifactProvider provider = new DefaultMavenArtifactProvider();
         provider.setCacheDirectory("target/cache");
 
         int before = camelCatalog.findComponentNames().size();
 
+        // use ~/.m2/repository as one of the remote repos - I needed it to test dummy-component SNAPSHOT
+        // fixed only locally (and also when Apache Snapshots repo was down)
+        provider.addMavenRepository("local",
+                new File(System.getProperty("user.home"), ".m2/repository").toURI().toURL().toString());
         Set<String> names = provider.addArtifactToCatalog(camelCatalog, "org.apache.camel", "dummy-component",
                 camelCatalog.getCatalogVersion());
         assertTrue(names.contains("dummy"));
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyList.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyList.java
index 3dc475b2cad..517c692a54a 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyList.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyList.java
@@ -30,7 +30,7 @@ import org.w3c.dom.NodeList;
 
 import org.apache.camel.dsl.jbang.core.common.RuntimeUtil;
 import org.apache.camel.dsl.jbang.core.common.XmlHelper;
-import org.apache.camel.main.download.MavenGav;
+import org.apache.camel.tooling.maven.MavenGav;
 import org.apache.camel.util.CamelCaseOrderedProperties;
 import org.apache.camel.util.FileUtil;
 import picocli.CommandLine;
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Export.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Export.java
index 246c3e59647..b9752cbe61e 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Export.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Export.java
@@ -21,7 +21,7 @@ import java.util.Comparator;
 import java.util.Properties;
 
 import org.apache.camel.dsl.jbang.core.common.RuntimeUtil;
-import org.apache.camel.main.download.MavenGav;
+import org.apache.camel.tooling.maven.MavenGav;
 import org.apache.camel.util.CamelCaseOrderedProperties;
 import picocli.CommandLine.Command;
 
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportBaseCommand.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportBaseCommand.java
index f9f724e0412..4457231728b 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportBaseCommand.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportBaseCommand.java
@@ -41,7 +41,7 @@ import java.util.stream.Collectors;
 import org.apache.camel.catalog.DefaultCamelCatalog;
 import org.apache.camel.dsl.jbang.core.common.RuntimeCompletionCandidates;
 import org.apache.camel.dsl.jbang.core.common.RuntimeUtil;
-import org.apache.camel.main.download.MavenGav;
+import org.apache.camel.tooling.maven.MavenGav;
 import org.apache.camel.util.CamelCaseOrderedProperties;
 import org.apache.camel.util.FileUtil;
 import org.apache.camel.util.IOHelper;
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportCamelMain.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportCamelMain.java
index d25e7945322..2197099df8e 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportCamelMain.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportCamelMain.java
@@ -27,7 +27,7 @@ import java.util.Set;
 import org.apache.camel.catalog.CamelCatalog;
 import org.apache.camel.catalog.DefaultCamelCatalog;
 import org.apache.camel.dsl.jbang.core.common.RuntimeUtil;
-import org.apache.camel.main.download.MavenGav;
+import org.apache.camel.tooling.maven.MavenGav;
 import org.apache.camel.util.CamelCaseOrderedProperties;
 import org.apache.camel.util.FileUtil;
 import org.apache.camel.util.IOHelper;
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportQuarkus.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportQuarkus.java
index 0bc1edf443c..d0222d8985e 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportQuarkus.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportQuarkus.java
@@ -31,7 +31,7 @@ import java.util.stream.Collectors;
 import org.apache.camel.catalog.CamelCatalog;
 import org.apache.camel.dsl.jbang.core.common.CatalogLoader;
 import org.apache.camel.dsl.jbang.core.common.RuntimeUtil;
-import org.apache.camel.main.download.MavenGav;
+import org.apache.camel.tooling.maven.MavenGav;
 import org.apache.camel.tooling.model.ArtifactModel;
 import org.apache.camel.util.CamelCaseOrderedProperties;
 import org.apache.camel.util.FileUtil;
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportSpringBoot.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportSpringBoot.java
index 0144fa41c2d..907f57d2f0c 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportSpringBoot.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportSpringBoot.java
@@ -33,7 +33,7 @@ import java.util.stream.Collectors;
 import org.apache.camel.catalog.CamelCatalog;
 import org.apache.camel.dsl.jbang.core.common.CatalogLoader;
 import org.apache.camel.dsl.jbang.core.common.RuntimeUtil;
-import org.apache.camel.main.download.MavenGav;
+import org.apache.camel.tooling.maven.MavenGav;
 import org.apache.camel.tooling.model.ArtifactModel;
 import org.apache.camel.util.CamelCaseOrderedProperties;
 import org.apache.camel.util.FileUtil;
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogBaseCommand.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogBaseCommand.java
index f44fadc0239..c9b1c0e5618 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogBaseCommand.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogBaseCommand.java
@@ -32,7 +32,7 @@ import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
 import org.apache.camel.dsl.jbang.core.common.CatalogLoader;
 import org.apache.camel.dsl.jbang.core.common.RuntimeCompletionCandidates;
 import org.apache.camel.dsl.jbang.core.common.VersionHelper;
-import org.apache.camel.main.download.MavenGav;
+import org.apache.camel.tooling.maven.MavenGav;
 import org.apache.camel.tooling.model.ArtifactModel;
 import org.apache.camel.util.json.Jsoner;
 import picocli.CommandLine;
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogDoc.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogDoc.java
index 8e4936a7353..ec4bc91c422 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogDoc.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/catalog/CatalogDoc.java
@@ -34,8 +34,8 @@ import org.apache.camel.dsl.jbang.core.commands.CamelCommand;
 import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
 import org.apache.camel.dsl.jbang.core.common.CatalogLoader;
 import org.apache.camel.dsl.jbang.core.common.RuntimeCompletionCandidates;
-import org.apache.camel.main.download.MavenGav;
 import org.apache.camel.main.util.SuggestSimilarHelper;
+import org.apache.camel.tooling.maven.MavenGav;
 import org.apache.camel.tooling.model.BaseOptionModel;
 import org.apache.camel.tooling.model.ComponentModel;
 import org.apache.camel.tooling.model.DataFormatModel;
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/Hawtio.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/Hawtio.java
index d3b1f625b7e..2bdace923ec 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/Hawtio.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/process/Hawtio.java
@@ -24,9 +24,9 @@ import java.util.concurrent.CountDownLatch;
 import org.apache.camel.dsl.jbang.core.commands.CamelCommand;
 import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
 import org.apache.camel.main.download.DependencyDownloaderClassLoader;
-import org.apache.camel.main.download.MavenArtifact;
 import org.apache.camel.main.download.MavenDependencyDownloader;
 import org.apache.camel.support.ObjectHelper;
+import org.apache.camel.tooling.maven.MavenArtifact;
 import picocli.CommandLine;
 import picocli.CommandLine.Command;
 
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/version/VersionList.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/version/VersionList.java
index e36eed467ca..63bfb22122b 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/version/VersionList.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/version/VersionList.java
@@ -55,7 +55,7 @@ public class VersionList extends CamelCommand {
                         description = "Minimum Camel version to avoid resolving too old releases", defaultValue = "3.14.0")
     String minimumVersion = "3.14.0";
 
-    @CommandLine.Option(names = { "--repo", "--repos" }, description = "Maven repository for downloading available versions")
+    @CommandLine.Option(names = { "--repo" }, description = "Maven repository for downloading available versions")
     String repo;
 
     @CommandLine.Option(names = { "--lts" }, description = "Only show LTS supported releases")
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/CatalogLoader.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/CatalogLoader.java
index 49030808388..43407795509 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/CatalogLoader.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/CatalogLoader.java
@@ -34,8 +34,8 @@ import org.apache.camel.catalog.VersionManager;
 import org.apache.camel.main.KameletMain;
 import org.apache.camel.main.download.DependencyDownloaderClassLoader;
 import org.apache.camel.main.download.DownloadException;
-import org.apache.camel.main.download.MavenArtifact;
 import org.apache.camel.main.download.MavenDependencyDownloader;
+import org.apache.camel.tooling.maven.MavenArtifact;
 
 public final class CatalogLoader {
 
diff --git a/dsl/camel-kamelet-main/pom.xml b/dsl/camel-kamelet-main/pom.xml
index ed92fd9c7c2..7beabe31774 100644
--- a/dsl/camel-kamelet-main/pom.xml
+++ b/dsl/camel-kamelet-main/pom.xml
@@ -115,52 +115,21 @@
             <groupId>org.apache.camel</groupId>
             <artifactId>camel-catalog-console</artifactId>
         </dependency>
-
-        <!-- maven / maven resolver -->
-        <dependency>
-            <groupId>org.apache.maven</groupId>
-            <artifactId>maven-resolver-provider</artifactId>
-            <version>${maven-version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.maven</groupId>
-            <artifactId>maven-settings-builder</artifactId>
-            <version>${maven-version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.maven.resolver</groupId>
-            <artifactId>maven-resolver-api</artifactId>
-            <version>${maven-resolver-version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.maven.resolver</groupId>
-            <artifactId>maven-resolver-spi</artifactId>
-            <version>${maven-resolver-version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.maven.resolver</groupId>
-            <artifactId>maven-resolver-impl</artifactId>
-            <version>${maven-resolver-version}</version>
-        </dependency>
         <dependency>
-            <groupId>org.apache.maven.resolver</groupId>
-            <artifactId>maven-resolver-connector-basic</artifactId>
-            <version>${maven-resolver-version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.maven.resolver</groupId>
-            <artifactId>maven-resolver-transport-file</artifactId>
-            <version>${maven-resolver-version}</version>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-resourceresolver-github</artifactId>
+            <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>org.apache.maven.resolver</groupId>
-            <artifactId>maven-resolver-transport-http</artifactId>
-            <version>${maven-resolver-version}</version>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-groovy-dsl</artifactId>
+            <scope>test</scope>
         </dependency>
+
+        <!-- Entire Maven downloading/resolution support is made using camel-tooling-maven -->
         <dependency>
-            <groupId>org.apache.maven.resolver</groupId>
-            <artifactId>maven-resolver-util</artifactId>
-            <version>${maven-resolver-version}</version>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-tooling-maven</artifactId>
         </dependency>
         <!-- optional spring annotation support -->
         <dependency>
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/AutoConfigureDownloadListener.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/AutoConfigureDownloadListener.java
index 61df86092b3..a03bb9ac695 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/AutoConfigureDownloadListener.java
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/AutoConfigureDownloadListener.java
@@ -26,6 +26,7 @@ import org.apache.camel.Expression;
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.spi.Language;
 import org.apache.camel.support.DefaultExchange;
+import org.apache.camel.tooling.maven.MavenGav;
 import org.apache.camel.util.IOHelper;
 import org.apache.camel.util.ObjectHelper;
 import org.slf4j.Logger;
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/CommandLineDependencyDownloader.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/CommandLineDependencyDownloader.java
index 451be0233b2..5140cdc5e8c 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/CommandLineDependencyDownloader.java
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/CommandLineDependencyDownloader.java
@@ -21,6 +21,7 @@ import java.util.List;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.support.service.ServiceSupport;
+import org.apache.camel.tooling.maven.MavenGav;
 
 public class CommandLineDependencyDownloader extends ServiceSupport {
 
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloader.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloader.java
index 2ab1eb1921e..131d6ae2de5 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloader.java
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloader.java
@@ -20,6 +20,7 @@ import java.util.List;
 
 import org.apache.camel.CamelContextAware;
 import org.apache.camel.StaticService;
+import org.apache.camel.tooling.maven.MavenArtifact;
 
 /**
  * To download dependencies at runtime.
@@ -128,7 +129,7 @@ public interface DependencyDownloader extends CamelContextAware, StaticService {
      * @param  groupId        maven group id
      * @param  artifactId     maven artifact id
      * @param  minimumVersion optional minimum version to avoid resolving too old releases
-     * @param  repo           to use specific maven repository instead of maven central
+     * @param  repo           to use specific maven repository instead of maven central (used if repo is {@code null})
      * @return                list of versions of the given artifact (0=camel-core version, 1=runtime version, such as
      *                        spring-boot or quarkus)
      */
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloaderClassResolver.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloaderClassResolver.java
index 0e662c0e181..fa700f58e60 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloaderClassResolver.java
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloaderClassResolver.java
@@ -20,6 +20,7 @@ import java.io.InputStream;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.impl.engine.DefaultClassResolver;
+import org.apache.camel.tooling.maven.MavenGav;
 import org.apache.camel.util.ObjectHelper;
 
 public final class DependencyDownloaderClassResolver extends DefaultClassResolver {
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloaderKamelet.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloaderKamelet.java
index d796c012cc6..4078e1fc3fa 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloaderKamelet.java
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloaderKamelet.java
@@ -35,6 +35,7 @@ import org.apache.camel.spi.Resource;
 import org.apache.camel.spi.RouteTemplateLoaderListener;
 import org.apache.camel.support.service.ServiceHelper;
 import org.apache.camel.support.service.ServiceSupport;
+import org.apache.camel.tooling.maven.MavenGav;
 import org.apache.camel.util.StringHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloaderPropertyBindingListener.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloaderPropertyBindingListener.java
index 86949910f17..66946796818 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloaderPropertyBindingListener.java
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloaderPropertyBindingListener.java
@@ -18,6 +18,7 @@ package org.apache.camel.main.download;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.support.PropertyBindingListener;
+import org.apache.camel.tooling.maven.MavenGav;
 
 public class DependencyDownloaderPropertyBindingListener implements PropertyBindingListener {
 
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloaderStrategy.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloaderStrategy.java
index 133930ec831..118ef4ee2f8 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloaderStrategy.java
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloaderStrategy.java
@@ -18,6 +18,7 @@ package org.apache.camel.main.download;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.spi.DependencyStrategy;
+import org.apache.camel.tooling.maven.MavenGav;
 
 public class DependencyDownloaderStrategy implements DependencyStrategy {
 
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/KnownDependenciesResolver.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/KnownDependenciesResolver.java
index 4988c0132e7..3421a9d8ee1 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/KnownDependenciesResolver.java
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/KnownDependenciesResolver.java
@@ -22,6 +22,7 @@ import java.util.Map;
 import java.util.Properties;
 
 import org.apache.camel.CamelContext;
+import org.apache.camel.tooling.maven.MavenGav;
 
 public final class KnownDependenciesResolver {
 
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenDependencyDownloader.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenDependencyDownloader.java
index 868f9f13098..2c6bf859c92 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenDependencyDownloader.java
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenDependencyDownloader.java
@@ -22,240 +22,63 @@ import java.lang.management.RuntimeMXBean;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLClassLoader;
-import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.HashSet;
-import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
-import java.util.Map;
-import java.util.Properties;
 import java.util.Set;
-import java.util.UUID;
-import java.util.stream.Collectors;
 
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 
+import org.apache.camel.main.util.VersionHelper;
+import org.apache.camel.main.util.XmlHelper;
+import org.apache.camel.tooling.maven.MavenGav;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.NodeList;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.CamelContextAware;
-import org.apache.camel.main.injection.DIRegistry;
-import org.apache.camel.main.util.VersionHelper;
-import org.apache.camel.main.util.XmlHelper;
 import org.apache.camel.support.service.ServiceHelper;
 import org.apache.camel.support.service.ServiceSupport;
+import org.apache.camel.tooling.maven.MavenArtifact;
+import org.apache.camel.tooling.maven.MavenDownloader;
+import org.apache.camel.tooling.maven.MavenDownloaderImpl;
+import org.apache.camel.tooling.maven.MavenResolutionException;
 import org.apache.camel.util.FileUtil;
-import org.apache.maven.model.building.DefaultModelBuilderFactory;
-import org.apache.maven.model.building.ModelBuilder;
-import org.apache.maven.repository.internal.DefaultArtifactDescriptorReader;
-import org.apache.maven.repository.internal.DefaultVersionRangeResolver;
-import org.apache.maven.repository.internal.DefaultVersionResolver;
-import org.apache.maven.repository.internal.SnapshotMetadataGeneratorFactory;
-import org.apache.maven.repository.internal.VersionsMetadataGeneratorFactory;
-import org.apache.maven.settings.Mirror;
-import org.apache.maven.settings.Profile;
-import org.apache.maven.settings.Proxy;
-import org.apache.maven.settings.Repository;
-import org.apache.maven.settings.Server;
-import org.apache.maven.settings.Settings;
-import org.apache.maven.settings.building.DefaultSettingsBuilder;
-import org.apache.maven.settings.building.DefaultSettingsBuildingRequest;
-import org.apache.maven.settings.building.SettingsBuilder;
-import org.apache.maven.settings.building.SettingsBuildingException;
-import org.apache.maven.settings.building.SettingsBuildingRequest;
-import org.apache.maven.settings.building.SettingsBuildingResult;
-import org.apache.maven.settings.crypto.DefaultSettingsDecrypter;
-import org.apache.maven.settings.crypto.DefaultSettingsDecryptionRequest;
-import org.apache.maven.settings.crypto.SettingsDecrypter;
-import org.apache.maven.settings.crypto.SettingsDecryptionRequest;
-import org.apache.maven.settings.crypto.SettingsDecryptionResult;
-import org.apache.maven.settings.io.DefaultSettingsReader;
-import org.apache.maven.settings.io.DefaultSettingsWriter;
-import org.apache.maven.settings.io.SettingsReader;
-import org.apache.maven.settings.io.SettingsWriter;
-import org.apache.maven.settings.validation.DefaultSettingsValidator;
-import org.apache.maven.settings.validation.SettingsValidator;
-import org.codehaus.plexus.util.xml.Xpp3Dom;
-import org.eclipse.aether.ConfigurationProperties;
-import org.eclipse.aether.DefaultRepositorySystemSession;
-import org.eclipse.aether.RepositorySystem;
-import org.eclipse.aether.RepositorySystemSession;
-import org.eclipse.aether.artifact.Artifact;
-import org.eclipse.aether.artifact.ArtifactTypeRegistry;
-import org.eclipse.aether.artifact.DefaultArtifactType;
-import org.eclipse.aether.collection.CollectRequest;
-import org.eclipse.aether.collection.DependencyGraphTransformer;
-import org.eclipse.aether.collection.DependencySelector;
-import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory;
-import org.eclipse.aether.graph.Dependency;
-import org.eclipse.aether.graph.DependencyFilter;
-import org.eclipse.aether.graph.DependencyNode;
-import org.eclipse.aether.impl.ArtifactDescriptorReader;
-import org.eclipse.aether.impl.ArtifactResolver;
-import org.eclipse.aether.impl.DependencyCollector;
-import org.eclipse.aether.impl.Deployer;
-import org.eclipse.aether.impl.Installer;
-import org.eclipse.aether.impl.LocalRepositoryProvider;
-import org.eclipse.aether.impl.MetadataGeneratorFactory;
-import org.eclipse.aether.impl.MetadataResolver;
-import org.eclipse.aether.impl.OfflineController;
-import org.eclipse.aether.impl.RemoteRepositoryFilterManager;
-import org.eclipse.aether.impl.RemoteRepositoryManager;
-import org.eclipse.aether.impl.RepositoryConnectorProvider;
-import org.eclipse.aether.impl.RepositoryEventDispatcher;
-import org.eclipse.aether.impl.RepositorySystemLifecycle;
-import org.eclipse.aether.impl.UpdateCheckManager;
-import org.eclipse.aether.impl.UpdatePolicyAnalyzer;
-import org.eclipse.aether.impl.VersionRangeResolver;
-import org.eclipse.aether.impl.VersionResolver;
-import org.eclipse.aether.internal.impl.DefaultArtifactResolver;
-import org.eclipse.aether.internal.impl.DefaultChecksumPolicyProvider;
-import org.eclipse.aether.internal.impl.DefaultDeployer;
-import org.eclipse.aether.internal.impl.DefaultFileProcessor;
-import org.eclipse.aether.internal.impl.DefaultInstaller;
-import org.eclipse.aether.internal.impl.DefaultLocalPathComposer;
-import org.eclipse.aether.internal.impl.DefaultLocalPathPrefixComposerFactory;
-import org.eclipse.aether.internal.impl.DefaultLocalRepositoryProvider;
-import org.eclipse.aether.internal.impl.DefaultMetadataResolver;
-import org.eclipse.aether.internal.impl.DefaultOfflineController;
-import org.eclipse.aether.internal.impl.DefaultRemoteRepositoryManager;
-import org.eclipse.aether.internal.impl.DefaultRepositoryConnectorProvider;
-import org.eclipse.aether.internal.impl.DefaultRepositoryEventDispatcher;
-import org.eclipse.aether.internal.impl.DefaultRepositoryLayoutProvider;
-import org.eclipse.aether.internal.impl.DefaultRepositorySystem;
-import org.eclipse.aether.internal.impl.DefaultRepositorySystemLifecycle;
-import org.eclipse.aether.internal.impl.DefaultTrackingFileManager;
-import org.eclipse.aether.internal.impl.DefaultTransporterProvider;
-import org.eclipse.aether.internal.impl.DefaultUpdateCheckManager;
-import org.eclipse.aether.internal.impl.DefaultUpdatePolicyAnalyzer;
-import org.eclipse.aether.internal.impl.EnhancedLocalRepositoryManagerFactory;
-import org.eclipse.aether.internal.impl.LocalPathComposer;
-import org.eclipse.aether.internal.impl.LocalPathPrefixComposerFactory;
-import org.eclipse.aether.internal.impl.Maven2RepositoryLayoutFactory;
-import org.eclipse.aether.internal.impl.TrackingFileManager;
-import org.eclipse.aether.internal.impl.checksum.DefaultChecksumAlgorithmFactorySelector;
-import org.eclipse.aether.internal.impl.checksum.Md5ChecksumAlgorithmFactory;
-import org.eclipse.aether.internal.impl.checksum.Sha1ChecksumAlgorithmFactory;
-import org.eclipse.aether.internal.impl.collect.DefaultDependencyCollector;
-import org.eclipse.aether.internal.impl.collect.DependencyCollectorDelegate;
-import org.eclipse.aether.internal.impl.collect.bf.BfDependencyCollector;
-import org.eclipse.aether.internal.impl.collect.df.DfDependencyCollector;
-import org.eclipse.aether.internal.impl.filter.DefaultRemoteRepositoryFilterManager;
-import org.eclipse.aether.internal.impl.slf4j.Slf4jLoggerFactory;
-import org.eclipse.aether.internal.impl.synccontext.DefaultSyncContextFactory;
-import org.eclipse.aether.internal.impl.synccontext.named.NameMapper;
-import org.eclipse.aether.internal.impl.synccontext.named.NameMappers;
-import org.eclipse.aether.internal.impl.synccontext.named.NamedLockFactoryAdapterFactory;
-import org.eclipse.aether.internal.impl.synccontext.named.NamedLockFactoryAdapterFactoryImpl;
-import org.eclipse.aether.metadata.DefaultMetadata;
-import org.eclipse.aether.metadata.Metadata;
-import org.eclipse.aether.named.NamedLockFactory;
-import org.eclipse.aether.named.providers.FileLockNamedLockFactory;
-import org.eclipse.aether.named.providers.LocalReadWriteLockNamedLockFactory;
-import org.eclipse.aether.named.providers.LocalSemaphoreNamedLockFactory;
-import org.eclipse.aether.named.providers.NoopNamedLockFactory;
-import org.eclipse.aether.repository.Authentication;
-import org.eclipse.aether.repository.AuthenticationSelector;
-import org.eclipse.aether.repository.LocalRepository;
-import org.eclipse.aether.repository.NoLocalRepositoryManagerException;
-import org.eclipse.aether.repository.ProxySelector;
-import org.eclipse.aether.repository.RemoteRepository;
-import org.eclipse.aether.repository.RepositoryPolicy;
-import org.eclipse.aether.resolution.ArtifactRequest;
-import org.eclipse.aether.resolution.DependencyRequest;
-import org.eclipse.aether.resolution.DependencyResolutionException;
-import org.eclipse.aether.resolution.DependencyResult;
-import org.eclipse.aether.resolution.MetadataRequest;
-import org.eclipse.aether.resolution.MetadataResult;
-import org.eclipse.aether.spi.connector.RepositoryConnectorFactory;
-import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory;
-import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySelector;
-import org.eclipse.aether.spi.connector.checksum.ChecksumPolicyProvider;
-import org.eclipse.aether.spi.connector.layout.RepositoryLayoutFactory;
-import org.eclipse.aether.spi.connector.layout.RepositoryLayoutProvider;
-import org.eclipse.aether.spi.connector.transport.TransporterFactory;
-import org.eclipse.aether.spi.connector.transport.TransporterProvider;
-import org.eclipse.aether.spi.io.FileProcessor;
-import org.eclipse.aether.spi.localrepo.LocalRepositoryManagerFactory;
-import org.eclipse.aether.spi.synccontext.SyncContextFactory;
-import org.eclipse.aether.transport.file.FileTransporterFactory;
-import org.eclipse.aether.transport.http.ChecksumExtractor;
-import org.eclipse.aether.transport.http.HttpTransporterFactory;
-import org.eclipse.aether.transport.http.Nexus2ChecksumExtractor;
-import org.eclipse.aether.transport.http.XChecksumChecksumExtractor;
-import org.eclipse.aether.util.artifact.DefaultArtifactTypeRegistry;
-import org.eclipse.aether.util.graph.manager.ClassicDependencyManager;
-import org.eclipse.aether.util.graph.selector.AndDependencySelector;
-import org.eclipse.aether.util.graph.selector.ExclusionDependencySelector;
-import org.eclipse.aether.util.graph.selector.OptionalDependencySelector;
-import org.eclipse.aether.util.graph.selector.ScopeDependencySelector;
-import org.eclipse.aether.util.graph.transformer.ChainedDependencyGraphTransformer;
-import org.eclipse.aether.util.graph.transformer.ConflictResolver;
-import org.eclipse.aether.util.graph.transformer.JavaDependencyContextRefiner;
-import org.eclipse.aether.util.graph.transformer.JavaScopeDeriver;
-import org.eclipse.aether.util.graph.transformer.JavaScopeSelector;
-import org.eclipse.aether.util.graph.transformer.NearestVersionSelector;
-import org.eclipse.aether.util.graph.transformer.SimpleOptionalitySelector;
-import org.eclipse.aether.util.graph.traverser.FatArtifactTraverser;
-import org.eclipse.aether.util.repository.AuthenticationBuilder;
-import org.eclipse.aether.util.repository.ConservativeAuthenticationSelector;
-import org.eclipse.aether.util.repository.DefaultAuthenticationSelector;
-import org.eclipse.aether.util.repository.DefaultMirrorSelector;
-import org.eclipse.aether.util.repository.DefaultProxySelector;
-import org.eclipse.aether.util.repository.JreProxySelector;
-import org.eclipse.aether.util.repository.SimpleArtifactDescriptorPolicy;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.sonatype.plexus.components.cipher.DefaultPlexusCipher;
-import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher;
-import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher;
 
 public class MavenDependencyDownloader extends ServiceSupport implements DependencyDownloader {
 
     public static final String MAVEN_CENTRAL_REPO = "https://repo1.maven.org/maven2";
     public static final String APACHE_SNAPSHOT_REPO = "https://repository.apache.org/snapshots";
 
-    private static final Logger LOG = LoggerFactory.getLogger(MavenDependencyDownloader.class);
-    private static final String CP = System.getProperty("java.class.path");
-
     private static final String MINIMUM_QUARKUS_VERSION = "2.0.0";
 
-    private static final RepositoryPolicy POLICY_DEFAULT = new RepositoryPolicy(
-            true, RepositoryPolicy.UPDATE_POLICY_NEVER, RepositoryPolicy.CHECKSUM_POLICY_WARN);
-    private static final RepositoryPolicy POLICY_FRESH = new RepositoryPolicy(
-            true, RepositoryPolicy.UPDATE_POLICY_ALWAYS, RepositoryPolicy.CHECKSUM_POLICY_WARN);
-    private static final RepositoryPolicy POLICY_DISABLED = new RepositoryPolicy(
-            false, RepositoryPolicy.UPDATE_POLICY_NEVER, RepositoryPolicy.CHECKSUM_POLICY_IGNORE);
+    private static final Logger LOG = LoggerFactory.getLogger(MavenDependencyDownloader.class);
+    private static final String CP = System.getProperty("java.class.path");
 
-    int customCount = 1;
     private String[] bootClasspath;
     private DownloadThreadPool threadPool;
-    private DIRegistry registry;
     private ClassLoader classLoader;
     private CamelContext camelContext;
     private final Set<DownloadListener> downloadListeners = new LinkedHashSet<>();
     private final Set<ArtifactDownloadListener> artifactDownloadListeners = new LinkedHashSet<>();
     private KnownReposResolver knownReposResolver;
 
+    // all maven-resolver work is delegated to camel-tooling-maven
+    private MavenDownloader mavenDownloader;
+
     // repository URLs set from "camel.jbang.repos" property or --repos option.
     private String repos;
     private boolean fresh;
 
+    // settings.xml and settings-security.xml locations to be passed to MavenDownloader from camel-tooling-maven
     private String mavenSettings;
     private String mavenSettingsSecurity;
-    private RepositorySystem repositorySystem;
-    private RepositorySystemSession repositorySystemSession;
-    // actual repositories to be used with maven-resolver
-    private final List<RemoteRepository> remoteRepositories = new ArrayList<>();
-    private RemoteRepository apacheSnapshots;
-    private boolean apacheSnapshotsIncluded;
 
     @Override
     public CamelContext getCamelContext() {
@@ -391,20 +214,19 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
             LOG.debug("Downloading: {}", gav);
             List<String> deps = List.of(gav);
 
-            List<RemoteRepository> repositories = new ArrayList<>(remoteRepositories);
             // include Apache snapshot to make it easy to use upcoming releases
-            if (!apacheSnapshotsIncluded && "org.apache.camel".equals(groupId) && version.contains("SNAPSHOT")) {
-                repositories.add(apacheSnapshots);
-            }
-            List<RemoteRepository> extaRepositories = new ArrayList<>();
-            // include extra repositories (if any)
-            extaRepositories.addAll(resolveExtraRepositories(extraRepos));
+            boolean useApacheSnaphots = "org.apache.camel".equals(groupId) && version.contains("SNAPSHOT");
+
+            // include extra repositories (if any) - these will be used in addition
+            // to the ones detected from ~/.m2/settings.xml and configured in
+            // org.apache.camel.main.download.MavenDependencyDownloader#repos
+            Set<String> extraRepositories = new LinkedHashSet<>(resolveExtraRepositories(extraRepos));
             // and from known extra repositories (if any)
             String known = knownReposResolver.getRepo(artifactId);
-            extaRepositories.addAll(resolveExtraRepositories(known));
-            repositories.addAll(extaRepositories);
+            extraRepositories.addAll(resolveExtraRepositories(known));
 
-            List<MavenArtifact> artifacts = resolveDependenciesViaAether(deps, repositories, transitively);
+            List<MavenArtifact> artifacts = resolveDependenciesViaAether(deps, extraRepositories,
+                    transitively, useApacheSnaphots);
             List<File> files = new ArrayList<>();
             LOG.debug("Resolved {} -> [{}]", gav, artifacts);
 
@@ -433,10 +255,10 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
                     listener.onDownloadedDependency(groupId, artifactId, version);
                 }
             }
-            if (!extaRepositories.isEmpty()) {
-                for (RemoteRepository repo : extaRepositories) {
+            if (!extraRepositories.isEmpty()) {
+                for (String repo : extraRepositories) {
                     for (DownloadListener listener : downloadListeners) {
-                        listener.onExtraRepository(repo.getUrl());
+                        listener.onExtraRepository(repo);
                     }
                 }
             }
@@ -450,13 +272,10 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
         LOG.debug("DownloadingArtifact: {}", gav);
         List<String> deps = List.of(gav);
 
-        List<RemoteRepository> repositories = new ArrayList<>(remoteRepositories);
         // include Apache snapshot to make it easy to use upcoming releases
-        if (!apacheSnapshotsIncluded && "org.apache.camel".equals(groupId) && version.contains("SNAPSHOT")) {
-            repositories.add(apacheSnapshots);
-        }
+        boolean useApacheSnaphots = "org.apache.camel".equals(groupId) && version.contains("SNAPSHOT");
 
-        List<MavenArtifact> artifacts = resolveDependenciesViaAether(deps, repositories, false);
+        List<MavenArtifact> artifacts = resolveDependenciesViaAether(deps, null, false, useApacheSnaphots);
         LOG.debug("Resolved {} -> [{}]", gav, artifacts);
 
         if (artifacts.size() == 1) {
@@ -467,20 +286,43 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
     }
 
     @Override
-    public List<String[]> resolveAvailableVersions(String groupId, String artifactId, String minimumVersion, String repo) {
+    public List<String[]> resolveAvailableVersions(String groupId, String artifactId,
+            String minimumVersion, String repo) {
         String gav = groupId + ":" + artifactId;
         LOG.debug("DownloadAvailableVersions: {}", gav);
 
-        // repo 0 is maven central
-        RemoteRepository repository = remoteRepositories.get(0);
-        if (repo != null) {
-            List<RemoteRepository> extra = resolveExtraRepositories(repo);
-            if (!extra.isEmpty()) {
-                repository = extra.get(0);
+        List<String[]> answer = new ArrayList<>();
+
+        try {
+            List<MavenGav> gavs = mavenDownloader.resolveAvailableVersions(groupId, artifactId, repo);
+
+            Set<String> extraRepos = repo == null ? null : Collections.singleton(repo);
+
+            for (MavenGav mavenGav : gavs) {
+                String v = mavenGav.getVersion();
+                if ("camel-spring-boot".equals(artifactId)) {
+                    String sbv = null;
+                    if (VersionHelper.isGE(v, minimumVersion)) {
+                        sbv = resolveSpringBootVersionByCamelVersion(v, extraRepos);
+                    }
+                    answer.add(new String[] { v, sbv });
+                } else if ("camel-quarkus-catalog".equals(artifactId)) {
+                    if (VersionHelper.isGE(v, MINIMUM_QUARKUS_VERSION)) {
+                        String cv = resolveCamelVersionByQuarkusVersion(v, extraRepos);
+                        if (cv != null && VersionHelper.isGE(cv, minimumVersion)) {
+                            answer.add(new String[] { cv, v });
+                        }
+                    }
+                } else {
+                    answer.add(new String[] { v, null });
+                }
             }
+        } catch (Exception e) {
+            LOG.error(e.getMessage(), e);
+            throw new DownloadException(e.getMessage(), e);
         }
-        List<String[]> versions = resolveAvailableVersions(groupId, artifactId, minimumVersion, repository);
-        return versions;
+
+        return answer;
     }
 
     public boolean alreadyOnClasspath(String groupId, String artifactId, String version) {
@@ -553,30 +395,17 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
         }
     }
 
-    private List<RemoteRepository> resolveExtraRepositories(String extraRepos) {
-        List<RemoteRepository> repositories = new ArrayList<>();
-        if (extraRepos != null) {
+    private Set<String> resolveExtraRepositories(String repositoryList) {
+        Set<String> repositories = new LinkedHashSet<>();
+        if (repositoryList != null) {
             Set<String> repositoryURLs = new HashSet<>();
-            for (String repo : extraRepos.split(",")) {
+            for (String repo : repositoryList.split("\\s*,\\s*")) {
                 try {
                     URL url = new URL(repo);
                     if (url.getHost().equals("repo1.maven.org")) {
                         continue;
                     }
-                    String id = "custom" + customCount++;
-                    RepositoryPolicy releasePolicy = fresh ? POLICY_FRESH : POLICY_DEFAULT;
-                    if (repositoryURLs.add(url.toExternalForm())) {
-                        if (url.getHost().equals("repository.apache.org") && url.getPath().contains("/snapshots")) {
-                            apacheSnapshotsIncluded = true;
-                            repositories.add(apacheSnapshots);
-                        } else {
-                            // both snapshots and releases allowed for custom repos
-                            repositories.add(new RemoteRepository.Builder(id, "default", repo)
-                                    .setReleasePolicy(releasePolicy)
-                                    .setSnapshotPolicy(fresh ? POLICY_FRESH : POLICY_DEFAULT)
-                                    .build());
-                        }
-                    }
+                    repositories.add(url.toExternalForm());
                 } catch (MalformedURLException e) {
                     LOG.warn("Can't use {} URL: {}. Skipping.", repo, e.getMessage(), e);
                 }
@@ -594,42 +423,14 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
         threadPool.setCamelContext(camelContext);
         ServiceHelper.buildService(threadPool);
 
-        // Aether/maven-resolver configuration used without Shrinkwrap
-        // and without deprecated:
-        //  - org.eclipse.aether.impl.DefaultServiceLocator
-        //  - org.apache.maven.repository.internal.MavenRepositorySystemUtils.newServiceLocator()
-
-        registry = new DIRegistry();
-        final Properties systemProperties = new Properties();
-        // MNG-5670 guard against ConcurrentModificationException
-        // MNG-6053 guard against key without value
-        synchronized (System.getProperties()) {
-            systemProperties.putAll(System.getProperties());
-        }
-
-        // locations of settings.xml and settings-security.xml
-        validateMavenSettingsLocations();
-
-        repositorySystem = configureRepositorySystem(registry, systemProperties,
-                mavenSettingsSecurity);
+        MavenDownloaderImpl mavenDownloaderImpl = new MavenDownloaderImpl();
+        mavenDownloaderImpl.setMavenSettingsLocation(mavenSettings);
+        mavenDownloaderImpl.setMavenSettingsSecurityLocation(mavenSettingsSecurity);
+        mavenDownloaderImpl.setRepos(repos);
+        mavenDownloaderImpl.setFresh(fresh);
+        ServiceHelper.buildService(mavenDownloaderImpl);
 
-        // read the settings
-        Settings settings = mavenConfiguration(registry, repositorySystem, systemProperties, mavenSettings);
-
-        // prepare the Maven session (local repository was configured within the settings)
-        // this object is thread safe - it uses configurable download pool, but we're doing our own pooling too
-        repositorySystemSession = configureRepositorySystemSession(registry, systemProperties,
-                settings, new File(settings.getLocalRepository()));
-
-        // process repositories - both from settings.xml and from --repos option. All are subject to
-        // mirrorring and proxying
-        List<RemoteRepository> originalRepositories = configureRemoteRepositories(settings, repos, fresh);
-        remoteRepositories.addAll(repositorySystem.newResolutionRepositories(repositorySystemSession,
-                originalRepositories));
-
-        // finally process apache snapshots
-        apacheSnapshots = repositorySystem.newResolutionRepositories(repositorySystemSession,
-                Collections.singletonList(apacheSnapshots)).get(0);
+        mavenDownloader = mavenDownloaderImpl;
     }
 
     @Override
@@ -639,724 +440,24 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
             bootClasspath = mb.getClassPath().split("[:|;]");
         }
         ServiceHelper.initService(threadPool);
+        ServiceHelper.initService(mavenDownloader);
     }
 
     @Override
-    protected void doStop() throws Exception {
+    protected void doStop() {
+        ServiceHelper.stopAndShutdownService(mavenDownloader);
         ServiceHelper.stopAndShutdownService(threadPool);
-        if (registry != null) {
-            registry.close();
-        }
-    }
-
-    private void validateMavenSettingsLocations() {
-        if (mavenSettingsSecurity != null && !new File(mavenSettingsSecurity).isFile()) {
-            LOG.warn("Can't access {}. Skipping Maven settings-security.xml configuration.", mavenSettingsSecurity);
-            mavenSettingsSecurity = null;
-        }
-
-        boolean skip = false;
-        if ("false".equalsIgnoreCase(mavenSettings)) {
-            // no implicit settings
-            mavenSettings = null;
-            // disable the settings-security.xml too
-            mavenSettingsSecurity = null;
-            skip = true;
-        } else if (mavenSettings == null) {
-            // implicit settings
-            String m2settings = System.getProperty("user.home") + File.separator + ".m2"
-                                + File.separator + "settings.xml";
-            if (new File(m2settings).isFile()) {
-                mavenSettings = m2settings;
-            }
-        } else {
-            if (!new File(mavenSettings).isFile()) {
-                LOG.warn("Can't access {}. Skipping Maven settings.xml configuration.", mavenSettings);
-            }
-            mavenSettings = null;
-        }
-
-        if (!skip) {
-            if (mavenSettingsSecurity == null) {
-                // implicit security settings
-                String m2settingsSecurity = System.getProperty("user.home") + File.separator + ".m2"
-                        + File.separator + "settings-security.xml";
-                if (new File(m2settingsSecurity).isFile()) {
-                    mavenSettingsSecurity = m2settingsSecurity;
-                }
-            } else {
-                if (!new File(mavenSettingsSecurity).isFile()) {
-                    LOG.warn("Can't access {}. Skipping Maven settings-settings.xml configuration.",
-                            mavenSettingsSecurity);
-                }
-                mavenSettingsSecurity = null;
-            }
-        }
-    }
-
-    /**
-     * Configure entire {@link RepositorySystem} service
-     */
-    public RepositorySystem configureRepositorySystem(
-            DIRegistry registry,
-            Properties systemProperties, String settingsSecurityLocation) {
-        basicRepositorySystemConfiguration(registry, systemProperties);
-        transportConfiguration(registry, systemProperties);
-        settingsConfiguration(registry, settingsSecurityLocation);
-
-        return registry.lookupByClass(RepositorySystem.class);
-    }
-
-    /**
-     * Configure the basic, necessary requirements of {@link RepositorySystem} in {@link DIRegistry}
-     */
-    private static void basicRepositorySystemConfiguration(DIRegistry registry, Properties systemProperties) {
-        // this is the first one registered in DefaultServiceLocator - what follows up is BFS dependencies
-        registry.bind(RepositorySystem.class, DefaultRepositorySystem.class);
-
-        // level 1 requirements of org.eclipse.aether.internal.impl.DefaultRepositorySystem
-        registry.bind(VersionResolver.class, DefaultVersionResolver.class);
-        registry.bind(VersionRangeResolver.class, DefaultVersionRangeResolver.class);
-        registry.bind(ArtifactResolver.class, DefaultArtifactResolver.class);
-        registry.bind(MetadataResolver.class, DefaultMetadataResolver.class);
-        registry.bind(ArtifactDescriptorReader.class, DefaultArtifactDescriptorReader.class);
-        registry.bind(DependencyCollector.class, DefaultDependencyCollector.class);
-        registry.bind(Installer.class, DefaultInstaller.class);
-        registry.bind(Deployer.class, DefaultDeployer.class);
-        registry.bind(LocalRepositoryProvider.class, DefaultLocalRepositoryProvider.class);
-        registry.bind(SyncContextFactory.class, DefaultSyncContextFactory.class);
-        registry.bind(RemoteRepositoryManager.class, DefaultRemoteRepositoryManager.class);
-
-        // level 2 requirements of org.eclipse.aether.internal.impl.DefaultRepositorySystem
-
-        // remaining requirements of org.apache.maven.repository.internal.DefaultVersionResolver
-        registry.bind(RepositoryEventDispatcher.class, DefaultRepositoryEventDispatcher.class);
-
-        // remaining requirements of org.eclipse.aether.internal.impl.DefaultArtifactResolver
-        registry.bind(FileProcessor.class, DefaultFileProcessor.class);
-        registry.bind(UpdateCheckManager.class, DefaultUpdateCheckManager.class);
-        registry.bind(RepositoryConnectorProvider.class, DefaultRepositoryConnectorProvider.class);
-        registry.bind(OfflineController.class, DefaultOfflineController.class);
-
-        // remaining requirements of org.apache.maven.repository.internal.DefaultArtifactDescriptorReader
-
-        // model builder has a lot of @Inject fields, so let's switch to what ServiceLocator version
-        // of DefaultArtifactDescriptorReader is doing in DefaultArtifactDescriptorReader.initService()
-        // also, org.apache.maven.model.building.DefaultModelBuilder uses @Inject on fields, which are not
-        // handled yet
-        //        registry.bind(ModelBuilder.class, DefaultModelBuilder.class);
-        registry.bind("modelBuilder", ModelBuilder.class, new DefaultModelBuilderFactory().newInstance());
-
-        // remaining requirements of org.eclipse.aether.internal.impl.collect.DefaultDependencyCollector
-        registry.bind(DependencyCollectorDelegate.class, DfDependencyCollector.class); // aether.collector.impl=df
-        registry.bind(DependencyCollectorDelegate.class, BfDependencyCollector.class); // aether.collector.impl=bf
-
-        // remaining requirements of org.eclipse.aether.internal.impl.DefaultInstaller
-        registry.bind(MetadataGeneratorFactory.class, SnapshotMetadataGeneratorFactory.class);
-        registry.bind(MetadataGeneratorFactory.class, VersionsMetadataGeneratorFactory.class);
-
-        // remaining requirements of org.eclipse.aether.internal.impl.DefaultLocalRepositoryProvider
-        registry.bind(LocalRepositoryManagerFactory.class, EnhancedLocalRepositoryManagerFactory.class);
-
-        // remaining requirements of org.eclipse.aether.internal.impl.synccontext.DefaultSyncContextFactory
-        registry.bind(NamedLockFactoryAdapterFactory.class, NamedLockFactoryAdapterFactoryImpl.class);
-
-        // remaining requirements of org.eclipse.aether.internal.impl.DefaultRemoteRepositoryManager
-        registry.bind(UpdatePolicyAnalyzer.class, DefaultUpdatePolicyAnalyzer.class);
-        registry.bind(ChecksumPolicyProvider.class, DefaultChecksumPolicyProvider.class);
-
-        // remaining levels of requirements of org.eclipse.aether.internal.impl.DefaultRepositorySystem
-
-        // requirements of org.eclipse.aether.internal.impl.DefaultUpdateCheckManager
-        registry.bind(TrackingFileManager.class, DefaultTrackingFileManager.class);
-
-        // requirements of org.eclipse.aether.internal.impl.synccontext.named.NamedLockFactoryAdapterFactoryImpl
-        registry.bind(NamedLockFactory.class, FileLockNamedLockFactory.class);
-        registry.bind(NamedLockFactory.class, LocalReadWriteLockNamedLockFactory.class);
-        registry.bind(NamedLockFactory.class, NoopNamedLockFactory.class);
-        registry.bind(NamedLockFactory.class, LocalSemaphoreNamedLockFactory.class);
-        registry.bind(NameMappers.GAV_NAME, NameMapper.class, NameMappers.gavNameMapper());
-        registry.bind(NameMappers.STATIC_NAME, NameMapper.class, NameMappers.staticNameMapper());
-        registry.bind(NameMappers.DISCRIMINATING_NAME, NameMapper.class, NameMappers.discriminatingNameMapper());
-        registry.bind(NameMappers.FILE_GAV_NAME, NameMapper.class, NameMappers.fileGavNameMapper());
-        registry.bind(NameMappers.FILE_HGAV_NAME, NameMapper.class, NameMappers.fileHashingGavNameMapper());
-
-        // requirements of org.apache.maven.repository.internal.DefaultVersionResolver (these are deprecated)
-        registry.bind(org.eclipse.aether.impl.SyncContextFactory.class,
-                org.eclipse.aether.internal.impl.synccontext.legacy.DefaultSyncContextFactory.class);
-
-        // requirements of org.eclipse.aether.internal.impl.EnhancedLocalRepositoryManagerFactory
-        registry.bind(LocalPathComposer.class, DefaultLocalPathComposer.class);
-        registry.bind(LocalPathPrefixComposerFactory.class, DefaultLocalPathPrefixComposerFactory.class);
-
-        // additional services
-        registry.bind(org.eclipse.aether.spi.log.LoggerFactory.class, Slf4jLoggerFactory.class);
-
-        // resolver 1.9.x
-        registry.bind(RemoteRepositoryFilterManager.class, DefaultRemoteRepositoryFilterManager.class);
-        registry.bind(RepositorySystemLifecycle.class, DefaultRepositorySystemLifecycle.class);
-    }
-
-    /**
-     * Configure the transport related requirements of {@link RepositorySystem} in {@link DIRegistry}
-     */
-    private static void transportConfiguration(DIRegistry registry, Properties systemProperties) {
-        // in order to resolve the artifacts we need some connector factories
-        registry.bind(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class);
-        // repository connectory factory needs transporter provider(s)
-        registry.bind(TransporterProvider.class, DefaultTransporterProvider.class);
-
-        // and transport provider needs transport factories. there are several implementations, but one of them
-        // is another indirect factory - the WagonTransporterFactory. However it was marked as _ancient_ with
-        // Maven 3.9 / Maven Resolver 1.9, so we'll use the _native_ ones. Even if the wagon allows us to share
-        // the http client (wagon) easier.
-        //        registry.bind(TransporterFactory.class, WagonTransporterFactory.class);
-        registry.bind(TransporterFactory.class, FileTransporterFactory.class);
-        registry.bind(TransporterFactory.class, HttpTransporterFactory.class);
-
-        // requirements of org.eclipse.aether.transport.http.HttpTransporterFactory
-        // nexus2 - ETag: "{SHA1{d40d68ba1f88d8e9b0040f175a6ff41928abd5e7}}"
-        registry.bind(ChecksumExtractor.class, Nexus2ChecksumExtractor.class);
-        // x-checksum - x-checksum-sha1: c74edb60ca2a0b57ef88d9a7da28f591e3d4ce7b
-        registry.bind(ChecksumExtractor.class, XChecksumChecksumExtractor.class);
-
-        // requirements of org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory
-        registry.bind(RepositoryLayoutProvider.class, DefaultRepositoryLayoutProvider.class);
-        // repository layout provider needs layout factory
-        registry.bind(RepositoryLayoutFactory.class, Maven2RepositoryLayoutFactory.class);
-
-        // requirements of org.eclipse.aether.internal.impl.Maven2RepositoryLayoutFactory
-        registry.bind(ChecksumAlgorithmFactorySelector.class, DefaultChecksumAlgorithmFactorySelector.class);
-        // checksum algorithm factory selector needs at least MD5 and SHA1 algorithm factories
-        registry.bind(ChecksumAlgorithmFactory.class, Md5ChecksumAlgorithmFactory.class);
-        registry.bind(ChecksumAlgorithmFactory.class, Sha1ChecksumAlgorithmFactory.class);
-    }
-
-    /**
-     * Configure the Maven services in {@link DIRegistry} needed to process {@link Settings Maven settings}
-     */
-    private static void settingsConfiguration(DIRegistry registry, String localSettingsSecurity) {
-        // before getting/creating an org.eclipse.aether.RepositorySystemSession, we need settings as a source
-        // of several configuration options/settings
-        // and because settings may contain encrypted entries, we need security settings configuration too
-
-        // org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher has @Inject parameter
-        // for configuration file, so we're creating it manually
-        //        registry.bind(SecDispatcher.class, DefaultSecDispatcher.class);
-        // mind that
-        // org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION
-        // ("settings.security") is the master password too... (secret of Polichinelle)
-        DefaultSecDispatcher securityDispatcher = new DefaultSecDispatcher(new DefaultPlexusCipher());
-        securityDispatcher.setConfigurationFile(localSettingsSecurity);
-        registry.bind("securityDispatcher", SecDispatcher.class, securityDispatcher);
-        registry.bind(SettingsDecrypter.class, DefaultSettingsDecrypter.class);
-
-        // we could use org.apache.maven.settings.building.DefaultSettingsBuilder directly, but it's better
-        // to be consistent and use DI for that - especially because after
-        // https://issues.apache.org/jira/browse/MNG-6680, DefaultSettingsBuilder is no longer annotated
-        // with @org.codehaus.plexus.component.annotations.Component, but with @jakarta.inject.Named
-        registry.bind(SettingsReader.class, DefaultSettingsReader.class);
-        registry.bind(SettingsWriter.class, DefaultSettingsWriter.class);
-        registry.bind(SettingsValidator.class, DefaultSettingsValidator.class);
-        registry.bind(SettingsBuilder.class, DefaultSettingsBuilder.class);
-    }
-
-    /**
-     * Using the configured {@link DIRegistry}, load {@link Settings Maven settings}
-     */
-    public Settings mavenConfiguration(
-            DIRegistry registry, RepositorySystem repositorySystem,
-            Properties systemProperties, String mavenSettings) {
-        // settings are important to configure the session later
-        SettingsBuilder settingsBuilder = registry.lookupByClass(SettingsBuilder.class);
-        SettingsBuildingRequest sbRequest = new DefaultSettingsBuildingRequest();
-        sbRequest.setSystemProperties(systemProperties);
-        if (mavenSettings != null) {
-            sbRequest.setUserSettingsFile(new File(mavenSettings));
-        }
-        Settings settings;
-        try {
-            SettingsBuildingResult sbResult = settingsBuilder.build(sbRequest);
-            settings = sbResult.getEffectiveSettings();
-        } catch (SettingsBuildingException e) {
-            LOG.warn("Problem reading settings file {}: {}. Falling back to defaults.",
-                    mavenSettings, e.getMessage(), e);
-            settings = new Settings();
-        }
-
-        // local repository in this order:
-        // 1) -Dmaven.repo.local
-        // 2) settings.xml
-        // 3) ${user.home}/.m2/repository (if exists)
-        // 4) /tmp/.m2/repository
-        String localRepository = System.getProperty("maven.repo.local");
-        if (localRepository == null || "".equals(localRepository.trim())) {
-            localRepository = settings.getLocalRepository();
-        }
-        if (localRepository == null || "".equals(localRepository.trim())) {
-            Path m2Repository = Paths.get(System.getProperty("user.home"), ".m2/repository");
-            if (!m2Repository.toFile().isDirectory()) {
-                m2Repository = Paths.get(System.getProperty("java.io.tmpdir"), UUID.randomUUID().toString());
-                m2Repository.toFile().mkdirs();
-            }
-            localRepository = m2Repository.toString();
-        }
-        File m2Repository = new File(localRepository);
-        settings.setLocalRepository(m2Repository.getAbsolutePath());
-
-        // some parts of the settings may be encrypted:
-        //  - settings.getServer("xxx").getPassphrase()
-        //  - settings.getServer("xxx").getPassword()
-        //  - settings.getProxies().get(N).getPassword()
-        // so we have to use previously configured org.apache.maven.settings.crypto.SettingsDecrypter
-        SettingsDecrypter decrypter = registry.lookupByClass(SettingsDecrypter.class);
-        SettingsDecryptionRequest sdRequest = new DefaultSettingsDecryptionRequest(settings);
-        SettingsDecryptionResult sdResult = decrypter.decrypt(sdRequest);
-        settings.setProxies(sdResult.getProxies());
-        settings.setServers(sdResult.getServers());
-
-        // profile activation isn't implicit
-        for (Map.Entry<String, Profile> entry : settings.getProfilesAsMap().entrySet()) {
-            String name = entry.getKey();
-            Profile profile = entry.getValue();
-            if (profile.getActivation() != null && profile.getActivation().isActiveByDefault()) {
-                settings.getActiveProfiles().add(name);
-            }
-            // TODO: handle other activation methods (file, JDK, property, OS)
-        }
-
-        return settings;
-    }
-
-    /**
-     * Using the configured {@link DIRegistry}, obtain thread-safe {@link RepositorySystemSession} used to resolve and
-     * download Maven dependencies.
-     */
-    public RepositorySystemSession configureRepositorySystemSession(
-            DIRegistry registry,
-            Properties systemProperties, Settings settings, File localRepository) {
-        DefaultRepositorySystemSession session = new DefaultRepositorySystemSession();
-
-        // proxies are copied from the settings to proxy selector
-        ProxySelector proxySelector;
-        if (settings.getProxies().isEmpty()) {
-            proxySelector = new JreProxySelector();
-        } else {
-            proxySelector = new DefaultProxySelector();
-            for (Proxy proxy : settings.getProxies()) {
-                if (proxy.isActive()) {
-                    String nonProxyHosts = proxy.getNonProxyHosts();
-                    org.eclipse.aether.repository.Proxy proxyConfig;
-                    AuthenticationBuilder builder = new AuthenticationBuilder();
-                    if (proxy.getUsername() != null) {
-                        builder.addUsername(proxy.getUsername());
-                        builder.addPassword(proxy.getPassword());
-                    }
-                    proxyConfig = new org.eclipse.aether.repository.Proxy(
-                            proxy.getProtocol(), proxy.getHost(),
-                            proxy.getPort(), builder.build());
-                    ((DefaultProxySelector) proxySelector).add(proxyConfig, nonProxyHosts);
-                }
-            }
-        }
-
-        // process servers:
-        //  - we'll extend MirrorSelector to provide mirror authentication
-        //  - we want to set session configuration options for http headers and permissions
-        // see maven-core:
-        //    org.apache.maven.internal.aether.DefaultRepositorySystemSessionFactory.newRepositorySession()
-        Map<String, Object> serverConfigurations = new HashMap<>();
-        DefaultAuthenticationSelector baseAuthenticationSelector = new DefaultAuthenticationSelector();
-        AuthenticationSelector authenticationSelector
-                = new ConservativeAuthenticationSelector(baseAuthenticationSelector);
-
-        int connectTimeout = ConfigurationProperties.DEFAULT_CONNECT_TIMEOUT;
-        int requestTimeout = ConfigurationProperties.DEFAULT_REQUEST_TIMEOUT;
-
-        for (Server server : settings.getServers()) {
-            // no need to bother with null values
-            Authentication auth = new AuthenticationBuilder()
-                    .addPrivateKey(server.getPrivateKey(), server.getPassphrase())
-                    .addUsername(server.getUsername())
-                    .addPassword(server.getPassword())
-                    .build();
-            baseAuthenticationSelector.add(server.getId(), auth);
-
-            // see private constants in org.eclipse.aether.transport.wagon.WagonTransporter
-            if (server.getFilePermissions() != null) {
-                serverConfigurations.put("aether.connector.perms.fileMode." + server.getId(),
-                        server.getFilePermissions());
-            }
-            if (server.getDirectoryPermissions() != null) {
-                serverConfigurations.put("aether.connector.perms.dirMode." + server.getId(),
-                        server.getFilePermissions());
-            }
-
-            if (server.getConfiguration() instanceof Xpp3Dom) {
-                // === pre maven 3.9 / maven-resolver 1.9:
-                // this part is a generic configuration used by different Maven components
-                //  - entire configuration is read by maven-core itself and passed as
-                //    org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration object using
-                //    "aether.connector.wagon.config.<repoId>" config property in
-                //    org.apache.maven.internal.aether.DefaultRepositorySystemSessionFactory.newRepositorySession()
-                //  - it's then processed in org.eclipse.aether.transport.wagon.WagonTransporter.connectWagon()
-                //    by configured org.eclipse.aether.transport.wagon.WagonConfigurator. In `mvn` run, the
-                //    configurator is org.eclipse.aether.internal.transport.wagon.PlexusWagonConfigurator which
-                //    uses o.e.a.internal.transport.wagon.PlexusWagonConfigurator.WagonComponentConfigurator
-                //  - the object to configure is an instance of org.apache.maven.wagon.Wagon and
-                //    WagonComponentConfigurator simply uses reflection for nested properties
-                //  - so for typical wagon-http scenario (used by Maven distribution itself), we can configure:
-                //     - org.apache.maven.wagon.shared.http.AbstractHttpClientWagon.setBasicAuthScope()
-                //     - org.apache.maven.wagon.shared.http.AbstractHttpClientWagon.setHttpConfiguration()
-                //     - org.apache.maven.wagon.shared.http.AbstractHttpClientWagon.setHttpHeaders(Properties)
-                //     - org.apache.maven.wagon.shared.http.AbstractHttpClientWagon.setInitialBackoffSeconds()
-                //     - org.apache.maven.wagon.shared.http.AbstractHttpClientWagon.setProxyBasicAuthScope()
-                //     - org.apache.maven.wagon.AbstractWagon.setInteractive()
-                //     - org.apache.maven.wagon.AbstractWagon.setReadTimeout()
-                //     - org.apache.maven.wagon.AbstractWagon.setTimeout()
-                // see https://maven.apache.org/guides/mini/guide-http-settings.html
-                //
-                // the ultimate option is to configure org.apache.maven.wagon.shared.http.HttpConfiguration
-                // object which is reflectively passed to a wagon
-                //
-                // however guide-http-settings.html still mentions <configuration>/<httpHeaders> and it's a bit
-                // confusing...
-                //  - org.eclipse.aether.transport.wagon.WagonTransporter.WagonTransporter() constructor
-                //    gets a "aether.connector.http.headers.<repoId>" or "aether.connector.http.headers" config
-                //    property, but I don't see anything that sets it in maven/maven-resolver/maven-wagon
-                //  - this property is also checked by
-                //    org.eclipse.aether.transport.http.HttpTransporter.HttpTransporter()
-                //  - later, in org.eclipse.aether.transport.wagon.WagonTransporter.connectWagon(), full
-                //    reflection-based org.eclipse.aether.transport.wagon.WagonConfigurator.configure() is used
-                //    and wagon's "httpHeaders" field is overriden - previously it was set to the value
-                //    of org.eclipse.aether.transport.wagon.WagonTransporter.headers which contained a User-Agent
-                //    header set from "aether.connector.userAgent" property set by Maven...
-                //
-                // === maven 3.9 / maven-resolver 1.9:
-                // As https://maven.apache.org/guides/mini/guide-resolver-transport.html says, the default transport
-                // (the default transport used by Maven Resolver) changed from ancient Wagon to modern
-                // maven-resolver-transport-http aka native HTTP transport.
-                // org.apache.maven.internal.aether.DefaultRepositorySystemSessionFactory.newRepositorySession()
-                // (org.apache.maven:maven-core) has changed considerably in Maven 3.9.0. Before 3.9.0,
-                // org.apache.maven.settings.Server.getConfiguration() was taken and simply passed (wrapped in
-                // org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration) as aether session config property
-                // named "aether.connector.wagon.config.<serverId>"
-                //
-                // With maven 3.9 / maven-resolver 1.9, the same property is used, but the XML configuration is
-                // "translated to proper resolver configuration properties as well", so additionally:
-                // - <httpHeaders> is translated into Map set as "aether.connector.http.headers.<serverId>" property
-                // - <connectTimeout> is translated into Integer set as "aether.connector.connectTimeout.<serverId>"
-                // - <requestTimeout> is translated into Integer set as "aether.connector.requestTimeout.<serverId>"
-                // - if <httpConfiguration>/<all>/<connectionTimeout> is found, a WARNING is printed:
-                //   [WARNING] Settings for server <serverId> uses legacy format
-                // - if <httpConfiguration>/<all>/<readTimeout> is found, a WARNING is printed:
-                //   [WARNING] Settings for server <serverId> uses legacy format
-                // (mind the translation: connectionTimeout->connectTimeout and readTimeout->requestTimeout
-                //
-                // all the properties are described here: https://maven.apache.org/resolver/configuration.html
-
-                Map<String, String> headers = new LinkedHashMap<>();
-                Xpp3Dom serverConfig = (Xpp3Dom) server.getConfiguration();
-
-                // handle:
-                //     <server>
-                //      <id>my-server</id>
-                //      <configuration>
-                //        <httpHeaders>
-                //          <property>
-                //            <name>X-Asked-By</name>
-                //            <value>Camel</value>
-                //          </property>
-                //        </httpHeaders>
-                //      </configuration>
-                //    </server>
-                // see org.codehaus.plexus.component.configurator.converters.composite.PropertiesConverter
-                Xpp3Dom httpHeaders = serverConfig.getChild("httpHeaders");
-                if (httpHeaders != null) {
-                    for (Xpp3Dom httpHeader : httpHeaders.getChildren("property")) {
-                        Xpp3Dom name = httpHeader.getChild("name");
-                        String headerName = name.getValue();
-                        Xpp3Dom value = httpHeader.getChild("value");
-                        String headerValue = value.getValue();
-                        headers.put(headerName, headerValue);
-                    }
-                }
-                serverConfigurations.put(ConfigurationProperties.HTTP_HEADERS + "." + server.getId(), headers);
-
-                // DON'T handle (as it's pre-maven 3.9):
-                //     <server>
-                //      <id>my-server</id>
-                //      <configuration>
-                //        <httpConfiguration>
-                //          <all>
-                //            <connectionTimeout>5000</connectionTimeout>
-                //            <readTimeout>10000</readTimeout>
-                //          </all>
-                //        </httpConfiguration>
-                //      </configuration>
-                //    </server>
-                // see org.codehaus.plexus.component.configurator.converters.composite.ObjectWithFieldsConverter
-                // handle (maven 3.9+):
-                //     <server>
-                //      <id>my-server</id>
-                //      <configuration>
-                //        <connectTimeout>5000</connectTimeout>
-                //        <requestTimeout>5000</requestTimeout>
-                //      </configuration>
-                //    </server>
-                Xpp3Dom connectTimeoutNode = serverConfig.getChild("connectTimeout");
-                if (connectTimeoutNode != null) {
-                    try {
-                        connectTimeout = Integer.parseInt(connectTimeoutNode.getValue());
-                    } catch (NumberFormatException ignored) {
-                    }
-                }
-                Xpp3Dom requestTimeoutNode = serverConfig.getChild("requestTimeout");
-                if (requestTimeoutNode != null) {
-                    try {
-                        requestTimeout = Integer.parseInt(requestTimeoutNode.getValue());
-                    } catch (NumberFormatException ignored) {
-                    }
-                }
-            }
-        }
-
-        // mirror settings - Pax URL had something like AuthenticatedMirrorSelector which assigned
-        // authentication to mirror-representing RemoteRepositories. But it's not required if we
-        // properly use org.eclipse.aether.RepositorySystem#newResolutionRepositories()!
-        DefaultMirrorSelector mirrorSelector = new DefaultMirrorSelector();
-        for (Mirror mirror : settings.getMirrors()) {
-            mirrorSelector.add(mirror.getId(), mirror.getUrl(), mirror.getLayout(), false, false,
-                    mirror.getMirrorOf(), mirror.getMirrorOfLayouts());
-        }
-
-        // no more actual requirements, but we need more services when using
-        // org.eclipse.aether.RepositorySystemSession
-        LocalRepositoryManagerFactory lrmFactory = registry.lookupByClass(LocalRepositoryManagerFactory.class);
-
-        try {
-            session.setLocalRepositoryManager(lrmFactory.newInstance(session, new LocalRepository(localRepository)));
-        } catch (NoLocalRepositoryManagerException e) {
-            LOG.warn(e.getMessage(), e);
-        }
-
-        // more session configuration which is implicit with
-        // org.apache.maven.repository.internal.MavenRepositorySystemUtils.newSession()
-        session.setDependencyTraverser(new FatArtifactTraverser());
-        session.setDependencyManager(new ClassicDependencyManager());
-        // this is exactly what's done inside
-        // org.jboss.shrinkwrap.resolver.impl.maven.MavenWorkingSessionImpl.resolveDependencies() - we don't
-        // have to do it on each resolution attempt
-        DependencySelector depFilter = new AndDependencySelector(
-                new ScopeDependencySelector("test", "provided"),
-                new OptionalDependencySelector(),
-                new ExclusionDependencySelector());
-        session.setDependencySelector(depFilter);
-        DependencyGraphTransformer transformer = new ConflictResolver(
-                new NearestVersionSelector(), new JavaScopeSelector(),
-                new SimpleOptionalitySelector(), new JavaScopeDeriver());
-        transformer = new ChainedDependencyGraphTransformer(transformer, new JavaDependencyContextRefiner());
-        session.setDependencyGraphTransformer(transformer);
-
-        DefaultArtifactTypeRegistry stereotypes = new DefaultArtifactTypeRegistry();
-        stereotypes.add(new DefaultArtifactType("pom"));
-        stereotypes.add(new DefaultArtifactType("maven-plugin", "jar", "", "java"));
-        stereotypes.add(new DefaultArtifactType("jar", "jar", "", "java"));
-        stereotypes.add(new DefaultArtifactType("ejb", "jar", "", "java"));
-        stereotypes.add(new DefaultArtifactType("ejb-client", "jar", "client", "java"));
-        stereotypes.add(new DefaultArtifactType("test-jar", "jar", "tests", "java"));
-        stereotypes.add(new DefaultArtifactType("javadoc", "jar", "javadoc", "java"));
-        stereotypes.add(new DefaultArtifactType("java-source", "jar", "sources", "java", false, false));
-        stereotypes.add(new DefaultArtifactType("war", "war", "", "java", false, true));
-        stereotypes.add(new DefaultArtifactType("ear", "ear", "", "java", false, true));
-        stereotypes.add(new DefaultArtifactType("rar", "rar", "", "java", false, true));
-        stereotypes.add(new DefaultArtifactType("par", "par", "", "java", false, true));
-        session.setArtifactTypeRegistry(stereotypes);
-        session.setArtifactDescriptorPolicy(new SimpleArtifactDescriptorPolicy(true, true));
-
-        session.setUserProperties(null);
-        session.setSystemProperties(systemProperties);
-        // this allows passing -Dxxx=yyy as config properties
-        session.setConfigProperties(systemProperties);
-
-        // these properties may be externalized to camel-jbang properties
-        session.setConfigProperty("aether.connector.basic.threads", "4");
-        session.setConfigProperty("aether.collector.impl", "df"); // or "bf"
-
-        // timeouts. see:
-        //  - org.eclipse.aether.transport.http.HttpTransporter.HttpTransporter()
-        //  - org.eclipse.aether.transport.wagon.WagonTransporter.connectWagon()
-        session.setConfigProperty(ConfigurationProperties.CONNECT_TIMEOUT, connectTimeout);
-        session.setConfigProperty(ConfigurationProperties.REQUEST_TIMEOUT, requestTimeout);
-
-        // server headers configuration - for each <server> from the settings.xml
-        serverConfigurations.forEach(session::setConfigProperty);
-
-        // remaining customization of the session
-        session.setProxySelector(proxySelector);
-        session.setMirrorSelector(mirrorSelector);
-
-        // explicit null global policies, so each repository can define its own
-        session.setChecksumPolicy(null);
-        session.setUpdatePolicy(null);
-
-        // to associate authentications with remote repositories (also mirrored)
-        session.setAuthenticationSelector(authenticationSelector);
-        // offline mode selected using for example `camel run --download` option - should be online by default
-        session.setOffline(false);
-        // controls whether repositories declared in artifact descriptors should be ignored during transitive
-        // dependency collection
-        session.setIgnoreArtifactDescriptorRepositories(true);
-        // deprecated, no API replacement
-        //            session.setFileTransformerManager(null);
-        // not used
-        //            session.setVersionFilter(null);
-        //            session.setRepositoryListener(null);
-        //            session.setTransferListener(null);
-        //            session.setResolutionErrorPolicy(null);
-        //            session.setCache(null);
-        //            session.setData(null);
-        //            session.setReadOnly();
-        // could be useful to search through kamelet/jbang config
-        session.setWorkspaceReader(null);
-
-        return session;
-    }
-
-    /**
-     * Using the passed ({@code --repos} parameter or {@code camel.jbang.repos} option) and configured (in Maven
-     * settings) repomote repository location, prepare a list of {@link RemoteRepository remote repositories} to be used
-     * during Maven resolution. These repositories are <b>not yet</b> mirrored/proxied. Use
-     * {@link RepositorySystem#newResolutionRepositories} first.
-     *
-     * @param settings maven settings
-     * @param repos    optional, comma-separated list of URLs
-     * @param fresh    whether to check for remote updates of the artifacts (SNAPSHOTs)
-     */
-    public List<RemoteRepository> configureRemoteRepositories(Settings settings, String repos, boolean fresh) {
-        List<RemoteRepository> repositories = new ArrayList<>();
-
-        // a set to prevent duplicates, but do not store URLs directly (hashCode() may lead to DNS resolution!)
-        Set<String> repositoryURLs = new HashSet<>();
-
-        // add maven central first - always
-        repositories.add(new RemoteRepository.Builder("central", "default", MAVEN_CENTRAL_REPO)
-                .setReleasePolicy(fresh ? POLICY_FRESH : POLICY_DEFAULT)
-                .setSnapshotPolicy(POLICY_DISABLED)
-                .build());
-
-        // configure Apache snapshots - to be used if needed
-        apacheSnapshots = new RemoteRepository.Builder("apache-snapshot", "default", APACHE_SNAPSHOT_REPO)
-                .setReleasePolicy(POLICY_DISABLED)
-                .setSnapshotPolicy(fresh ? POLICY_FRESH : POLICY_DEFAULT)
-                .build();
-
-        // and custom repos and remember URLs to not duplicate the repositories from the settings
-        if (repos != null) {
-            for (String repo : repos.split(",")) {
-                try {
-                    URL url = new URL(repo);
-                    if (url.getHost().equals("repo1.maven.org")) {
-                        continue;
-                    }
-                    String id = "custom" + customCount++;
-                    RepositoryPolicy releasePolicy = fresh ? POLICY_FRESH : POLICY_DEFAULT;
-                    if (repositoryURLs.add(url.toExternalForm())) {
-                        if (url.getHost().equals("repository.apache.org") && url.getPath().contains("/snapshots")) {
-                            apacheSnapshotsIncluded = true;
-                            repositories.add(apacheSnapshots);
-                        } else {
-                            // both snapshots and releases allowed for custom repos
-                            repositories.add(new RemoteRepository.Builder(id, "default", repo)
-                                    .setReleasePolicy(releasePolicy)
-                                    .setSnapshotPolicy(fresh ? POLICY_FRESH : POLICY_DEFAULT)
-                                    .build());
-                        }
-                    }
-                } catch (MalformedURLException e) {
-                    LOG.warn("Can't use {} URL: {}. Skipping.", repo, e.getMessage(), e);
-                }
-            }
-        }
-
-        // then process the repositories from active profiles of external Maven settings
-        for (String profile : settings.getActiveProfiles()) {
-            for (Repository r : settings.getProfilesAsMap().get(profile).getRepositories()) {
-                try {
-                    URL url = new URL(r.getUrl());
-                    if (repositoryURLs.add(url.toExternalForm())) {
-                        if (url.getHost().equals("repository.apache.org") && url.getPath().startsWith("/snapshots")) {
-                            apacheSnapshotsIncluded = true;
-                        }
-                        RemoteRepository.Builder rb = new RemoteRepository.Builder(r.getId(), r.getLayout(), r.getUrl());
-                        if (r.getReleases() == null) {
-                            rb.setPolicy(fresh ? POLICY_FRESH : POLICY_DEFAULT);
-                        }
-                        // if someone defines Apache snapshots repository, (s)he has to specify proper policy, sorry.
-                        if (r.getSnapshots() == null) {
-                            rb.setSnapshotPolicy(POLICY_DISABLED);
-                        }
-                        repositories.add(rb.build());
-                    }
-                } catch (MalformedURLException e) {
-                    LOG.warn("Can't use {} URL from Maven settings: {}. Skipping.", r.getUrl(), e.getMessage(), e);
-                }
-            }
-        }
-
-        return repositories;
-    }
-
-    public List<MavenArtifact> resolveDependenciesViaAether(List<String> depIds, boolean transitively) {
-        return resolveDependenciesViaAether(depIds, remoteRepositories, transitively);
     }
 
     public List<MavenArtifact> resolveDependenciesViaAether(
-            List<String> depIds,
-            List<RemoteRepository> repositories, boolean transitively) {
-
+            List<String> depIds, Set<String> extraRepositories,
+            boolean transitively, boolean useApacheSnapshots) {
         try {
-            ArtifactTypeRegistry artifactTypeRegistry = repositorySystemSession.getArtifactTypeRegistry();
-
-            final List<ArtifactRequest> requests = new ArrayList<>(depIds.size());
-            CollectRequest collectRequest = new CollectRequest();
-            collectRequest.setRepositories(repositories);
-
-            for (String depId : depIds) {
-                ArtifactRequest ar = new ArtifactRequest();
-                ar.setRepositories(repositories);
-                ar.setArtifact(MavenGav.parseGav(depId, artifactTypeRegistry).getArtifact());
-                requests.add(ar);
-
-                Dependency dependency = new Dependency(ar.getArtifact(), "compile", false);
-                collectRequest.addDependency(dependency);
-                //                collectRequest.addManagedDependency(...);
-            }
-
-            DependencyFilter filter = transitively
-                    ? new AcceptAllDependencyFilter()
-                    : new AcceptDirectDependencyFilter(requests);
-
-            DependencyRequest dependencyRequest = new DependencyRequest(collectRequest, filter);
-            DependencyResult dependencyResult
-                    = repositorySystem.resolveDependencies(repositorySystemSession, dependencyRequest);
-
-            return dependencyResult.getArtifactResults().stream()
-                    .map(dr -> {
-                        String gav = dr.getArtifact().getGroupId() + ":"
-                                     + dr.getArtifact().getArtifactId() + ":"
-                                     + (!"jar".equals(dr.getArtifact().getExtension())
-                                             ? dr.getArtifact().getExtension() + ":" : "")
-                                     + (!"".equals(dr.getArtifact().getClassifier())
-                                             ? dr.getArtifact().getClassifier() + ":" : "")
-                                     + dr.getArtifact().getVersion();
-                        return new MavenArtifact(MavenGav.parseGav(gav, artifactTypeRegistry), dr.getArtifact().getFile());
-                    })
-                    .collect(Collectors.toList());
-        } catch (DependencyResolutionException e) {
-            String repos = repositories == null
+            return mavenDownloader.resolveArtifacts(depIds, extraRepositories, transitively, useApacheSnapshots);
+        } catch (MavenResolutionException e) {
+            String repos = e.getRepositories() == null
                     ? "(empty URL list)"
-                    : repositories.stream().map(RemoteRepository::getUrl).collect(Collectors.joining(", "));
+                    : String.join(", ", e.getRepositories());
             String msg = "Cannot resolve dependencies in " + repos;
             throw new DownloadException(msg, e);
         } catch (RuntimeException e) {
@@ -1364,69 +465,11 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
         }
     }
 
-    public List<String[]> resolveAvailableVersions(
-            String groupId, String artifactId, String minimumVersion, RemoteRepository repository) {
-
-        List<String[]> answer = new ArrayList<>();
-
-        try {
-            MetadataRequest ar = new MetadataRequest();
-            ar.setRepository(repository);
-            ar.setFavorLocalRepository(false);
-            ar.setMetadata(new DefaultMetadata(groupId, artifactId, "maven-metadata.xml", Metadata.Nature.RELEASE));
-
-            List<MetadataResult> result = repositorySystem.resolveMetadata(repositorySystemSession, List.of(ar));
-            for (MetadataResult mr : result) {
-                if (mr.isResolved() && mr.getMetadata().getFile() != null) {
-                    File f = mr.getMetadata().getFile();
-                    if (f.exists() && f.isFile()) {
-                        DocumentBuilderFactory dbf = XmlHelper.createDocumentBuilderFactory();
-                        DocumentBuilder db = dbf.newDocumentBuilder();
-                        Document dom = db.parse(f);
-                        NodeList nl = dom.getElementsByTagName("version");
-                        for (int i = 0; i < nl.getLength(); i++) {
-                            Element node = (Element) nl.item(i);
-                            String v = node.getTextContent();
-                            if (v != null) {
-                                if ("camel-spring-boot".equals(artifactId)) {
-                                    String sbv = null;
-                                    if (VersionHelper.isGE(v, minimumVersion)) {
-                                        sbv = resolveSpringBootVersionByCamelVersion(v, repository);
-                                    }
-                                    answer.add(new String[] { v, sbv });
-                                } else if ("camel-quarkus-catalog".equals(artifactId)) {
-                                    if (VersionHelper.isGE(v, MINIMUM_QUARKUS_VERSION)) {
-                                        String cv = resolveCamelVersionByQuarkusVersion(v, repository);
-                                        if (cv != null && VersionHelper.isGE(cv, minimumVersion)) {
-                                            answer.add(new String[] { cv, v });
-                                        }
-                                    }
-                                } else {
-                                    answer.add(new String[] { v, null });
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        } catch (Exception e) {
-            String msg = "Cannot resolve available versions in " + repository.getUrl();
-            throw new DownloadException(msg, e);
-        }
-
-        return answer;
-    }
-
-    private String resolveCamelVersionByQuarkusVersion(String quarkusVersion, RemoteRepository repository) throws Exception {
+    private String resolveCamelVersionByQuarkusVersion(String quarkusVersion, Set<String> extraRepos)
+            throws Exception {
         String gav = "org.apache.camel.quarkus" + ":" + "camel-quarkus" + ":pom:" + quarkusVersion;
-        // always include maven central
-        List<RemoteRepository> repos;
-        if (repository == remoteRepositories.get(0)) {
-            repos = List.of(repository);
-        } else {
-            repos = List.of(remoteRepositories.get(0), repository);
-        }
-        List<MavenArtifact> artifacts = resolveDependenciesViaAether(List.of(gav), repos, false);
+
+        List<MavenArtifact> artifacts = resolveDependenciesViaAether(List.of(gav), extraRepos, false, false);
         if (!artifacts.isEmpty()) {
             MavenArtifact ma = artifacts.get(0);
             if (ma != null && ma.getFile() != null) {
@@ -1449,16 +492,11 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
         return null;
     }
 
-    private String resolveSpringBootVersionByCamelVersion(String camelVersion, RemoteRepository repository) throws Exception {
+    private String resolveSpringBootVersionByCamelVersion(String camelVersion, Set<String> extraRepos)
+            throws Exception {
         String gav = "org.apache.camel.springboot" + ":" + "spring-boot" + ":pom:" + camelVersion;
-        // always include maven central
-        List<RemoteRepository> repos;
-        if (repository == remoteRepositories.get(0)) {
-            repos = List.of(repository);
-        } else {
-            repos = List.of(remoteRepositories.get(0), repository);
-        }
-        List<MavenArtifact> artifacts = resolveDependenciesViaAether(List.of(gav), repos, false);
+
+        List<MavenArtifact> artifacts = resolveDependenciesViaAether(List.of(gav), extraRepos, false, false);
         if (!artifacts.isEmpty()) {
             MavenArtifact ma = artifacts.get(0);
             if (ma != null && ma.getFile() != null) {
@@ -1481,37 +519,4 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
         return null;
     }
 
-    private static class AcceptAllDependencyFilter implements DependencyFilter {
-        @Override
-        public boolean accept(DependencyNode node, List<DependencyNode> parents) {
-            return true;
-        }
-    }
-
-    private static class AcceptDirectDependencyFilter implements DependencyFilter {
-        private final List<ArtifactRequest> requests;
-
-        public AcceptDirectDependencyFilter(List<ArtifactRequest> requests) {
-            this.requests = requests;
-        }
-
-        @Override
-        public boolean accept(DependencyNode node, List<DependencyNode> parents) {
-            Dependency dependency = node.getDependency();
-            if (dependency == null) {
-                return false;
-            }
-            Artifact current = dependency.getArtifact();
-            for (ArtifactRequest ar : requests) {
-                if (current.getGroupId().equals(ar.getArtifact().getGroupId())
-                        && current.getArtifactId().equals(ar.getArtifact().getArtifactId())
-                        && current.getExtension().equals(ar.getArtifact().getExtension())
-                        && current.getClassifier().equals(ar.getArtifact().getClassifier())) {
-                    return true;
-                }
-            }
-            return false;
-        }
-    }
-
 }
diff --git a/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/MavenDependencyResolverTest.java b/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/MavenDependencyResolverTest.java
index a91fb5bd854..980247b4a91 100644
--- a/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/MavenDependencyResolverTest.java
+++ b/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/MavenDependencyResolverTest.java
@@ -16,44 +16,15 @@
  */
 package org.apache.camel.main;
 
-import java.io.File;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.Base64;
 import java.util.List;
-import java.util.Properties;
-import java.util.concurrent.TimeUnit;
 
-import org.apache.camel.main.download.MavenArtifact;
 import org.apache.camel.main.download.MavenDependencyDownloader;
-import org.apache.camel.main.injection.DIRegistry;
-import org.apache.camel.util.FileUtil;
-import org.apache.commons.codec.binary.Hex;
-import org.apache.http.Header;
-import org.apache.http.entity.StringEntity;
-import org.apache.http.impl.bootstrap.HttpServer;
-import org.apache.http.impl.bootstrap.ServerBootstrap;
-import org.apache.maven.settings.Mirror;
-import org.apache.maven.settings.Repository;
-import org.apache.maven.settings.Settings;
-import org.eclipse.aether.RepositorySystem;
-import org.eclipse.aether.RepositorySystemSession;
-import org.eclipse.aether.artifact.DefaultArtifact;
-import org.eclipse.aether.repository.RemoteRepository;
-import org.eclipse.aether.resolution.ArtifactRequest;
-import org.eclipse.aether.resolution.ArtifactResult;
-import org.junit.jupiter.api.AfterAll;
+import org.apache.camel.tooling.maven.MavenArtifact;
 import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.sonatype.plexus.components.cipher.DefaultPlexusCipher;
-import org.sonatype.plexus.components.cipher.PlexusCipher;
-import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -63,86 +34,22 @@ public class MavenDependencyResolverTest {
 
     public static final Logger LOG = LoggerFactory.getLogger(MavenDependencyResolverTest.class);
 
-    private static HttpServer localServer;
-
-    @BeforeAll
-    public static void startMavenMirror() throws Exception {
-        localServer = ServerBootstrap.bootstrap()
-                .setListenerPort(8888)
-                .registerHandler("/maven/*", (req, res, context) -> {
-                    Header authz = req.getFirstHeader("Authorization");
-                    if (authz == null) {
-                        res.addHeader("WWW-Authenticate", "Basic realm=Camel");
-                        res.setStatusCode(401);
-                        return;
-                    }
-                    String creds = new String(Base64.getDecoder().decode(authz.getValue().split(" ")[1]));
-                    if (!"camel:passw0rd".equals(creds)) {
-                        res.setStatusCode(403);
-                        return;
-                    }
-                    LOG.info("Request: {}", req.getRequestLine());
-                    String request = req.getRequestLine().getUri().substring("/maven".length());
-                    if (request.endsWith(".jar") || request.endsWith(".pom")) {
-                        res.setEntity(new StringEntity(request));
-                    } else {
-                        MessageDigest md = null;
-                        try {
-                            if (request.endsWith(".md5")) {
-                                md = MessageDigest.getInstance("MD5");
-                                request = request.substring(0, request.length() - 4);
-                            } else if (request.endsWith(".sha1")) {
-                                md = MessageDigest.getInstance("SHA");
-                                request = request.substring(0, request.length() - 5);
-                            }
-                            if (md != null) {
-                                byte[] digest = md.digest(request.getBytes(StandardCharsets.UTF_8));
-                                res.setEntity(new StringEntity(Hex.encodeHexString(digest)));
-                            }
-                        } catch (NoSuchAlgorithmException e) {
-                            throw new RuntimeException(e);
-                        }
-                    }
-                    res.setStatusCode(200);
-                })
-                .create();
-        localServer.start();
-    }
-
-    @AfterAll
-    public static void stopMavenMirror() {
-        if (localServer != null) {
-            localServer.shutdown(2, TimeUnit.SECONDS);
-        }
-    }
-
-    @Test
-    public void masterPasswords() throws Exception {
-        PlexusCipher pc = new DefaultPlexusCipher();
-        String mp = pc.encrypt("camel", DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION);
-        LOG.info("master password: {}", mp); // e.g., "SHrYKy0oCBEH5SHhRcuv0U52J3E908O23QWHDyEiGtQ="
-        String p = pc.encrypt("passw0rd", "camel");
-        LOG.info("password: {}", p); // e.g., "9V4tKIxO4ZsHx63bkn9uy6zsYM9VJyG03sTsPzPDK9c="
-
-        assertEquals("passw0rd", pc.decrypt(p, pc.decrypt(mp, DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION)));
-        assertEquals("camel", pc.decrypt(mp, DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION));
-    }
-
     @Test
     public void testDownload() throws Exception {
         List<String> deps = List.of("org.apache.camel:camel-core:3.17.0");
         try (MavenDependencyDownloader downloader = new MavenDependencyDownloader()) {
-            // build() creates own DIRegistry and configures the resolver/aether stuff
+            // build() creates own DIRegistry and configures the resolver/aether stuff  through
+            // org.apache.camel:camel-tooling-maven
             downloader.build();
 
-            List<MavenArtifact> answer = downloader.resolveDependenciesViaAether(deps, true);
+            List<MavenArtifact> answer = downloader.resolveDependenciesViaAether(deps, null, true, false);
             Assertions.assertNotNull(answer);
             assertTrue(answer.size() > 15);
             for (MavenArtifact ma : answer) {
                 LOG.info("Artifact (transitive): {}", ma);
             }
 
-            answer = downloader.resolveDependenciesViaAether(deps, false);
+            answer = downloader.resolveDependenciesViaAether(deps, null, false, false);
             Assertions.assertNotNull(answer);
             assertEquals(1, answer.size());
             for (MavenArtifact ma : answer) {
@@ -151,146 +58,4 @@ public class MavenDependencyResolverTest {
         }
     }
 
-    @Test
-    public void playingWithRepositorySystem() throws Exception {
-        // MRESOLVER-157 is about removal of org.apache.maven.repository.internal.MavenRepositorySystemUtils,
-        // so we can 1) do it manually, 2) use guice/sisu
-
-        // org.eclipse.aether.RepositorySystem (2 levels down)
-        //    org.eclipse.aether.impl.VersionResolver
-        //       org.eclipse.aether.impl.MetadataResolver
-        //       org.eclipse.aether.impl.SyncContextFactory
-        //       org.eclipse.aether.impl.RepositoryEventDispatcher
-        //    org.eclipse.aether.impl.VersionRangeResolver
-        //       org.eclipse.aether.impl.MetadataResolver
-        //       org.eclipse.aether.impl.SyncContextFactory
-        //       org.eclipse.aether.impl.RepositoryEventDispatcher
-        //    org.eclipse.aether.impl.ArtifactResolver
-        //       org.eclipse.aether.spi.io.FileProcessor
-        //       org.eclipse.aether.impl.RepositoryEventDispatcher
-        //       org.eclipse.aether.impl.VersionResolver
-        //       org.eclipse.aether.impl.UpdateCheckManager
-        //       org.eclipse.aether.impl.RepositoryConnectorProvider
-        //       org.eclipse.aether.impl.RemoteRepositoryManager
-        //       org.eclipse.aether.spi.synccontext.SyncContextFactory
-        //       org.eclipse.aether.impl.OfflineController
-        //    org.eclipse.aether.impl.MetadataResolver
-        //       org.eclipse.aether.impl.RepositoryEventDispatcher
-        //       org.eclipse.aether.impl.UpdateCheckManager
-        //       org.eclipse.aether.impl.RepositoryConnectorProvider
-        //       org.eclipse.aether.impl.RemoteRepositoryManager
-        //       org.eclipse.aether.spi.synccontext.SyncContextFactory
-        //       org.eclipse.aether.impl.OfflineController
-        //    org.eclipse.aether.impl.ArtifactDescriptorReader
-        //       org.eclipse.aether.impl.RemoteRepositoryManager
-        //       org.eclipse.aether.impl.VersionResolver
-        //       org.eclipse.aether.impl.VersionRangeResolver
-        //       org.eclipse.aether.impl.ArtifactResolver
-        //       org.apache.maven.model.building.ModelBuilder
-        //       org.eclipse.aether.impl.RepositoryEventDispatcher
-        //    org.eclipse.aether.impl.DependencyCollector
-        //       Map<String, org.eclipse.aether.internal.impl.collect.DependencyCollectorDelegate>
-        //    org.eclipse.aether.impl.Installer
-        //       org.eclipse.aether.spi.io.FileProcessor
-        //       org.eclipse.aether.impl.RepositoryEventDispatcher
-        //       Set<org.eclipse.aether.impl.MetadataGeneratorFactory>
-        //       org.eclipse.aether.spi.synccontext.SyncContextFactory
-        //    org.eclipse.aether.impl.Deployer
-        //       org.eclipse.aether.spi.io.FileProcessor
-        //       org.eclipse.aether.impl.RepositoryEventDispatcher
-        //       org.eclipse.aether.impl.RepositoryConnectorProvider
-        //       org.eclipse.aether.impl.RemoteRepositoryManager
-        //       org.eclipse.aether.impl.UpdateCheckManager
-        //       Set<org.eclipse.aether.impl.MetadataGeneratorFactory>
-        //       org.eclipse.aether.spi.synccontext.SyncContextFactory
-        //       org.eclipse.aether.impl.OfflineController
-        //    org.eclipse.aether.impl.LocalRepositoryProvider
-        //       Set<org.eclipse.aether.spi.localrepo.LocalRepositoryManagerFactory>
-        //    org.eclipse.aether.spi.synccontext.SyncContextFactory
-        //       org.eclipse.aether.internal.impl.synccontext.named.NamedLockFactorySelector
-        //    org.eclipse.aether.impl.RemoteRepositoryManager
-        //       org.eclipse.aether.impl.UpdatePolicyAnalyzer
-        //       org.eclipse.aether.spi.connector.checksum.ChecksumPolicyProvider
-
-        try (DIRegistry registry = new DIRegistry();
-             MavenDependencyDownloader downloader = new MavenDependencyDownloader()) {
-            // here we don't call downloader.build() and will do the same stuff manually for demonstration purpose
-
-            // see org.eclipse.aether.impl.DefaultServiceLocator.DefaultServiceLocator() - it registers
-            // lots of default implementations to get started (but it's deprecated with MRESOLVER-157)
-
-            // global settings file is by default ${m2.home}/.m2/settings.xml
-            //  - no defaults in Maven, but shrinkwrap uses this order:
-            //     - -Dmaven.home
-            //     - $M2_HOME
-            //     - $MAVEN_HOME
-            // local settings file is by default ${user.home}/.m2/settings.xml
-            // security settings file is by default ~/.m2/settings-security.xml
-            // (see: org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher), but it may be altered
-            // but it may be altered by (also from plexus-sec-dispatcher) -Dsettings.security
-            // local repository is by default ${user.home}/.m2/repository, but may be altered by
-            // -Dmaven.repo.local
-            String localSettings = "target/test-classes/.m2/settings.xml";
-            String localSettingsSecurity = "target/test-classes/.m2/settings-security.xml";
-
-            downloader.setMavenSettings(localSettings);
-            downloader.setMavenSettingsSecurity(localSettingsSecurity);
-            downloader.setFresh(true);
-            downloader.setRepos(null);
-            //            downloader.build();
-
-            Properties systemProperties = new Properties();
-
-            // now, org.eclipse.aether.RepositorySystem can be obtained
-            RepositorySystem repositorySystem
-                    = downloader.configureRepositorySystem(registry, systemProperties, localSettingsSecurity);
-
-            Settings settings = downloader.mavenConfiguration(registry, repositorySystem,
-                    systemProperties, localSettings);
-
-            // when using Maven without a project that may contain <repositories> in pom.xml, repositories
-            // are taken from the active profiles defined in settings. If a repository is protected, the id
-            // must match an id of one of the <server>s defined in the settings
-            for (String ap : settings.getActiveProfiles()) {
-                List<Repository> repositories = settings.getProfilesAsMap().get(ap).getRepositories();
-                repositories.forEach(r -> {
-                    if ("test-server".equals(r.getId())) {
-                        r.setUrl("http://localhost:" + localServer.getLocalPort() + "/maven/repository");
-                    }
-                });
-            }
-            for (Mirror mirror : settings.getMirrors()) {
-                if ("test-mirror".equals(mirror.getId())) {
-                    mirror.setUrl("http://localhost:" + localServer.getLocalPort() + "/maven/mirror");
-                }
-            }
-
-            // for test, we'll use hardcoded version
-            String localRepository = "target/.m2/repository";
-            // local repository manager is required and never set implicitly
-            File m2Repo = new File(localRepository);
-            FileUtil.removeDir(m2Repo);
-
-            // we can finally create a session to resolve artifacts
-            RepositorySystemSession session
-                    = downloader.configureRepositorySystemSession(registry, systemProperties, settings, m2Repo);
-
-            List<RemoteRepository> remoteRepositories = downloader.configureRemoteRepositories(settings, null, false);
-
-            // finally we can resolve the artifact
-            ArtifactRequest request = new ArtifactRequest();
-            // repositories from the settings. auth, mirrors and proxies should be handled automatically if we use
-            // one handy method: org.eclipse.aether.RepositorySystem#newResolutionRepositories()
-            for (RemoteRepository r : repositorySystem.newResolutionRepositories(session, remoteRepositories)) {
-                request.addRepository(r);
-            }
-            request.setArtifact(new DefaultArtifact("org.apache.camel", "camel-anything", "jar", "3.42.0"));
-
-            ArtifactResult result = repositorySystem.resolveArtifact(session, request);
-            assertTrue(result.getArtifact().getFile().isFile());
-            assertEquals("/mirror/org/apache/camel/camel-anything/3.42.0/camel-anything-3.42.0.jar",
-                    Files.readString(result.getArtifact().getFile().toPath()));
-        }
-    }
-
 }
diff --git a/parent/pom.xml b/parent/pom.xml
index 5161c91ea93..e9efd15647a 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -253,6 +253,7 @@
         <jakarta-enterprise-cdi-api-version>4.0.1</jakarta-enterprise-cdi-api-version>
         <jakarta-api-version>2.1.5</jakarta-api-version>
         <jakarta.el-version>3.0.3</jakarta.el-version>
+        <jakarta-inject-version>2.0.1</jakarta-inject-version>
         <jakarta-xml-bind-api-version>4.0.0</jakarta-xml-bind-api-version>
         <jakarta-xml-soap-api-version>3.0.0</jakarta-xml-soap-api-version>
         <jakarta-xml-ws-api-version>4.0.0</jakarta-xml-ws-api-version>
@@ -524,6 +525,11 @@
                 <artifactId>camel-tooling-model</artifactId>
                 <version>${project.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.apache.camel</groupId>
+                <artifactId>camel-tooling-maven</artifactId>
+                <version>${project.version}</version>
+            </dependency>
             <dependency>
                 <groupId>org.apache.camel</groupId>
                 <artifactId>camel-api</artifactId>
diff --git a/tooling/camel-tooling-maven/pom.xml b/tooling/camel-tooling-maven/pom.xml
new file mode 100644
index 00000000000..34633f5a4bd
--- /dev/null
+++ b/tooling/camel-tooling-maven/pom.xml
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>tooling</artifactId>
+        <version>4.0.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>camel-tooling-maven</artifactId>
+
+    <name>Camel :: Tooling :: Maven</name>
+    <description>Utilities to make Maven operations easier</description>
+
+    <properties>
+        <camel.osgi.import.pkg>
+            *
+        </camel.osgi.import.pkg>
+        <camel.osgi.export.pkg>
+            org.apache.camel.tooling.maven
+        </camel.osgi.export.pkg>
+    </properties>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-support</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>jakarta.inject</groupId>
+            <artifactId>jakarta.inject-api</artifactId>
+            <version>${jakarta-inject-version}</version>
+        </dependency>
+
+        <!-- maven / maven resolver -->
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-resolver-provider</artifactId>
+            <version>${maven-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-settings-builder</artifactId>
+            <version>${maven-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven.resolver</groupId>
+            <artifactId>maven-resolver-api</artifactId>
+            <version>${maven-resolver-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven.resolver</groupId>
+            <artifactId>maven-resolver-spi</artifactId>
+            <version>${maven-resolver-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven.resolver</groupId>
+            <artifactId>maven-resolver-impl</artifactId>
+            <version>${maven-resolver-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven.resolver</groupId>
+            <artifactId>maven-resolver-connector-basic</artifactId>
+            <version>${maven-resolver-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven.resolver</groupId>
+            <artifactId>maven-resolver-transport-file</artifactId>
+            <version>${maven-resolver-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven.resolver</groupId>
+            <artifactId>maven-resolver-transport-http</artifactId>
+            <version>${maven-resolver-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven.resolver</groupId>
+            <artifactId>maven-resolver-util</artifactId>
+            <version>${maven-resolver-version}</version>
+        </dependency>
+
+        <!-- testing -->
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-slf4j2-impl</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+        </plugins>
+    </build>
+
+</project>
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenArtifact.java b/tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/MavenArtifact.java
similarity index 89%
copy from dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenArtifact.java
copy to tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/MavenArtifact.java
index d9ca9c07ecd..8d83a791a89 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenArtifact.java
+++ b/tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/MavenArtifact.java
@@ -14,10 +14,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.main.download;
+package org.apache.camel.tooling.maven;
 
 import java.io.File;
 
+/**
+ * Aggregate of {@link MavenGav} and actually resolved file for the related Maven artifact.
+ */
 public class MavenArtifact {
 
     private final MavenGav gav;
diff --git a/tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/MavenDownloader.java b/tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/MavenDownloader.java
new file mode 100644
index 00000000000..ca08ce3d755
--- /dev/null
+++ b/tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/MavenDownloader.java
@@ -0,0 +1,67 @@
+/*
+ * 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.tooling.maven;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Pragmatic Maven download/resolution API that should replace usage of Ivy/Grape and Shrinkwrap across Camel.
+ */
+public interface MavenDownloader {
+
+    /**
+     * Main resolution method. Using Maven Resolver, a list of maven coordinates (in the form of
+     * {@code groupId:artifactId[:packaging[:classifier]]:version}) is used to download artifacts from configured Maven
+     * repositories.
+     *
+     * @param  dependencyGAVs     a list of Maven coordinates
+     * @param  extraRepositories  nullable list of additional repositories to use (except the discovered ones)
+     * @param  transitively       whether to download/resolve dependencies transitively
+     * @param  useApacheSnapshots whether to include Apache Snapshots repository in the list of used repositories
+     * @return
+     * @throws {@link             MavenResolutionException} that can hold a list of repositories used during resolution.
+     */
+    List<MavenArtifact> resolveArtifacts(
+            List<String> dependencyGAVs, Set<String> extraRepositories,
+            boolean transitively, boolean useApacheSnapshots)
+            throws MavenResolutionException;
+
+    /**
+     * Resolves available versions for groupId + artifactId from single remote repository.
+     *
+     * @param groupId
+     * @param artifactId
+     * @param repository external repository to use (defaults to Maven Central if {@code null})
+     * @return
+     */
+    List<MavenGav> resolveAvailableVersions(String groupId, String artifactId, String repository)
+            throws MavenResolutionException;
+
+    /**
+     * Existing, configured {@link MavenDownloader} can be used as a template to create customized version which shares
+     * most of the configuration except underlying {@code org.eclipse.aether.RepositorySystemSession}, which can't be
+     * shared.
+     *
+     * @param  localRepository
+     * @param  connectTimeout
+     * @param  requestTimeout
+     * @return
+     */
+    MavenDownloader customize(String localRepository, int connectTimeout, int requestTimeout);
+
+}
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenDependencyDownloader.java b/tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/MavenDownloaderImpl.java
similarity index 67%
copy from dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenDependencyDownloader.java
copy to tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/MavenDownloaderImpl.java
index 868f9f13098..8b83205f313 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenDependencyDownloader.java
+++ b/tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/MavenDownloaderImpl.java
@@ -14,44 +14,32 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.main.download;
+package org.apache.camel.tooling.maven;
 
+import java.io.BufferedInputStream;
 import java.io.File;
-import java.lang.management.ManagementFactory;
-import java.lang.management.RuntimeMXBean;
+import java.io.FileInputStream;
 import java.net.MalformedURLException;
 import java.net.URL;
-import java.net.URLClassLoader;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
 import java.util.UUID;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
 
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.NodeList;
-
-import org.apache.camel.CamelContext;
-import org.apache.camel.CamelContextAware;
-import org.apache.camel.main.injection.DIRegistry;
-import org.apache.camel.main.util.VersionHelper;
-import org.apache.camel.main.util.XmlHelper;
-import org.apache.camel.support.service.ServiceHelper;
 import org.apache.camel.support.service.ServiceSupport;
-import org.apache.camel.util.FileUtil;
+import org.apache.camel.tooling.maven.support.DIRegistry;
+import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader;
 import org.apache.maven.model.building.DefaultModelBuilderFactory;
 import org.apache.maven.model.building.ModelBuilder;
 import org.apache.maven.repository.internal.DefaultArtifactDescriptorReader;
@@ -89,6 +77,7 @@ import org.eclipse.aether.RepositorySystem;
 import org.eclipse.aether.RepositorySystemSession;
 import org.eclipse.aether.artifact.Artifact;
 import org.eclipse.aether.artifact.ArtifactTypeRegistry;
+import org.eclipse.aether.artifact.DefaultArtifact;
 import org.eclipse.aether.artifact.DefaultArtifactType;
 import org.eclipse.aether.collection.CollectRequest;
 import org.eclipse.aether.collection.DependencyGraphTransformer;
@@ -169,6 +158,8 @@ import org.eclipse.aether.repository.ProxySelector;
 import org.eclipse.aether.repository.RemoteRepository;
 import org.eclipse.aether.repository.RepositoryPolicy;
 import org.eclipse.aether.resolution.ArtifactRequest;
+import org.eclipse.aether.resolution.ArtifactResolutionException;
+import org.eclipse.aether.resolution.ArtifactResult;
 import org.eclipse.aether.resolution.DependencyRequest;
 import org.eclipse.aether.resolution.DependencyResolutionException;
 import org.eclipse.aether.resolution.DependencyResult;
@@ -217,16 +208,16 @@ import org.sonatype.plexus.components.cipher.DefaultPlexusCipher;
 import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher;
 import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher;
 
-public class MavenDependencyDownloader extends ServiceSupport implements DependencyDownloader {
+/**
+ * The only class in Camel that deals with all these DI mechanisms of maven-resolver library.
+ */
+public class MavenDownloaderImpl extends ServiceSupport implements MavenDownloader {
+
+    public static final Logger LOG = LoggerFactory.getLogger(MavenDownloader.class);
 
     public static final String MAVEN_CENTRAL_REPO = "https://repo1.maven.org/maven2";
     public static final String APACHE_SNAPSHOT_REPO = "https://repository.apache.org/snapshots";
 
-    private static final Logger LOG = LoggerFactory.getLogger(MavenDependencyDownloader.class);
-    private static final String CP = System.getProperty("java.class.path");
-
-    private static final String MINIMUM_QUARKUS_VERSION = "2.0.0";
-
     private static final RepositoryPolicy POLICY_DEFAULT = new RepositoryPolicy(
             true, RepositoryPolicy.UPDATE_POLICY_NEVER, RepositoryPolicy.CHECKSUM_POLICY_WARN);
     private static final RepositoryPolicy POLICY_FRESH = new RepositoryPolicy(
@@ -234,419 +225,263 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
     private static final RepositoryPolicy POLICY_DISABLED = new RepositoryPolicy(
             false, RepositoryPolicy.UPDATE_POLICY_NEVER, RepositoryPolicy.CHECKSUM_POLICY_IGNORE);
 
-    int customCount = 1;
-    private String[] bootClasspath;
-    private DownloadThreadPool threadPool;
+    private RepositorySystem repositorySystem;
+    private RepositorySystemSession repositorySystemSession;
+
+    // repositories to be used with maven-resolver, read from settings and configuration parameters.
+    // These are processed according to mirror/proxy configuration
+    private final List<RemoteRepository> remoteRepositories = new ArrayList<>();
+    // pre-configured Maven Central repository
+    private RemoteRepository centralRepository;
+    // pre-configured Maven Central repository with mirror/proxy configuration
+    private RemoteRepository centralResolutionRepository;
+    // pre-configured Apache Snapshots repository in case it's needed on demand
+    private RemoteRepository apacheSnapshotsRepository;
+    // pre-configured Apache Snapshots repository with mirror/proxy configuration
+    private RemoteRepository apacheSnapshotsResolutionRepository;
+    private RepositoryPolicy defaultPolicy;
+
+    // the necessary, thin DI container to configure Maven Resolver
     private DIRegistry registry;
-    private ClassLoader classLoader;
-    private CamelContext camelContext;
-    private final Set<DownloadListener> downloadListeners = new LinkedHashSet<>();
-    private final Set<ArtifactDownloadListener> artifactDownloadListeners = new LinkedHashSet<>();
-    private KnownReposResolver knownReposResolver;
 
-    // repository URLs set from "camel.jbang.repos" property or --repos option.
+    // settings.xml and settings-security.xml locations to be passed to MavenDownloader from camel-tooling-maven
+    private String mavenSettings;
+    private String mavenSettingsSecurity;
+    // comma-separated list of additional repositories to use
     private String repos;
     private boolean fresh;
 
-    private String mavenSettings;
-    private String mavenSettingsSecurity;
-    private RepositorySystem repositorySystem;
-    private RepositorySystemSession repositorySystemSession;
-    // actual repositories to be used with maven-resolver
-    private final List<RemoteRepository> remoteRepositories = new ArrayList<>();
-    private RemoteRepository apacheSnapshots;
     private boolean apacheSnapshotsIncluded;
 
-    @Override
-    public CamelContext getCamelContext() {
-        return camelContext;
-    }
+    private AtomicInteger customRepositoryCounter = new AtomicInteger(1);
 
     @Override
-    public void setCamelContext(CamelContext camelContext) {
-        this.camelContext = camelContext;
-    }
-
-    public ClassLoader getClassLoader() {
-        return classLoader;
-    }
-
-    public void setClassLoader(ClassLoader classLoader) {
-        this.classLoader = classLoader;
-    }
-
-    public KnownReposResolver getKnownReposResolver() {
-        return knownReposResolver;
-    }
-
-    public void setKnownReposResolver(KnownReposResolver knownReposResolver) {
-        this.knownReposResolver = knownReposResolver;
-    }
+    protected void doBuild() {
+        // prepare all services that don't change when resolving Maven artifacts
 
-    @Override
-    public void addDownloadListener(DownloadListener downloadListener) {
-        CamelContextAware.trySetCamelContext(downloadListener, getCamelContext());
-        downloadListeners.add(downloadListener);
-    }
+        // Aether/maven-resolver configuration used without Shrinkwrap
+        // and without deprecated:
+        //  - org.eclipse.aether.impl.DefaultServiceLocator
+        //  - org.apache.maven.repository.internal.MavenRepositorySystemUtils.newServiceLocator()
 
-    @Override
-    public void addArtifactDownloadListener(ArtifactDownloadListener downloadListener) {
-        CamelContextAware.trySetCamelContext(downloadListener, getCamelContext());
-        artifactDownloadListeners.add(downloadListener);
-    }
+        registry = new DIRegistry();
+        final Properties systemProperties = new Properties();
+        // MNG-5670 guard against ConcurrentModificationException
+        // MNG-6053 guard against key without value
+        synchronized (System.getProperties()) {
+            systemProperties.putAll(System.getProperties());
+        }
 
-    @Override
-    public String getRepos() {
-        return repos;
-    }
+        // locations of settings.xml and settings-security.xml
+        validateMavenSettingsLocations();
 
-    @Override
-    public void setRepos(String repos) {
-        this.repos = repos;
-    }
+        repositorySystem = configureRepositorySystem(registry, systemProperties, mavenSettingsSecurity);
 
-    @Override
-    public boolean isFresh() {
-        return fresh;
-    }
+        // read the settings
+        Settings settings = mavenConfiguration(registry, repositorySystem, systemProperties, mavenSettings);
 
-    @Override
-    public void setFresh(boolean fresh) {
-        this.fresh = fresh;
-    }
+        // prepare the Maven session (local repository was configured within the settings)
+        // this object is thread safe - it uses configurable download pool
+        repositorySystemSession = configureRepositorySystemSession(registry, systemProperties,
+                settings, new File(settings.getLocalRepository()));
 
-    @Override
-    public String getMavenSettings() {
-        return mavenSettings;
-    }
+        // process repositories - both from settings.xml and from --repos option. All are subject to
+        // mirrorring and proxying (handled by org.eclipse.aether.RepositorySystem#newResolutionRepositories())
+        List<RemoteRepository> originalRepositories = configureDefaultRepositories(settings);
 
-    @Override
-    public void setMavenSettings(String mavenSettings) {
-        this.mavenSettings = mavenSettings;
-    }
+        remoteRepositories.addAll(repositorySystem.newResolutionRepositories(repositorySystemSession,
+                originalRepositories));
 
-    @Override
-    public String getMavenSettingsSecurity() {
-        return mavenSettingsSecurity;
-    }
+        // mirroring/proxying Maven Central
+        centralResolutionRepository = remoteRepositories.get(0);
 
-    @Override
-    public void setMavenSettingsSecurity(String mavenSettingsSecurity) {
-        this.mavenSettingsSecurity = mavenSettingsSecurity;
-    }
+        if (!apacheSnapshotsIncluded) {
+            // process apache snapshots even if it's not present in remoteRepositories, because it
+            // may be used on demand for each download/resolution request
+            apacheSnapshotsResolutionRepository = repositorySystem.newResolutionRepositories(repositorySystemSession,
+                    Collections.singletonList(apacheSnapshotsRepository)).get(0);
+        }
 
-    @Override
-    public void downloadDependency(String groupId, String artifactId, String version) {
-        downloadDependency(groupId, artifactId, version, true);
+        defaultPolicy = fresh ? POLICY_FRESH : POLICY_DEFAULT;
     }
 
     @Override
-    public void downloadDependency(String groupId, String artifactId, String version, String extraRepos) {
-        doDownloadDependency(groupId, artifactId, version, true, false, extraRepos);
+    protected void doInit() {
     }
 
     @Override
-    public void downloadHiddenDependency(String groupId, String artifactId, String version) {
-        doDownloadDependency(groupId, artifactId, version, true, true, null);
+    protected void doStop() throws Exception {
+        if (registry != null) {
+            registry.close();
+        }
     }
 
     @Override
-    public void downloadDependency(String groupId, String artifactId, String version, boolean transitively) {
-        doDownloadDependency(groupId, artifactId, version, transitively, false, null);
-    }
-
-    protected void doDownloadDependency(
-            String groupId, String artifactId, String version, boolean transitively,
-            boolean hidden, String extraRepos) {
-
-        if (!hidden) {
-            // trigger listener
-            for (DownloadListener listener : downloadListeners) {
-                listener.onDownloadDependency(groupId, artifactId, version);
-            }
+    public List<MavenArtifact> resolveArtifacts(
+            List<String> dependencyGAVs, Set<String> extraRepositories,
+            boolean transitively, boolean useApacheSnapshots)
+            throws MavenResolutionException {
+        ArtifactTypeRegistry artifactTypeRegistry = repositorySystemSession.getArtifactTypeRegistry();
+
+        final List<ArtifactRequest> requests = new ArrayList<>(dependencyGAVs.size());
+        CollectRequest collectRequest = new CollectRequest();
+        List<RemoteRepository> repositories = new ArrayList<>(remoteRepositories);
+        if (extraRepositories != null) {
+            // simply configure them in addition to the default repositories
+            List<RemoteRepository> extraRemoteRepositories = new ArrayList<>();
+            // read them
+            configureRepositories(extraRemoteRepositories, extraRepositories);
+            // proxy/mirror them
+            repositories.addAll(repositorySystem.newResolutionRepositories(repositorySystemSession,
+                    extraRemoteRepositories));
         }
-
-        // when running jbang directly then the CP has some existing camel components
-        // that essentially is not needed to be downloaded, but we need the listener to trigger
-        // to capture that the GAV is required for running the application
-        if (CP != null) {
-            // is it already on classpath
-            String target = artifactId;
-            if (version != null) {
-                target = target + "-" + version;
-            }
-            if (CP.contains(target)) {
-                // already on classpath
-                return;
-            }
+        if (useApacheSnapshots && !apacheSnapshotsIncluded) {
+            repositories.add(apacheSnapshotsResolutionRepository);
         }
 
-        // we need version to be able to download from maven
-        if (version == null) {
-            return;
+        collectRequest.setRepositories(repositories);
+
+        for (String depId : dependencyGAVs) {
+            ArtifactRequest ar = new ArtifactRequest();
+            ar.setRepositories(repositories);
+            MavenGav gav = MavenGav.parseGav(depId);
+            Artifact artifact = new DefaultArtifact(
+                    gav.getGroupId(), gav.getArtifactId(), gav.getClassifier(),
+                    gav.getPackaging(), gav.getVersion(), artifactTypeRegistry.get(gav.getPackaging()));
+            ar.setArtifact(artifact);
+            requests.add(ar);
+
+            Dependency dependency = new Dependency(ar.getArtifact(), "compile", false);
+            collectRequest.addDependency(dependency);
+            //collectRequest.addManagedDependency(...);
         }
 
-        String gav = groupId + ":" + artifactId + ":" + version;
-        threadPool.download(LOG, () -> {
-            LOG.debug("Downloading: {}", gav);
-            List<String> deps = List.of(gav);
-
-            List<RemoteRepository> repositories = new ArrayList<>(remoteRepositories);
-            // include Apache snapshot to make it easy to use upcoming releases
-            if (!apacheSnapshotsIncluded && "org.apache.camel".equals(groupId) && version.contains("SNAPSHOT")) {
-                repositories.add(apacheSnapshots);
+        if (transitively) {
+            DependencyRequest dependencyRequest = new DependencyRequest(collectRequest, new AcceptAllDependencyFilter());
+            try {
+                DependencyResult dependencyResult
+                        = repositorySystem.resolveDependencies(repositorySystemSession, dependencyRequest);
+
+                return dependencyResult.getArtifactResults().stream()
+                        .map(dr -> {
+                            Artifact a = dr.getArtifact();
+                            MavenGav gav = MavenGav.fromCoordinates(a.getGroupId(), a.getArtifactId(),
+                                    a.getVersion(), a.getExtension(), a.getClassifier());
+                            return new MavenArtifact(gav, a.getFile());
+                        })
+                        .collect(Collectors.toList());
+            } catch (DependencyResolutionException e) {
+                MavenResolutionException mre = new MavenResolutionException(e.getMessage(), e);
+                repositories.forEach(r -> mre.getRepositories().add(r.getUrl()));
+                throw mre;
             }
-            List<RemoteRepository> extaRepositories = new ArrayList<>();
-            // include extra repositories (if any)
-            extaRepositories.addAll(resolveExtraRepositories(extraRepos));
-            // and from known extra repositories (if any)
-            String known = knownReposResolver.getRepo(artifactId);
-            extaRepositories.addAll(resolveExtraRepositories(known));
-            repositories.addAll(extaRepositories);
-
-            List<MavenArtifact> artifacts = resolveDependenciesViaAether(deps, repositories, transitively);
-            List<File> files = new ArrayList<>();
-            LOG.debug("Resolved {} -> [{}]", gav, artifacts);
-
-            for (MavenArtifact a : artifacts) {
-                File file = a.getFile();
-                // only add to classpath if not already present (do not trigger listener)
-                if (!alreadyOnClasspath(a.getGav().getGroupId(), a.getGav().getArtifactId(),
-                        a.getGav().getVersion(), false)) {
-                    if (classLoader instanceof DependencyDownloaderClassLoader) {
-                        DependencyDownloaderClassLoader ddc = (DependencyDownloaderClassLoader) classLoader;
-                        ddc.addFile(file);
-                    }
-                    files.add(file);
-                    LOG.trace("Added classpath: {}", a.getGav());
-                }
-            }
-
-            // trigger listeners after downloaded and added to classloader
-            for (File file : files) {
-                for (ArtifactDownloadListener listener : artifactDownloadListeners) {
-                    listener.onDownloadedFile(file);
-                }
-            }
-            if (!artifacts.isEmpty()) {
-                for (DownloadListener listener : downloadListeners) {
-                    listener.onDownloadedDependency(groupId, artifactId, version);
-                }
-            }
-            if (!extaRepositories.isEmpty()) {
-                for (RemoteRepository repo : extaRepositories) {
-                    for (DownloadListener listener : downloadListeners) {
-                        listener.onExtraRepository(repo.getUrl());
-                    }
-                }
+        } else {
+            try {
+                List<ArtifactResult> artifactResults
+                        = repositorySystem.resolveArtifacts(repositorySystemSession, requests);
+
+                return artifactResults.stream()
+                        .map(dr -> {
+                            Artifact a = dr.getArtifact();
+                            MavenGav gav = MavenGav.fromCoordinates(a.getGroupId(), a.getArtifactId(),
+                                    a.getVersion(), a.getExtension(), a.getClassifier());
+                            return new MavenArtifact(gav, a.getFile());
+                        })
+                        .collect(Collectors.toList());
+            } catch (ArtifactResolutionException e) {
+                MavenResolutionException mre = new MavenResolutionException(e.getMessage(), e);
+                repositories.forEach(r -> mre.getRepositories().add(r.getUrl()));
+                throw mre;
             }
-
-        }, gav);
-    }
-
-    @Override
-    public MavenArtifact downloadArtifact(String groupId, String artifactId, String version) {
-        String gav = groupId + ":" + artifactId + ":" + version;
-        LOG.debug("DownloadingArtifact: {}", gav);
-        List<String> deps = List.of(gav);
-
-        List<RemoteRepository> repositories = new ArrayList<>(remoteRepositories);
-        // include Apache snapshot to make it easy to use upcoming releases
-        if (!apacheSnapshotsIncluded && "org.apache.camel".equals(groupId) && version.contains("SNAPSHOT")) {
-            repositories.add(apacheSnapshots);
         }
-
-        List<MavenArtifact> artifacts = resolveDependenciesViaAether(deps, repositories, false);
-        LOG.debug("Resolved {} -> [{}]", gav, artifacts);
-
-        if (artifacts.size() == 1) {
-            return artifacts.get(0);
-        }
-
-        return null;
     }
 
     @Override
-    public List<String[]> resolveAvailableVersions(String groupId, String artifactId, String minimumVersion, String repo) {
-        String gav = groupId + ":" + artifactId;
-        LOG.debug("DownloadAvailableVersions: {}", gav);
-
-        // repo 0 is maven central
-        RemoteRepository repository = remoteRepositories.get(0);
-        if (repo != null) {
-            List<RemoteRepository> extra = resolveExtraRepositories(repo);
-            if (!extra.isEmpty()) {
-                repository = extra.get(0);
-            }
-        }
-        List<String[]> versions = resolveAvailableVersions(groupId, artifactId, minimumVersion, repository);
-        return versions;
-    }
-
-    public boolean alreadyOnClasspath(String groupId, String artifactId, String version) {
-        return alreadyOnClasspath(groupId, artifactId, version, true);
-    }
+    public List<MavenGav> resolveAvailableVersions(String groupId, String artifactId, String repository)
+            throws MavenResolutionException {
+        MetadataRequest req = new MetadataRequest();
+        List<MavenGav> gavs = new ArrayList<>();
 
-    private boolean alreadyOnClasspath(String groupId, String artifactId, String version, boolean listener) {
-        // if no artifact then regard this as okay
-        if (artifactId == null) {
-            return true;
-        }
+        try {
+            if (repository == null) {
+                req.setRepository(centralResolutionRepository);
+            } else {
+                String id = "custom" + customRepositoryCounter.getAndIncrement();
+                RemoteRepository custom = new RemoteRepository.Builder(id, "default", repository)
+                        .setReleasePolicy(defaultPolicy)
+                        .setSnapshotPolicy(defaultPolicy)
+                        .build();
 
-        String target = artifactId;
-        if (version != null) {
-            target = target + "-" + version;
-        }
+                // simply configure them in addition to the default repositories
+                List<RemoteRepository> customResolutionRepository = repositorySystem.newResolutionRepositories(repositorySystemSession,
+                        Collections.singletonList(custom));
 
-        if (bootClasspath != null) {
-            for (String s : bootClasspath) {
-                if (s.contains(target)) {
-                    if (listener) {
-                        for (DownloadListener dl : downloadListeners) {
-                            dl.onDownloadDependency(groupId, artifactId, version);
-                        }
-                    }
-                    // already on classpath
-                    return true;
-                }
+                req.setRepository(customResolutionRepository.get(0));
             }
-        }
 
-        if (classLoader instanceof URLClassLoader) {
-            // create path like target to match against the file url
-            String urlTarget = groupId + "/" + artifactId;
-            urlTarget = urlTarget.replace('.', '/');
-            urlTarget += "/" + version + "/" + target + ".jar";
-            urlTarget = FileUtil.normalizePath(urlTarget); // windows vs linux
-            URLClassLoader ucl = (URLClassLoader) classLoader;
-            for (URL u : ucl.getURLs()) {
-                String s = u.toString();
-                s = FileUtil.normalizePath(s);
-                if (s.contains(urlTarget)) {
-                    // trigger listener
-                    if (listener) {
-                        for (DownloadListener dl : downloadListeners) {
-                            dl.onDownloadDependency(groupId, artifactId, version);
-                        }
-                    }
-                    // already on classpath
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
+            req.setFavorLocalRepository(false);
+            req.setMetadata(new DefaultMetadata(groupId, artifactId, "maven-metadata.xml", Metadata.Nature.RELEASE));
 
-    @Override
-    public void onLoadingKamelet(String name) {
-        // trigger listener
-        for (DownloadListener listener : downloadListeners) {
-            listener.onLoadingKamelet(name);
-        }
-    }
-
-    @Override
-    public void onLoadingModeline(String key, String value) {
-        // trigger listener
-        for (DownloadListener listener : downloadListeners) {
-            listener.onLoadingModeline(key, value);
-        }
-    }
-
-    private List<RemoteRepository> resolveExtraRepositories(String extraRepos) {
-        List<RemoteRepository> repositories = new ArrayList<>();
-        if (extraRepos != null) {
-            Set<String> repositoryURLs = new HashSet<>();
-            for (String repo : extraRepos.split(",")) {
-                try {
-                    URL url = new URL(repo);
-                    if (url.getHost().equals("repo1.maven.org")) {
-                        continue;
-                    }
-                    String id = "custom" + customCount++;
-                    RepositoryPolicy releasePolicy = fresh ? POLICY_FRESH : POLICY_DEFAULT;
-                    if (repositoryURLs.add(url.toExternalForm())) {
-                        if (url.getHost().equals("repository.apache.org") && url.getPath().contains("/snapshots")) {
-                            apacheSnapshotsIncluded = true;
-                            repositories.add(apacheSnapshots);
-                        } else {
-                            // both snapshots and releases allowed for custom repos
-                            repositories.add(new RemoteRepository.Builder(id, "default", repo)
-                                    .setReleasePolicy(releasePolicy)
-                                    .setSnapshotPolicy(fresh ? POLICY_FRESH : POLICY_DEFAULT)
-                                    .build());
+            List<MetadataResult> result = repositorySystem.resolveMetadata(repositorySystemSession, List.of(req));
+            for (MetadataResult mr : result) {
+                if (mr.isResolved() && mr.getMetadata().getFile() != null) {
+                    File f = mr.getMetadata().getFile();
+                    if (f.exists() && f.isFile()) {
+                        MetadataXpp3Reader reader = new MetadataXpp3Reader();
+                        try (BufferedInputStream is = new BufferedInputStream(new FileInputStream(f))) {
+                            org.apache.maven.artifact.repository.metadata.Metadata md = reader.read(is);
+                            List<String> versions = md.getVersioning().getVersions();
+                            if (versions != null) {
+                                for (String v : versions) {
+                                    if (v != null) {
+                                        gavs.add(MavenGav.fromCoordinates(groupId, artifactId, v, null, null));
+                                    }
+                                }
+                            }
                         }
                     }
-                } catch (MalformedURLException e) {
-                    LOG.warn("Can't use {} URL: {}. Skipping.", repo, e.getMessage(), e);
                 }
             }
+            return gavs;
+        } catch (Exception e) {
+            String msg = "Cannot resolve available versions in " + req.getRepository().getUrl();
+            MavenResolutionException mre = new MavenResolutionException(msg, e);
+            mre.getRepositories().add(req.getRepository().getUrl());
+            throw mre;
         }
-        return repositories;
     }
 
     @Override
-    protected void doBuild() {
-        if (classLoader == null && camelContext != null) {
-            classLoader = camelContext.getApplicationContextClassLoader();
-        }
-        threadPool = new DownloadThreadPool();
-        threadPool.setCamelContext(camelContext);
-        ServiceHelper.buildService(threadPool);
-
-        // Aether/maven-resolver configuration used without Shrinkwrap
-        // and without deprecated:
-        //  - org.eclipse.aether.impl.DefaultServiceLocator
-        //  - org.apache.maven.repository.internal.MavenRepositorySystemUtils.newServiceLocator()
-
-        registry = new DIRegistry();
-        final Properties systemProperties = new Properties();
-        // MNG-5670 guard against ConcurrentModificationException
-        // MNG-6053 guard against key without value
-        synchronized (System.getProperties()) {
-            systemProperties.putAll(System.getProperties());
-        }
+    public MavenDownloader customize(String localRepository, int connectTimeout, int requestTimeout) {
+        MavenDownloaderImpl copy = new MavenDownloaderImpl();
+        copy.repositorySystem = repositorySystem;
+        copy.remoteRepositories.addAll(remoteRepositories);
+        copy.apacheSnapshotsRepository = apacheSnapshotsRepository;
+        copy.apacheSnapshotsResolutionRepository = apacheSnapshotsResolutionRepository;
+        copy.defaultPolicy = defaultPolicy;
+        copy.registry = registry;
+        copy.mavenSettings = mavenSettings;
+        copy.mavenSettingsSecurity = mavenSettingsSecurity;
+        copy.repos = repos;
+        copy.fresh = fresh;
+        copy.apacheSnapshotsIncluded = apacheSnapshotsIncluded;
+        copy.customRepositoryCounter = customRepositoryCounter;
 
-        // locations of settings.xml and settings-security.xml
-        validateMavenSettingsLocations();
-
-        repositorySystem = configureRepositorySystem(registry, systemProperties,
-                mavenSettingsSecurity);
-
-        // read the settings
-        Settings settings = mavenConfiguration(registry, repositorySystem, systemProperties, mavenSettings);
-
-        // prepare the Maven session (local repository was configured within the settings)
-        // this object is thread safe - it uses configurable download pool, but we're doing our own pooling too
-        repositorySystemSession = configureRepositorySystemSession(registry, systemProperties,
-                settings, new File(settings.getLocalRepository()));
-
-        // process repositories - both from settings.xml and from --repos option. All are subject to
-        // mirrorring and proxying
-        List<RemoteRepository> originalRepositories = configureRemoteRepositories(settings, repos, fresh);
-        remoteRepositories.addAll(repositorySystem.newResolutionRepositories(repositorySystemSession,
-                originalRepositories));
-
-        // finally process apache snapshots
-        apacheSnapshots = repositorySystem.newResolutionRepositories(repositorySystemSession,
-                Collections.singletonList(apacheSnapshots)).get(0);
-    }
+        LocalRepositoryManagerFactory lrmFactory = registry.lookupByClass(LocalRepositoryManagerFactory.class);
 
-    @Override
-    protected void doInit() {
-        RuntimeMXBean mb = ManagementFactory.getRuntimeMXBean();
-        if (mb != null) {
-            bootClasspath = mb.getClassPath().split("[:|;]");
+        // session can't be shared
+        DefaultRepositorySystemSession rssCopy = new DefaultRepositorySystemSession(repositorySystemSession);
+        rssCopy.setConfigProperty(ConfigurationProperties.CONNECT_TIMEOUT, connectTimeout);
+        rssCopy.setConfigProperty(ConfigurationProperties.REQUEST_TIMEOUT, requestTimeout);
+        try {
+            rssCopy.setLocalRepositoryManager(lrmFactory.newInstance(rssCopy,
+                    new LocalRepository(localRepository)));
+        } catch (NoLocalRepositoryManagerException e) {
+            LOG.warn(e.getMessage(), e);
         }
-        ServiceHelper.initService(threadPool);
-    }
+        copy.repositorySystemSession = rssCopy;
 
-    @Override
-    protected void doStop() throws Exception {
-        ServiceHelper.stopAndShutdownService(threadPool);
-        if (registry != null) {
-            registry.close();
-        }
+        return copy;
     }
 
     private void validateMavenSettingsLocations() {
@@ -680,7 +515,7 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
             if (mavenSettingsSecurity == null) {
                 // implicit security settings
                 String m2settingsSecurity = System.getProperty("user.home") + File.separator + ".m2"
-                        + File.separator + "settings-security.xml";
+                                            + File.separator + "settings-security.xml";
                 if (new File(m2settingsSecurity).isFile()) {
                     mavenSettingsSecurity = m2settingsSecurity;
                 }
@@ -697,7 +532,7 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
     /**
      * Configure entire {@link RepositorySystem} service
      */
-    public RepositorySystem configureRepositorySystem(
+    RepositorySystem configureRepositorySystem(
             DIRegistry registry,
             Properties systemProperties, String settingsSecurityLocation) {
         basicRepositorySystemConfiguration(registry, systemProperties);
@@ -854,7 +689,7 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
         // we could use org.apache.maven.settings.building.DefaultSettingsBuilder directly, but it's better
         // to be consistent and use DI for that - especially because after
         // https://issues.apache.org/jira/browse/MNG-6680, DefaultSettingsBuilder is no longer annotated
-        // with @org.codehaus.plexus.component.annotations.Component, but with @jakarta.inject.Named
+        // with @org.codehaus.plexus.component.annotations.Component, but with @javax.inject.Named
         registry.bind(SettingsReader.class, DefaultSettingsReader.class);
         registry.bind(SettingsWriter.class, DefaultSettingsWriter.class);
         registry.bind(SettingsValidator.class, DefaultSettingsValidator.class);
@@ -864,7 +699,7 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
     /**
      * Using the configured {@link DIRegistry}, load {@link Settings Maven settings}
      */
-    public Settings mavenConfiguration(
+    Settings mavenConfiguration(
             DIRegistry registry, RepositorySystem repositorySystem,
             Properties systemProperties, String mavenSettings) {
         // settings are important to configure the session later
@@ -932,7 +767,7 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
      * Using the configured {@link DIRegistry}, obtain thread-safe {@link RepositorySystemSession} used to resolve and
      * download Maven dependencies.
      */
-    public RepositorySystemSession configureRepositorySystemSession(
+    RepositorySystemSession configureRepositorySystemSession(
             DIRegistry registry,
             Properties systemProperties, Settings settings, File localRepository) {
         DefaultRepositorySystemSession session = new DefaultRepositorySystemSession();
@@ -1224,79 +1059,87 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
     }
 
     /**
+     * <p>
      * Using the passed ({@code --repos} parameter or {@code camel.jbang.repos} option) and configured (in Maven
-     * settings) repomote repository location, prepare a list of {@link RemoteRepository remote repositories} to be used
-     * during Maven resolution. These repositories are <b>not yet</b> mirrored/proxied. Use
+     * settings) repository locations, prepare a list of {@link RemoteRepository remote repositories} to be used during
+     * Maven resolution. These repositories are <b>not yet</b> mirrored/proxied. Use
      * {@link RepositorySystem#newResolutionRepositories} first.
+     * </p>
+     *
+     * <p>
+     * This method is used during initialization of this {@link MavenDownloader}, but when invoking actual
+     * download/resolve methods, we can use additional repositories.
+     * </p>
      *
      * @param settings maven settings
-     * @param repos    optional, comma-separated list of URLs
-     * @param fresh    whether to check for remote updates of the artifacts (SNAPSHOTs)
      */
-    public List<RemoteRepository> configureRemoteRepositories(Settings settings, String repos, boolean fresh) {
+    List<RemoteRepository> configureDefaultRepositories(Settings settings) {
         List<RemoteRepository> repositories = new ArrayList<>();
 
         // a set to prevent duplicates, but do not store URLs directly (hashCode() may lead to DNS resolution!)
         Set<String> repositoryURLs = new HashSet<>();
 
         // add maven central first - always
-        repositories.add(new RemoteRepository.Builder("central", "default", MAVEN_CENTRAL_REPO)
-                .setReleasePolicy(fresh ? POLICY_FRESH : POLICY_DEFAULT)
+        centralRepository = new RemoteRepository.Builder("central", "default", MAVEN_CENTRAL_REPO)
+                .setReleasePolicy(defaultPolicy)
                 .setSnapshotPolicy(POLICY_DISABLED)
-                .build());
+                .build();
+        repositories.add(centralRepository);
 
         // configure Apache snapshots - to be used if needed
-        apacheSnapshots = new RemoteRepository.Builder("apache-snapshot", "default", APACHE_SNAPSHOT_REPO)
+        apacheSnapshotsRepository = new RemoteRepository.Builder("apache-snapshot", "default", APACHE_SNAPSHOT_REPO)
                 .setReleasePolicy(POLICY_DISABLED)
-                .setSnapshotPolicy(fresh ? POLICY_FRESH : POLICY_DEFAULT)
+                .setSnapshotPolicy(defaultPolicy)
                 .build();
 
         // and custom repos and remember URLs to not duplicate the repositories from the settings
         if (repos != null) {
-            for (String repo : repos.split(",")) {
-                try {
-                    URL url = new URL(repo);
-                    if (url.getHost().equals("repo1.maven.org")) {
-                        continue;
+            List<RemoteRepository> repositoriesFromConfiguration = new ArrayList<>();
+            Set<String> urls = Arrays.stream(repos.split("\\s*,\\s*")).collect(Collectors.toSet());
+            configureRepositories(repositoriesFromConfiguration, urls);
+            for (RemoteRepository repo : repositoriesFromConfiguration) {
+                if (repositoryURLs.add(repo.getUrl())) {
+                    if (repo == apacheSnapshotsRepository) {
+                        // record that Apache Snapshots repository is included in default (always used) repositories
+                        apacheSnapshotsIncluded = true;
                     }
-                    String id = "custom" + customCount++;
-                    RepositoryPolicy releasePolicy = fresh ? POLICY_FRESH : POLICY_DEFAULT;
-                    if (repositoryURLs.add(url.toExternalForm())) {
-                        if (url.getHost().equals("repository.apache.org") && url.getPath().contains("/snapshots")) {
-                            apacheSnapshotsIncluded = true;
-                            repositories.add(apacheSnapshots);
-                        } else {
-                            // both snapshots and releases allowed for custom repos
-                            repositories.add(new RemoteRepository.Builder(id, "default", repo)
-                                    .setReleasePolicy(releasePolicy)
-                                    .setSnapshotPolicy(fresh ? POLICY_FRESH : POLICY_DEFAULT)
-                                    .build());
-                        }
-                    }
-                } catch (MalformedURLException e) {
-                    LOG.warn("Can't use {} URL: {}. Skipping.", repo, e.getMessage(), e);
+                    repositories.add(repo);
                 }
             }
         }
 
-        // then process the repositories from active profiles of external Maven settings
+        // then process the repositories from active profiles from external Maven settings
         for (String profile : settings.getActiveProfiles()) {
             for (Repository r : settings.getProfilesAsMap().get(profile).getRepositories()) {
                 try {
                     URL url = new URL(r.getUrl());
-                    if (repositoryURLs.add(url.toExternalForm())) {
+                    if (repositoryURLs.add(r.getUrl())) {
                         if (url.getHost().equals("repository.apache.org") && url.getPath().startsWith("/snapshots")) {
+                            // record that Apache Snapshots repository is included in default (always used)
+                            // repositories and used preconfigured instance of o.e.aether.repository.RemoteRepository
                             apacheSnapshotsIncluded = true;
+                            repositories.add(apacheSnapshotsRepository);
+                        } else {
+                            RemoteRepository.Builder rb = new RemoteRepository.Builder(r.getId(), r.getLayout(), r.getUrl());
+                            if (r.getReleases() == null) {
+                                // default (enabled) policy for releases
+                                rb.setPolicy(defaultPolicy);
+                            } else {
+                                rb.setPolicy(new RepositoryPolicy(
+                                        r.getReleases().isEnabled(),
+                                        r.getReleases().getUpdatePolicy(), r.getReleases().getChecksumPolicy()));
+                            }
+                            // if someone defines Apache snapshots repository, (s)he has to specify proper policy, sorry.
+                            if (r.getSnapshots() == null) {
+                                // default (disabled) policy for releases
+                                rb.setSnapshotPolicy(POLICY_DISABLED);
+                            } else {
+                                rb.setSnapshotPolicy(new RepositoryPolicy(
+                                        r.getSnapshots().isEnabled(),
+                                        r.getSnapshots().getUpdatePolicy(), r.getSnapshots().getChecksumPolicy()));
+                            }
+                            repositories.add(rb.build());
                         }
-                        RemoteRepository.Builder rb = new RemoteRepository.Builder(r.getId(), r.getLayout(), r.getUrl());
-                        if (r.getReleases() == null) {
-                            rb.setPolicy(fresh ? POLICY_FRESH : POLICY_DEFAULT);
-                        }
-                        // if someone defines Apache snapshots repository, (s)he has to specify proper policy, sorry.
-                        if (r.getSnapshots() == null) {
-                            rb.setSnapshotPolicy(POLICY_DISABLED);
-                        }
-                        repositories.add(rb.build());
                     }
                 } catch (MalformedURLException e) {
                     LOG.warn("Can't use {} URL from Maven settings: {}. Skipping.", r.getUrl(), e.getMessage(), e);
@@ -1307,178 +1150,78 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
         return repositories;
     }
 
-    public List<MavenArtifact> resolveDependenciesViaAether(List<String> depIds, boolean transitively) {
-        return resolveDependenciesViaAether(depIds, remoteRepositories, transitively);
-    }
-
-    public List<MavenArtifact> resolveDependenciesViaAether(
-            List<String> depIds,
-            List<RemoteRepository> repositories, boolean transitively) {
-
-        try {
-            ArtifactTypeRegistry artifactTypeRegistry = repositorySystemSession.getArtifactTypeRegistry();
-
-            final List<ArtifactRequest> requests = new ArrayList<>(depIds.size());
-            CollectRequest collectRequest = new CollectRequest();
-            collectRequest.setRepositories(repositories);
-
-            for (String depId : depIds) {
-                ArtifactRequest ar = new ArtifactRequest();
-                ar.setRepositories(repositories);
-                ar.setArtifact(MavenGav.parseGav(depId, artifactTypeRegistry).getArtifact());
-                requests.add(ar);
-
-                Dependency dependency = new Dependency(ar.getArtifact(), "compile", false);
-                collectRequest.addDependency(dependency);
-                //                collectRequest.addManagedDependency(...);
-            }
-
-            DependencyFilter filter = transitively
-                    ? new AcceptAllDependencyFilter()
-                    : new AcceptDirectDependencyFilter(requests);
-
-            DependencyRequest dependencyRequest = new DependencyRequest(collectRequest, filter);
-            DependencyResult dependencyResult
-                    = repositorySystem.resolveDependencies(repositorySystemSession, dependencyRequest);
-
-            return dependencyResult.getArtifactResults().stream()
-                    .map(dr -> {
-                        String gav = dr.getArtifact().getGroupId() + ":"
-                                     + dr.getArtifact().getArtifactId() + ":"
-                                     + (!"jar".equals(dr.getArtifact().getExtension())
-                                             ? dr.getArtifact().getExtension() + ":" : "")
-                                     + (!"".equals(dr.getArtifact().getClassifier())
-                                             ? dr.getArtifact().getClassifier() + ":" : "")
-                                     + dr.getArtifact().getVersion();
-                        return new MavenArtifact(MavenGav.parseGav(gav, artifactTypeRegistry), dr.getArtifact().getFile());
-                    })
-                    .collect(Collectors.toList());
-        } catch (DependencyResolutionException e) {
-            String repos = repositories == null
-                    ? "(empty URL list)"
-                    : repositories.stream().map(RemoteRepository::getUrl).collect(Collectors.joining(", "));
-            String msg = "Cannot resolve dependencies in " + repos;
-            throw new DownloadException(msg, e);
-        } catch (RuntimeException e) {
-            throw new DownloadException("Unknown error occurred while trying to resolve dependencies", e);
-        }
-    }
-
-    public List<String[]> resolveAvailableVersions(
-            String groupId, String artifactId, String minimumVersion, RemoteRepository repository) {
-
-        List<String[]> answer = new ArrayList<>();
-
-        try {
-            MetadataRequest ar = new MetadataRequest();
-            ar.setRepository(repository);
-            ar.setFavorLocalRepository(false);
-            ar.setMetadata(new DefaultMetadata(groupId, artifactId, "maven-metadata.xml", Metadata.Nature.RELEASE));
-
-            List<MetadataResult> result = repositorySystem.resolveMetadata(repositorySystemSession, List.of(ar));
-            for (MetadataResult mr : result) {
-                if (mr.isResolved() && mr.getMetadata().getFile() != null) {
-                    File f = mr.getMetadata().getFile();
-                    if (f.exists() && f.isFile()) {
-                        DocumentBuilderFactory dbf = XmlHelper.createDocumentBuilderFactory();
-                        DocumentBuilder db = dbf.newDocumentBuilder();
-                        Document dom = db.parse(f);
-                        NodeList nl = dom.getElementsByTagName("version");
-                        for (int i = 0; i < nl.getLength(); i++) {
-                            Element node = (Element) nl.item(i);
-                            String v = node.getTextContent();
-                            if (v != null) {
-                                if ("camel-spring-boot".equals(artifactId)) {
-                                    String sbv = null;
-                                    if (VersionHelper.isGE(v, minimumVersion)) {
-                                        sbv = resolveSpringBootVersionByCamelVersion(v, repository);
-                                    }
-                                    answer.add(new String[] { v, sbv });
-                                } else if ("camel-quarkus-catalog".equals(artifactId)) {
-                                    if (VersionHelper.isGE(v, MINIMUM_QUARKUS_VERSION)) {
-                                        String cv = resolveCamelVersionByQuarkusVersion(v, repository);
-                                        if (cv != null && VersionHelper.isGE(cv, minimumVersion)) {
-                                            answer.add(new String[] { cv, v });
-                                        }
-                                    }
-                                } else {
-                                    answer.add(new String[] { v, null });
-                                }
-                            }
-                        }
-                    }
+    /**
+     * Helper method to translate a collection of Strings for remote repository URLs into actual instances of
+     * {@link RemoteRepository} added to the passed {@code repositories}. We don't detected duplicates here and we don't
+     * do mirror/proxy processing of the repositories.
+     *
+     * @param repositories
+     * @param urls
+     */
+    private void configureRepositories(List<RemoteRepository> repositories, Set<String> urls) {
+        urls.forEach(repo -> {
+            try {
+                URL url = new URL(repo);
+                if (url.getHost().equals("repo1.maven.org")) {
+                    // Maven Central is always used, so skip it
+                    return;
+                }
+                if (url.getHost().equals("repository.apache.org") && url.getPath().contains("/snapshots")) {
+                    // Apache Snapshots added, so we'll use our own definition of this repository
+                    repositories.add(apacheSnapshotsRepository);
+                } else {
+                    // both snapshots and releases allowed for custom repos
+                    String id = "custom" + customRepositoryCounter.getAndIncrement();
+                    repositories.add(new RemoteRepository.Builder(id, "default", repo)
+                            .setReleasePolicy(defaultPolicy)
+                            .setSnapshotPolicy(defaultPolicy)
+                            .build());
                 }
+            } catch (MalformedURLException e) {
+                LOG.warn("Can't use {} URL: {}. Skipping.", repo, e.getMessage(), e);
             }
-        } catch (Exception e) {
-            String msg = "Cannot resolve available versions in " + repository.getUrl();
-            throw new DownloadException(msg, e);
-        }
-
-        return answer;
+        });
     }
 
-    private String resolveCamelVersionByQuarkusVersion(String quarkusVersion, RemoteRepository repository) throws Exception {
-        String gav = "org.apache.camel.quarkus" + ":" + "camel-quarkus" + ":pom:" + quarkusVersion;
-        // always include maven central
-        List<RemoteRepository> repos;
-        if (repository == remoteRepositories.get(0)) {
-            repos = List.of(repository);
-        } else {
-            repos = List.of(remoteRepositories.get(0), repository);
-        }
-        List<MavenArtifact> artifacts = resolveDependenciesViaAether(List.of(gav), repos, false);
-        if (!artifacts.isEmpty()) {
-            MavenArtifact ma = artifacts.get(0);
-            if (ma != null && ma.getFile() != null) {
-                String name = ma.getFile().getAbsolutePath();
-                File file = new File(name);
-                if (file.exists()) {
-                    DocumentBuilderFactory dbf = XmlHelper.createDocumentBuilderFactory();
-                    DocumentBuilder db = dbf.newDocumentBuilder();
-                    Document dom = db.parse(file);
-                    // the camel version is in <parent>
-                    NodeList nl = dom.getElementsByTagName("parent");
-                    if (nl.getLength() == 1) {
-                        Element node = (Element) nl.item(0);
-                        return node.getElementsByTagName("version").item(0).getTextContent();
-                    }
-                }
-            }
-        }
+    /**
+     * Configure a location of {@code settings.xml} (when not set, defaults to {@code ~/.m2/settings.xml} unless it's
+     * explicitly set to {@code "false"}.
+     * 
+     * @param mavenSettings
+     */
+    public void setMavenSettingsLocation(String mavenSettings) {
+        this.mavenSettings = mavenSettings;
+    }
 
-        return null;
+    /**
+     * Configure a location of {@code settings-security.xml} (when not set, defaults to
+     * {@code ~/.m2/settings-security.xml} unless {@link #setMavenSettingsLocation(String)} is set explicitly set to
+     * {@code "false"}.
+     * 
+     * @param mavenSettingsSecurity
+     */
+    public void setMavenSettingsSecurityLocation(String mavenSettingsSecurity) {
+        this.mavenSettingsSecurity = mavenSettingsSecurity;
     }
 
-    private String resolveSpringBootVersionByCamelVersion(String camelVersion, RemoteRepository repository) throws Exception {
-        String gav = "org.apache.camel.springboot" + ":" + "spring-boot" + ":pom:" + camelVersion;
-        // always include maven central
-        List<RemoteRepository> repos;
-        if (repository == remoteRepositories.get(0)) {
-            repos = List.of(repository);
-        } else {
-            repos = List.of(remoteRepositories.get(0), repository);
-        }
-        List<MavenArtifact> artifacts = resolveDependenciesViaAether(List.of(gav), repos, false);
-        if (!artifacts.isEmpty()) {
-            MavenArtifact ma = artifacts.get(0);
-            if (ma != null && ma.getFile() != null) {
-                String name = ma.getFile().getAbsolutePath();
-                File file = new File(name);
-                if (file.exists()) {
-                    DocumentBuilderFactory dbf = XmlHelper.createDocumentBuilderFactory();
-                    DocumentBuilder db = dbf.newDocumentBuilder();
-                    Document dom = db.parse(file);
-                    // the camel version is in <properties>
-                    NodeList nl = dom.getElementsByTagName("properties");
-                    if (nl.getLength() > 0) {
-                        Element node = (Element) nl.item(0);
-                        return node.getElementsByTagName("spring-boot-version").item(0).getTextContent();
-                    }
-                }
-            }
-        }
+    /**
+     * Configure comma-separated list of repositories to use (in addition to the ones discovered from Maven settings).
+     * 
+     * @param repos
+     */
+    public void setRepos(String repos) {
+        this.repos = repos;
+    }
 
-        return null;
+    /**
+     * Set a flag determining Maven update behavior. See the description of {@code -U,--update-snapshots} Maven option.
+     * When set to {@code true}, Maven metadata (to determine newest SNAPSHOT or RELEASE or LATEST version) is always
+     * fetched.
+     * 
+     * @param fresh
+     */
+    public void setFresh(boolean fresh) {
+        this.fresh = fresh;
     }
 
     private static class AcceptAllDependencyFilter implements DependencyFilter {
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenGav.java b/tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/MavenGav.java
similarity index 80%
rename from dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenGav.java
rename to tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/MavenGav.java
index 91c06ab8ea6..a42287d1051 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenGav.java
+++ b/tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/MavenGav.java
@@ -14,19 +14,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.main.download;
-
-import org.eclipse.aether.artifact.Artifact;
-import org.eclipse.aether.artifact.ArtifactTypeRegistry;
-import org.eclipse.aether.artifact.DefaultArtifact;
+package org.apache.camel.tooling.maven;
 
 /**
- * Maven GAV model
+ * Maven GAV model with parsing support and speacial rules for some names:
+ * <ul>
+ * <li>{@code camel:core -> org.apache.camel:camel-core}</li>
+ * <li>{@code camel-xxx -> org.apache.camel:camel-xxx}</li>
+ * <li>{@code camel-quarkus-xxx -> camel-xxx}</li>
+ * </ul>
  */
 public final class MavenGav {
 
-    private Artifact artifact;
-
     private String groupId;
     private String artifactId;
     private String version;
@@ -37,18 +36,26 @@ public final class MavenGav {
     }
 
     public static MavenGav parseGav(String gav) {
-        return parseGav(gav, null, null);
-    }
-
-    public static MavenGav parseGav(String gav, String defaultVersion) {
-        return parseGav(gav, defaultVersion, null);
+        return parseGav(gav, null);
     }
 
-    public static MavenGav parseGav(String gav, ArtifactTypeRegistry artifactTypeRegistry) {
-        return parseGav(gav, null, artifactTypeRegistry);
+    public static MavenGav fromCoordinates(
+            String groupId, String artifactId, String version, String packaging,
+            String classifier) {
+        MavenGav answer = new MavenGav();
+        answer.groupId = groupId;
+        answer.artifactId = artifactId;
+        answer.version = version;
+        if (classifier != null && !"".equals(classifier)) {
+            answer.classifier = classifier;
+        }
+        if (packaging != null && !"".equals(packaging)) {
+            answer.packaging = packaging;
+        }
+        return answer;
     }
 
-    public static MavenGav parseGav(String gav, String defaultVersion, ArtifactTypeRegistry artifactTypeRegistry) {
+    public static MavenGav parseGav(String gav, String defaultVersion) {
         MavenGav answer = new MavenGav();
         // camel-k style GAV
         if (gav.startsWith("camel:")) {
@@ -91,6 +98,7 @@ public final class MavenGav {
                 answer.setVersion(defaultVersion);
             }
         } else {
+            // for those used to OSGi's pax-url-aether syntax
             String[] parts = gav.startsWith("mvn:") ? gav.substring(4).split(":") : gav.split(":");
             if (parts.length > 0) {
                 answer.setGroupId(parts[0]);
@@ -114,15 +122,6 @@ public final class MavenGav {
                 }
             }
         }
-        if (artifactTypeRegistry == null) {
-            answer.setArtifact(new DefaultArtifact(
-                    answer.groupId, answer.artifactId, answer.classifier,
-                    answer.packaging, answer.version));
-        } else {
-            answer.setArtifact(new DefaultArtifact(
-                    answer.groupId, answer.artifactId, answer.classifier,
-                    answer.packaging, answer.version, artifactTypeRegistry.get(answer.packaging)));
-        }
 
         return answer;
     }
@@ -167,14 +166,6 @@ public final class MavenGav {
         this.classifier = classifier;
     }
 
-    public Artifact getArtifact() {
-        return artifact;
-    }
-
-    public void setArtifact(Artifact artifact) {
-        this.artifact = artifact;
-    }
-
     @Override
     public String toString() {
         if (version != null) {
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenArtifact.java b/tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/MavenResolutionException.java
similarity index 61%
copy from dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenArtifact.java
copy to tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/MavenResolutionException.java
index d9ca9c07ecd..58315ea9fa0 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenArtifact.java
+++ b/tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/MavenResolutionException.java
@@ -14,30 +14,28 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.main.download;
+package org.apache.camel.tooling.maven;
 
-import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
 
-public class MavenArtifact {
+public class MavenResolutionException extends Exception {
 
-    private final MavenGav gav;
-    private final File file;
+    private final List<String> repositoriesUsed = new ArrayList<>();
 
-    public MavenArtifact(MavenGav gav, File file) {
-        this.gav = gav;
-        this.file = file;
+    public MavenResolutionException() {
     }
 
-    public MavenGav getGav() {
-        return gav;
+    public MavenResolutionException(String message) {
+        super(message);
     }
 
-    public File getFile() {
-        return file;
+    public MavenResolutionException(String message, Throwable cause) {
+        super(message, cause);
     }
 
-    @Override
-    public String toString() {
-        return gav.toString();
+    public List<String> getRepositories() {
+        return repositoriesUsed;
     }
+
 }
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenArtifact.java b/tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/package-info.java
similarity index 63%
copy from dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenArtifact.java
copy to tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/package-info.java
index d9ca9c07ecd..0b03141b7de 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenArtifact.java
+++ b/tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/package-info.java
@@ -14,30 +14,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.main.download;
 
-import java.io.File;
-
-public class MavenArtifact {
-
-    private final MavenGav gav;
-    private final File file;
-
-    public MavenArtifact(MavenGav gav, File file) {
-        this.gav = gav;
-        this.file = file;
-    }
-
-    public MavenGav getGav() {
-        return gav;
-    }
-
-    public File getFile() {
-        return file;
-    }
-
-    @Override
-    public String toString() {
-        return gav.toString();
-    }
-}
+/**
+ * <p>
+ * Package with interfaces/classes to be used when proper/canonical Maven resolution is required. Currently it's:
+ * <ul>
+ * <li>catalog/camel-catalog-maven (previously using Ivy/Grape)</li>
+ * <li>dsl/camel-kamelet-main (previously using Shrinkwrap)</li>
+ * </ul>
+ * </p>
+ */
+package org.apache.camel.tooling.maven;
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/injection/DIRegistry.java b/tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/support/DIRegistry.java
similarity index 96%
rename from dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/injection/DIRegistry.java
rename to tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/support/DIRegistry.java
index 386b7095e65..2eec2f85c05 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/injection/DIRegistry.java
+++ b/tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/support/DIRegistry.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.main.injection;
+package org.apache.camel.tooling.maven.support;
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Array;
@@ -53,6 +53,13 @@ import org.apache.camel.util.function.Suppliers;
  * Such requirement was found when trying to configure maven-resolver without using the deprecated service locator
  * helpers (see <a href="https://issues.apache.org/jira/browse/MRESOLVER-157">MRESOLVER-157</a>).
  * </p>
+ *
+ * <p>
+ * While this is quite thin extension of {@link SupplierRegistry} and thin implementation of JSR-330 style of dependency
+ * injection and could potentially be used in many places, for now it's used <em>only</em> to configure
+ * <em>beans/services</em> required by {@link org.eclipse.aether.RepositorySystem}. If there's a need to use this
+ * registry in other places, we can move it from {@code camel-tooling-maven} module.
+ * </p>
  */
 public class DIRegistry extends SupplierRegistry {
 
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenArtifact.java b/tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/support/package-info.java
similarity index 63%
rename from dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenArtifact.java
rename to tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/support/package-info.java
index d9ca9c07ecd..9a670cd2628 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenArtifact.java
+++ b/tooling/camel-tooling-maven/src/main/java/org/apache/camel/tooling/maven/support/package-info.java
@@ -14,30 +14,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.main.download;
 
-import java.io.File;
-
-public class MavenArtifact {
-
-    private final MavenGav gav;
-    private final File file;
-
-    public MavenArtifact(MavenGav gav, File file) {
-        this.gav = gav;
-        this.file = file;
-    }
-
-    public MavenGav getGav() {
-        return gav;
-    }
-
-    public File getFile() {
-        return file;
-    }
-
-    @Override
-    public String toString() {
-        return gav.toString();
-    }
-}
+/**
+ * Package with classes that are used together with maven-resolver.
+ */
+package org.apache.camel.tooling.maven.support;
diff --git a/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/MavenGavTest.java b/tooling/camel-tooling-maven/src/test/java/org/apache/camel/tooling/maven/MavenGavTest.java
similarity index 95%
rename from dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/MavenGavTest.java
rename to tooling/camel-tooling-maven/src/test/java/org/apache/camel/tooling/maven/MavenGavTest.java
index e642dc26202..7ead04cc8c6 100644
--- a/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/MavenGavTest.java
+++ b/tooling/camel-tooling-maven/src/test/java/org/apache/camel/tooling/maven/MavenGavTest.java
@@ -14,9 +14,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.main;
+package org.apache.camel.tooling.maven;
 
-import org.apache.camel.main.download.MavenGav;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
diff --git a/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/MavenDependencyResolverTest.java b/tooling/camel-tooling-maven/src/test/java/org/apache/camel/tooling/maven/MavenResolverTest.java
similarity index 83%
copy from dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/MavenDependencyResolverTest.java
copy to tooling/camel-tooling-maven/src/test/java/org/apache/camel/tooling/maven/MavenResolverTest.java
index a91fb5bd854..7ce93bdbdcc 100644
--- a/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/MavenDependencyResolverTest.java
+++ b/tooling/camel-tooling-maven/src/test/java/org/apache/camel/tooling/maven/MavenResolverTest.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.main;
+package org.apache.camel.tooling.maven;
 
 import java.io.File;
 import java.nio.charset.StandardCharsets;
@@ -26,9 +26,7 @@ import java.util.List;
 import java.util.Properties;
 import java.util.concurrent.TimeUnit;
 
-import org.apache.camel.main.download.MavenArtifact;
-import org.apache.camel.main.download.MavenDependencyDownloader;
-import org.apache.camel.main.injection.DIRegistry;
+import org.apache.camel.tooling.maven.support.DIRegistry;
 import org.apache.camel.util.FileUtil;
 import org.apache.commons.codec.binary.Hex;
 import org.apache.http.Header;
@@ -45,23 +43,17 @@ import org.eclipse.aether.repository.RemoteRepository;
 import org.eclipse.aether.resolution.ArtifactRequest;
 import org.eclipse.aether.resolution.ArtifactResult;
 import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.sonatype.plexus.components.cipher.DefaultPlexusCipher;
-import org.sonatype.plexus.components.cipher.PlexusCipher;
-import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
-@Disabled("Manual test")
-public class MavenDependencyResolverTest {
+public class MavenResolverTest {
 
-    public static final Logger LOG = LoggerFactory.getLogger(MavenDependencyResolverTest.class);
+    public static final Logger LOG = LoggerFactory.getLogger(MavenResolverTest.class);
 
     private static HttpServer localServer;
 
@@ -116,41 +108,6 @@ public class MavenDependencyResolverTest {
         }
     }
 
-    @Test
-    public void masterPasswords() throws Exception {
-        PlexusCipher pc = new DefaultPlexusCipher();
-        String mp = pc.encrypt("camel", DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION);
-        LOG.info("master password: {}", mp); // e.g., "SHrYKy0oCBEH5SHhRcuv0U52J3E908O23QWHDyEiGtQ="
-        String p = pc.encrypt("passw0rd", "camel");
-        LOG.info("password: {}", p); // e.g., "9V4tKIxO4ZsHx63bkn9uy6zsYM9VJyG03sTsPzPDK9c="
-
-        assertEquals("passw0rd", pc.decrypt(p, pc.decrypt(mp, DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION)));
-        assertEquals("camel", pc.decrypt(mp, DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION));
-    }
-
-    @Test
-    public void testDownload() throws Exception {
-        List<String> deps = List.of("org.apache.camel:camel-core:3.17.0");
-        try (MavenDependencyDownloader downloader = new MavenDependencyDownloader()) {
-            // build() creates own DIRegistry and configures the resolver/aether stuff
-            downloader.build();
-
-            List<MavenArtifact> answer = downloader.resolveDependenciesViaAether(deps, true);
-            Assertions.assertNotNull(answer);
-            assertTrue(answer.size() > 15);
-            for (MavenArtifact ma : answer) {
-                LOG.info("Artifact (transitive): {}", ma);
-            }
-
-            answer = downloader.resolveDependenciesViaAether(deps, false);
-            Assertions.assertNotNull(answer);
-            assertEquals(1, answer.size());
-            for (MavenArtifact ma : answer) {
-                LOG.info("Artifact (non-transitive): {}", ma);
-            }
-        }
-    }
-
     @Test
     public void playingWithRepositorySystem() throws Exception {
         // MRESOLVER-157 is about removal of org.apache.maven.repository.internal.MavenRepositorySystemUtils,
@@ -213,7 +170,7 @@ public class MavenDependencyResolverTest {
         //       org.eclipse.aether.spi.connector.checksum.ChecksumPolicyProvider
 
         try (DIRegistry registry = new DIRegistry();
-             MavenDependencyDownloader downloader = new MavenDependencyDownloader()) {
+             MavenDownloaderImpl downloader = new MavenDownloaderImpl()) {
             // here we don't call downloader.build() and will do the same stuff manually for demonstration purpose
 
             // see org.eclipse.aether.impl.DefaultServiceLocator.DefaultServiceLocator() - it registers
@@ -233,11 +190,12 @@ public class MavenDependencyResolverTest {
             String localSettings = "target/test-classes/.m2/settings.xml";
             String localSettingsSecurity = "target/test-classes/.m2/settings-security.xml";
 
-            downloader.setMavenSettings(localSettings);
-            downloader.setMavenSettingsSecurity(localSettingsSecurity);
+            downloader.setMavenSettingsLocation(localSettings);
+            downloader.setMavenSettingsSecurityLocation(localSettingsSecurity);
             downloader.setFresh(true);
             downloader.setRepos(null);
-            //            downloader.build();
+            // don't build, as we'll do the maven-resolver initialization ourselves
+            //downloader.build();
 
             Properties systemProperties = new Properties();
 
@@ -275,7 +233,7 @@ public class MavenDependencyResolverTest {
             RepositorySystemSession session
                     = downloader.configureRepositorySystemSession(registry, systemProperties, settings, m2Repo);
 
-            List<RemoteRepository> remoteRepositories = downloader.configureRemoteRepositories(settings, null, false);
+            List<RemoteRepository> remoteRepositories = downloader.configureDefaultRepositories(settings);
 
             // finally we can resolve the artifact
             ArtifactRequest request = new ArtifactRequest();
diff --git a/tooling/camel-tooling-maven/src/test/java/org/apache/camel/tooling/maven/MavenTest.java b/tooling/camel-tooling-maven/src/test/java/org/apache/camel/tooling/maven/MavenTest.java
new file mode 100644
index 00000000000..3fc89a679d8
--- /dev/null
+++ b/tooling/camel-tooling-maven/src/test/java/org/apache/camel/tooling/maven/MavenTest.java
@@ -0,0 +1,44 @@
+/*
+ * 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.tooling.maven;
+
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonatype.plexus.components.cipher.DefaultPlexusCipher;
+import org.sonatype.plexus.components.cipher.PlexusCipher;
+import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class MavenTest {
+
+    public static final Logger LOG = LoggerFactory.getLogger(MavenTest.class);
+
+    @Test
+    public void masterPasswords() throws Exception {
+        PlexusCipher pc = new DefaultPlexusCipher();
+        String mp = pc.encrypt("camel", DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION);
+        LOG.info("master password: {}", mp); // e.g., "SHrYKy0oCBEH5SHhRcuv0U52J3E908O23QWHDyEiGtQ="
+        String p = pc.encrypt("passw0rd", "camel");
+        LOG.info("password: {}", p); // e.g., "9V4tKIxO4ZsHx63bkn9uy6zsYM9VJyG03sTsPzPDK9c="
+
+        assertEquals("passw0rd", pc.decrypt(p, pc.decrypt(mp, DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION)));
+        assertEquals("camel", pc.decrypt(mp, DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION));
+    }
+
+}
diff --git a/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/injection/DIRegistryTest.java b/tooling/camel-tooling-maven/src/test/java/org/apache/camel/tooling/maven/support/DIRegistryTest.java
similarity index 99%
rename from dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/injection/DIRegistryTest.java
rename to tooling/camel-tooling-maven/src/test/java/org/apache/camel/tooling/maven/support/DIRegistryTest.java
index fa03d816e3b..f3c619d0899 100644
--- a/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/injection/DIRegistryTest.java
+++ b/tooling/camel-tooling-maven/src/test/java/org/apache/camel/tooling/maven/support/DIRegistryTest.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.main.injection;
+package org.apache.camel.tooling.maven.support;
 
 import java.io.FilenameFilter;
 import java.io.IOException;
diff --git a/dsl/camel-kamelet-main/src/test/resources/.m2/settings-security.xml b/tooling/camel-tooling-maven/src/test/resources/.m2/settings-security.xml
similarity index 100%
rename from dsl/camel-kamelet-main/src/test/resources/.m2/settings-security.xml
rename to tooling/camel-tooling-maven/src/test/resources/.m2/settings-security.xml
diff --git a/dsl/camel-kamelet-main/src/test/resources/.m2/settings.xml b/tooling/camel-tooling-maven/src/test/resources/.m2/settings.xml
similarity index 100%
rename from dsl/camel-kamelet-main/src/test/resources/.m2/settings.xml
rename to tooling/camel-tooling-maven/src/test/resources/.m2/settings.xml
diff --git a/tooling/camel-tooling-maven/src/test/resources/log4j2.properties b/tooling/camel-tooling-maven/src/test/resources/log4j2.properties
new file mode 100644
index 00000000000..9e703f7435a
--- /dev/null
+++ b/tooling/camel-tooling-maven/src/test/resources/log4j2.properties
@@ -0,0 +1,28 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+
+appender.file.type = File
+appender.file.name = file
+appender.file.fileName = target/camel-tooling-maven.log
+appender.file.layout.type = PatternLayout
+appender.file.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+appender.out.type = Console
+appender.out.name = out
+appender.out.layout.type = PatternLayout
+appender.out.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+rootLogger.level = INFO
+rootLogger.appenderRef.file.ref = file
diff --git a/tooling/pom.xml b/tooling/pom.xml
index 464114f7ea9..824101a64ee 100644
--- a/tooling/pom.xml
+++ b/tooling/pom.xml
@@ -41,6 +41,7 @@
         <module>camel-tooling-util</module>
         <module>openapi-rest-dsl-generator</module>
         <module>maven</module>
+        <module>camel-tooling-maven</module>
     </modules>
 
     <properties>


[camel] 01/04: [CAMEL-19123] Upgrade to maven-resolver 1.9.7 and move away from wagon transport

Posted by gg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ggrzybek pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git

commit a47c5971232891ba33a1cee4f3ac6a7395663741
Author: Grzegorz Grzybek <gr...@gmail.com>
AuthorDate: Wed Mar 8 12:51:10 2023 +0100

    [CAMEL-19123] Upgrade to maven-resolver 1.9.7 and move away from wagon transport
---
 camel-dependencies/pom.xml                         |   2 +-
 dsl/camel-kamelet-main/pom.xml                     |  15 --
 .../main/download/MavenDependencyDownloader.java   | 152 +++++++++++++--------
 .../camel/main/MavenDependencyResolverTest.java    |   6 +-
 parent/pom.xml                                     |   2 +-
 5 files changed, 103 insertions(+), 74 deletions(-)

diff --git a/camel-dependencies/pom.xml b/camel-dependencies/pom.xml
index 25a7b2ebc08..fae851941b0 100644
--- a/camel-dependencies/pom.xml
+++ b/camel-dependencies/pom.xml
@@ -355,7 +355,7 @@
         <maven-resources-plugin-version>3.3.0</maven-resources-plugin-version>
         <maven-reporting-api-version>2.2.1</maven-reporting-api-version>
         <maven-reporting-impl-version>2.0.5</maven-reporting-impl-version>
-        <maven-resolver-version>1.9.5</maven-resolver-version>
+        <maven-resolver-version>1.9.7</maven-resolver-version>
         <maven-shade-plugin-version>3.4.1</maven-shade-plugin-version>
         <maven-shared-utils-plugin-version>3.3.4</maven-shared-utils-plugin-version>
         <maven-surefire-report-plugin-version>3.0.0-M9</maven-surefire-report-plugin-version>
diff --git a/dsl/camel-kamelet-main/pom.xml b/dsl/camel-kamelet-main/pom.xml
index 37006670c61..ed92fd9c7c2 100644
--- a/dsl/camel-kamelet-main/pom.xml
+++ b/dsl/camel-kamelet-main/pom.xml
@@ -157,21 +157,6 @@
             <artifactId>maven-resolver-transport-http</artifactId>
             <version>${maven-resolver-version}</version>
         </dependency>
-        <dependency>
-            <groupId>org.apache.maven.resolver</groupId>
-            <artifactId>maven-resolver-transport-wagon</artifactId>
-            <version>${maven-resolver-version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.maven.wagon</groupId>
-            <artifactId>wagon-file</artifactId>
-            <version>${maven-wagon-version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.maven.wagon</groupId>
-            <artifactId>wagon-http</artifactId>
-            <version>${maven-wagon-version}</version>
-        </dependency>
         <dependency>
             <groupId>org.apache.maven.resolver</groupId>
             <artifactId>maven-resolver-util</artifactId>
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenDependencyDownloader.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenDependencyDownloader.java
index 7eefc1512f3..868f9f13098 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenDependencyDownloader.java
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenDependencyDownloader.java
@@ -82,9 +82,6 @@ import org.apache.maven.settings.io.SettingsReader;
 import org.apache.maven.settings.io.SettingsWriter;
 import org.apache.maven.settings.validation.DefaultSettingsValidator;
 import org.apache.maven.settings.validation.SettingsValidator;
-import org.apache.maven.wagon.Wagon;
-import org.apache.maven.wagon.providers.file.FileWagon;
-import org.apache.maven.wagon.providers.http.HttpWagon;
 import org.codehaus.plexus.util.xml.Xpp3Dom;
 import org.eclipse.aether.ConfigurationProperties;
 import org.eclipse.aether.DefaultRepositorySystemSession;
@@ -188,9 +185,11 @@ import org.eclipse.aether.spi.connector.transport.TransporterProvider;
 import org.eclipse.aether.spi.io.FileProcessor;
 import org.eclipse.aether.spi.localrepo.LocalRepositoryManagerFactory;
 import org.eclipse.aether.spi.synccontext.SyncContextFactory;
-import org.eclipse.aether.transport.wagon.WagonConfigurator;
-import org.eclipse.aether.transport.wagon.WagonProvider;
-import org.eclipse.aether.transport.wagon.WagonTransporterFactory;
+import org.eclipse.aether.transport.file.FileTransporterFactory;
+import org.eclipse.aether.transport.http.ChecksumExtractor;
+import org.eclipse.aether.transport.http.HttpTransporterFactory;
+import org.eclipse.aether.transport.http.Nexus2ChecksumExtractor;
+import org.eclipse.aether.transport.http.XChecksumChecksumExtractor;
 import org.eclipse.aether.util.artifact.DefaultArtifactTypeRegistry;
 import org.eclipse.aether.util.graph.manager.ClassicDependencyManager;
 import org.eclipse.aether.util.graph.selector.AndDependencySelector;
@@ -557,7 +556,7 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
     private List<RemoteRepository> resolveExtraRepositories(String extraRepos) {
         List<RemoteRepository> repositories = new ArrayList<>();
         if (extraRepos != null) {
-            Set<URL> repositoryURLs = new HashSet<>();
+            Set<String> repositoryURLs = new HashSet<>();
             for (String repo : extraRepos.split(",")) {
                 try {
                     URL url = new URL(repo);
@@ -566,7 +565,7 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
                     }
                     String id = "custom" + customCount++;
                     RepositoryPolicy releasePolicy = fresh ? POLICY_FRESH : POLICY_DEFAULT;
-                    if (repositoryURLs.add(url)) {
+                    if (repositoryURLs.add(url.toExternalForm())) {
                         if (url.getHost().equals("repository.apache.org") && url.getPath().contains("/snapshots")) {
                             apacheSnapshotsIncluded = true;
                             repositories.add(apacheSnapshots);
@@ -587,7 +586,7 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
     }
 
     @Override
-    protected void doBuild() throws Exception {
+    protected void doBuild() {
         if (classLoader == null && camelContext != null) {
             classLoader = camelContext.getApplicationContextClassLoader();
         }
@@ -596,6 +595,10 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
         ServiceHelper.buildService(threadPool);
 
         // Aether/maven-resolver configuration used without Shrinkwrap
+        // and without deprecated:
+        //  - org.eclipse.aether.impl.DefaultServiceLocator
+        //  - org.apache.maven.repository.internal.MavenRepositorySystemUtils.newServiceLocator()
+
         registry = new DIRegistry();
         final Properties systemProperties = new Properties();
         // MNG-5670 guard against ConcurrentModificationException
@@ -630,7 +633,7 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
     }
 
     @Override
-    protected void doInit() throws Exception {
+    protected void doInit() {
         RuntimeMXBean mb = ManagementFactory.getRuntimeMXBean();
         if (mb != null) {
             bootClasspath = mb.getClassPath().split("[:|;]");
@@ -673,11 +676,20 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
             mavenSettings = null;
         }
 
-        if (!skip && mavenSettingsSecurity == null) {
-            String m2settingsSecurity = System.getProperty("user.home") + File.separator + ".m2"
-                                        + File.separator + "settings-security.xml";
-            if (new File(m2settingsSecurity).isFile()) {
-                mavenSettingsSecurity = m2settingsSecurity;
+        if (!skip) {
+            if (mavenSettingsSecurity == null) {
+                // implicit security settings
+                String m2settingsSecurity = System.getProperty("user.home") + File.separator + ".m2"
+                        + File.separator + "settings-security.xml";
+                if (new File(m2settingsSecurity).isFile()) {
+                    mavenSettingsSecurity = m2settingsSecurity;
+                }
+            } else {
+                if (!new File(mavenSettingsSecurity).isFile()) {
+                    LOG.warn("Can't access {}. Skipping Maven settings-settings.xml configuration.",
+                            mavenSettingsSecurity);
+                }
+                mavenSettingsSecurity = null;
             }
         }
     }
@@ -749,8 +761,6 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
         // remaining requirements of org.eclipse.aether.internal.impl.synccontext.DefaultSyncContextFactory
         registry.bind(NamedLockFactoryAdapterFactory.class, NamedLockFactoryAdapterFactoryImpl.class);
 
-        HashMap<String, NameMapper> mappers = new HashMap<>();
-
         // remaining requirements of org.eclipse.aether.internal.impl.DefaultRemoteRepositoryManager
         registry.bind(UpdatePolicyAnalyzer.class, DefaultUpdatePolicyAnalyzer.class);
         registry.bind(ChecksumPolicyProvider.class, DefaultChecksumPolicyProvider.class);
@@ -795,37 +805,20 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
         registry.bind(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class);
         // repository connectory factory needs transporter provider(s)
         registry.bind(TransporterProvider.class, DefaultTransporterProvider.class);
-        // and transport provider needs transport factories
-        //        registry.bind(TransporterFactory.class, HttpTransporterFactory.class);
-        //        registry.bind(TransporterFactory.class, FileTransporterFactory.class);
-        // with wagon factory, we may have more flexibility, because a Wagon
-        // may use pre-configured instance of http client (with all the TLS stuff configured)
-        registry.bind(TransporterFactory.class, WagonTransporterFactory.class);
-        // wagon transporter factory needs a wagon provider
-        // wagon transporter uses a hint to select an org.apache.maven.wagon.Wagon. The hint comes from
-        // org.apache.maven.wagon.repository.Repository.getProtocol()
-        registry.bind("manualWagonProvider", WagonProvider.class, new WagonProvider() {
-            @Override
-            public Wagon lookup(String roleHint) {
-                switch (roleHint) {
-                    case "file":
-                        return new FileWagon();
-                    case "http":
-                    case "https":
-                        return new HttpWagon();
-                    default:
-                        return null;
-                }
-            }
 
-            @Override
-            public void release(Wagon wagon) {
-            }
-        });
-        // wagon transporter factory also needs a wagon configurator
-        registry.bind("manualWagonConfigurator", WagonConfigurator.class,
-                (WagonConfigurator) (wagon, configuration) -> {
-                });
+        // and transport provider needs transport factories. there are several implementations, but one of them
+        // is another indirect factory - the WagonTransporterFactory. However it was marked as _ancient_ with
+        // Maven 3.9 / Maven Resolver 1.9, so we'll use the _native_ ones. Even if the wagon allows us to share
+        // the http client (wagon) easier.
+        //        registry.bind(TransporterFactory.class, WagonTransporterFactory.class);
+        registry.bind(TransporterFactory.class, FileTransporterFactory.class);
+        registry.bind(TransporterFactory.class, HttpTransporterFactory.class);
+
+        // requirements of org.eclipse.aether.transport.http.HttpTransporterFactory
+        // nexus2 - ETag: "{SHA1{d40d68ba1f88d8e9b0040f175a6ff41928abd5e7}}"
+        registry.bind(ChecksumExtractor.class, Nexus2ChecksumExtractor.class);
+        // x-checksum - x-checksum-sha1: c74edb60ca2a0b57ef88d9a7da28f591e3d4ce7b
+        registry.bind(ChecksumExtractor.class, XChecksumChecksumExtractor.class);
 
         // requirements of org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory
         registry.bind(RepositoryLayoutProvider.class, DefaultRepositoryLayoutProvider.class);
@@ -976,6 +969,10 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
         DefaultAuthenticationSelector baseAuthenticationSelector = new DefaultAuthenticationSelector();
         AuthenticationSelector authenticationSelector
                 = new ConservativeAuthenticationSelector(baseAuthenticationSelector);
+
+        int connectTimeout = ConfigurationProperties.DEFAULT_CONNECT_TIMEOUT;
+        int requestTimeout = ConfigurationProperties.DEFAULT_REQUEST_TIMEOUT;
+
         for (Server server : settings.getServers()) {
             // no need to bother with null values
             Authentication auth = new AuthenticationBuilder()
@@ -996,6 +993,7 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
             }
 
             if (server.getConfiguration() instanceof Xpp3Dom) {
+                // === pre maven 3.9 / maven-resolver 1.9:
                 // this part is a generic configuration used by different Maven components
                 //  - entire configuration is read by maven-core itself and passed as
                 //    org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration object using
@@ -1033,6 +1031,29 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
                 //    and wagon's "httpHeaders" field is overriden - previously it was set to the value
                 //    of org.eclipse.aether.transport.wagon.WagonTransporter.headers which contained a User-Agent
                 //    header set from "aether.connector.userAgent" property set by Maven...
+                //
+                // === maven 3.9 / maven-resolver 1.9:
+                // As https://maven.apache.org/guides/mini/guide-resolver-transport.html says, the default transport
+                // (the default transport used by Maven Resolver) changed from ancient Wagon to modern
+                // maven-resolver-transport-http aka native HTTP transport.
+                // org.apache.maven.internal.aether.DefaultRepositorySystemSessionFactory.newRepositorySession()
+                // (org.apache.maven:maven-core) has changed considerably in Maven 3.9.0. Before 3.9.0,
+                // org.apache.maven.settings.Server.getConfiguration() was taken and simply passed (wrapped in
+                // org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration) as aether session config property
+                // named "aether.connector.wagon.config.<serverId>"
+                //
+                // With maven 3.9 / maven-resolver 1.9, the same property is used, but the XML configuration is
+                // "translated to proper resolver configuration properties as well", so additionally:
+                // - <httpHeaders> is translated into Map set as "aether.connector.http.headers.<serverId>" property
+                // - <connectTimeout> is translated into Integer set as "aether.connector.connectTimeout.<serverId>"
+                // - <requestTimeout> is translated into Integer set as "aether.connector.requestTimeout.<serverId>"
+                // - if <httpConfiguration>/<all>/<connectionTimeout> is found, a WARNING is printed:
+                //   [WARNING] Settings for server <serverId> uses legacy format
+                // - if <httpConfiguration>/<all>/<readTimeout> is found, a WARNING is printed:
+                //   [WARNING] Settings for server <serverId> uses legacy format
+                // (mind the translation: connectionTimeout->connectTimeout and readTimeout->requestTimeout
+                //
+                // all the properties are described here: https://maven.apache.org/resolver/configuration.html
 
                 Map<String, String> headers = new LinkedHashMap<>();
                 Xpp3Dom serverConfig = (Xpp3Dom) server.getConfiguration();
@@ -1062,7 +1083,7 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
                 }
                 serverConfigurations.put(ConfigurationProperties.HTTP_HEADERS + "." + server.getId(), headers);
 
-                // handle:
+                // DON'T handle (as it's pre-maven 3.9):
                 //     <server>
                 //      <id>my-server</id>
                 //      <configuration>
@@ -1075,6 +1096,28 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
                 //      </configuration>
                 //    </server>
                 // see org.codehaus.plexus.component.configurator.converters.composite.ObjectWithFieldsConverter
+                // handle (maven 3.9+):
+                //     <server>
+                //      <id>my-server</id>
+                //      <configuration>
+                //        <connectTimeout>5000</connectTimeout>
+                //        <requestTimeout>5000</requestTimeout>
+                //      </configuration>
+                //    </server>
+                Xpp3Dom connectTimeoutNode = serverConfig.getChild("connectTimeout");
+                if (connectTimeoutNode != null) {
+                    try {
+                        connectTimeout = Integer.parseInt(connectTimeoutNode.getValue());
+                    } catch (NumberFormatException ignored) {
+                    }
+                }
+                Xpp3Dom requestTimeoutNode = serverConfig.getChild("requestTimeout");
+                if (requestTimeoutNode != null) {
+                    try {
+                        requestTimeout = Integer.parseInt(requestTimeoutNode.getValue());
+                    } catch (NumberFormatException ignored) {
+                    }
+                }
             }
         }
 
@@ -1143,10 +1186,8 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
         // timeouts. see:
         //  - org.eclipse.aether.transport.http.HttpTransporter.HttpTransporter()
         //  - org.eclipse.aether.transport.wagon.WagonTransporter.connectWagon()
-        session.setConfigProperty(ConfigurationProperties.CONNECT_TIMEOUT,
-                ConfigurationProperties.DEFAULT_CONNECT_TIMEOUT);
-        session.setConfigProperty(ConfigurationProperties.REQUEST_TIMEOUT,
-                ConfigurationProperties.DEFAULT_REQUEST_TIMEOUT);
+        session.setConfigProperty(ConfigurationProperties.CONNECT_TIMEOUT, connectTimeout);
+        session.setConfigProperty(ConfigurationProperties.REQUEST_TIMEOUT, requestTimeout);
 
         // server headers configuration - for each <server> from the settings.xml
         serverConfigurations.forEach(session::setConfigProperty);
@@ -1195,7 +1236,8 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
     public List<RemoteRepository> configureRemoteRepositories(Settings settings, String repos, boolean fresh) {
         List<RemoteRepository> repositories = new ArrayList<>();
 
-        Set<URL> repositoryURLs = new HashSet<>();
+        // a set to prevent duplicates, but do not store URLs directly (hashCode() may lead to DNS resolution!)
+        Set<String> repositoryURLs = new HashSet<>();
 
         // add maven central first - always
         repositories.add(new RemoteRepository.Builder("central", "default", MAVEN_CENTRAL_REPO)
@@ -1219,7 +1261,7 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
                     }
                     String id = "custom" + customCount++;
                     RepositoryPolicy releasePolicy = fresh ? POLICY_FRESH : POLICY_DEFAULT;
-                    if (repositoryURLs.add(url)) {
+                    if (repositoryURLs.add(url.toExternalForm())) {
                         if (url.getHost().equals("repository.apache.org") && url.getPath().contains("/snapshots")) {
                             apacheSnapshotsIncluded = true;
                             repositories.add(apacheSnapshots);
@@ -1242,7 +1284,7 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
             for (Repository r : settings.getProfilesAsMap().get(profile).getRepositories()) {
                 try {
                     URL url = new URL(r.getUrl());
-                    if (repositoryURLs.add(url)) {
+                    if (repositoryURLs.add(url.toExternalForm())) {
                         if (url.getHost().equals("repository.apache.org") && url.getPath().startsWith("/snapshots")) {
                             apacheSnapshotsIncluded = true;
                         }
diff --git a/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/MavenDependencyResolverTest.java b/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/MavenDependencyResolverTest.java
index 32530a383ce..a91fb5bd854 100644
--- a/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/MavenDependencyResolverTest.java
+++ b/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/MavenDependencyResolverTest.java
@@ -131,8 +131,8 @@ public class MavenDependencyResolverTest {
     @Test
     public void testDownload() throws Exception {
         List<String> deps = List.of("org.apache.camel:camel-core:3.17.0");
-        try (DIRegistry registry = new DIRegistry();
-             MavenDependencyDownloader downloader = new MavenDependencyDownloader()) {
+        try (MavenDependencyDownloader downloader = new MavenDependencyDownloader()) {
+            // build() creates own DIRegistry and configures the resolver/aether stuff
             downloader.build();
 
             List<MavenArtifact> answer = downloader.resolveDependenciesViaAether(deps, true);
@@ -214,6 +214,8 @@ public class MavenDependencyResolverTest {
 
         try (DIRegistry registry = new DIRegistry();
              MavenDependencyDownloader downloader = new MavenDependencyDownloader()) {
+            // here we don't call downloader.build() and will do the same stuff manually for demonstration purpose
+
             // see org.eclipse.aether.impl.DefaultServiceLocator.DefaultServiceLocator() - it registers
             // lots of default implementations to get started (but it's deprecated with MRESOLVER-157)
 
diff --git a/parent/pom.xml b/parent/pom.xml
index 879d2798fe0..622874e3a2b 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -350,7 +350,7 @@
         <maven-resources-plugin-version>3.3.0</maven-resources-plugin-version>
         <maven-reporting-api-version>2.2.1</maven-reporting-api-version>
         <maven-reporting-impl-version>2.0.5</maven-reporting-impl-version>
-        <maven-resolver-version>1.9.5</maven-resolver-version>
+        <maven-resolver-version>1.9.7</maven-resolver-version>
         <maven-shade-plugin-version>3.4.1</maven-shade-plugin-version>
         <maven-shared-utils-plugin-version>3.3.4</maven-shared-utils-plugin-version>
         <maven-surefire-report-plugin-version>3.0.0-M9</maven-surefire-report-plugin-version>


[camel] 02/04: [CAMEL-11767] Fix dummy-component used in @Disabled tests

Posted by gg...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ggrzybek pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 8ed744ebad80c1250f63612f78eb9c6fc1d5f091
Author: Grzegorz Grzybek <gr...@gmail.com>
AuthorDate: Tue Mar 7 13:39:24 2023 +0100

    [CAMEL-11767] Fix dummy-component used in @Disabled tests
---
 bom/camel-bom/pom.xml                              |  5 ++
 catalog/dummy-component/pom.xml                    | 45 ++++++++++++--
 .../component/dummy/DummyComponentConfigurer.java  | 55 +++++++++++++++++
 .../component/dummy/DummyEndpointConfigurer.java   | 55 +++++++++++++++++
 .../component/dummy/DummyEndpointUriFactory.java   | 71 ++++++++++++++++++++++
 .../services/org/apache/camel/component.properties |  7 +++
 .../services/org/apache/camel/component/dummy      |  2 +
 .../org/apache/camel/configurer/dummy-component    |  2 +
 .../org/apache/camel/configurer/dummy-endpoint     |  2 +
 .../org/apache/camel/urifactory/dummy-endpoint     |  2 +
 .../org/apache/camel/component/dummy/dummy.json    | 34 +++++++++++
 .../src/main/docs/dummy-component.adoc             | 29 +++++++++
 .../camel/component/dummy/DummyEndpoint.java       |  4 +-
 parent/pom.xml                                     |  5 ++
 14 files changed, 312 insertions(+), 6 deletions(-)

diff --git a/bom/camel-bom/pom.xml b/bom/camel-bom/pom.xml
index 64d72e213f5..448af304d5a 100644
--- a/bom/camel-bom/pom.xml
+++ b/bom/camel-bom/pom.xml
@@ -2102,6 +2102,11 @@
         <artifactId>camel-zookeeper-master</artifactId>
         <version>${project.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>dummy-component</artifactId>
+        <version>${project.version}</version>
+      </dependency>
       <dependency>
         <groupId>org.apache.camel</groupId>
         <artifactId>spi-annotations</artifactId>
diff --git a/catalog/dummy-component/pom.xml b/catalog/dummy-component/pom.xml
index fcfd4e37e34..c80134e194e 100644
--- a/catalog/dummy-component/pom.xml
+++ b/catalog/dummy-component/pom.xml
@@ -33,6 +33,10 @@
     <description>Camel Dummy Component</description>
     <packaging>jar</packaging>
 
+    <properties>
+        <camel-prepare-component>true</camel-prepare-component>
+    </properties>
+
     <dependencies>
 
         <dependency>
@@ -66,20 +70,51 @@
                 <version>${project.version}</version>
                 <executions>
                     <execution>
-                        <id>prepare</id>
+                        <id>generate</id>
                         <goals>
-                            <goal>prepare-components</goal>
+                            <goal>generate</goal>
                         </goals>
-                        <phase>generate-resources</phase>
+                        <phase>process-classes</phase>
                     </execution>
                     <execution>
-                        <id>validate</id>
+                        <id>generate-postcompile</id>
                         <goals>
-                            <goal>validate-components</goal>
+                            <goal>generate-postcompile</goal>
                         </goals>
                         <phase>prepare-package</phase>
                     </execution>
                 </executions>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.apache.camel</groupId>
+                        <artifactId>camel-core-model</artifactId>
+                        <version>${project.version}</version>
+                        <scope>compile</scope>
+                    </dependency>
+                </dependencies>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <phase>initialize</phase>
+                        <goals>
+                            <goal>add-source</goal>
+                            <goal>add-resource</goal>
+                        </goals>
+                        <configuration>
+                            <sources>
+                                <source>src/generated/java</source>
+                            </sources>
+                            <resources>
+                                <resource>
+                                    <directory>src/generated/resources</directory>
+                                </resource>
+                            </resources>
+                        </configuration>
+                    </execution>
+                </executions>
             </plugin>
         </plugins>
     </build>
diff --git a/catalog/dummy-component/src/generated/java/org/apache/camel/component/dummy/DummyComponentConfigurer.java b/catalog/dummy-component/src/generated/java/org/apache/camel/component/dummy/DummyComponentConfigurer.java
new file mode 100644
index 00000000000..de8e5cbf248
--- /dev/null
+++ b/catalog/dummy-component/src/generated/java/org/apache/camel/component/dummy/DummyComponentConfigurer.java
@@ -0,0 +1,55 @@
+/* Generated by camel build tools - do NOT edit this file! */
+package org.apache.camel.component.dummy;
+
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.spi.ExtendedPropertyConfigurerGetter;
+import org.apache.camel.spi.PropertyConfigurerGetter;
+import org.apache.camel.spi.ConfigurerStrategy;
+import org.apache.camel.spi.GeneratedPropertyConfigurer;
+import org.apache.camel.util.CaseInsensitiveMap;
+import org.apache.camel.support.component.PropertyConfigurerSupport;
+
+/**
+ * Generated by camel build tools - do NOT edit this file!
+ */
+@SuppressWarnings("unchecked")
+public class DummyComponentConfigurer extends PropertyConfigurerSupport implements GeneratedPropertyConfigurer, PropertyConfigurerGetter {
+
+    @Override
+    public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) {
+        DummyComponent target = (DummyComponent) obj;
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "autowiredenabled":
+        case "autowiredEnabled": target.setAutowiredEnabled(property(camelContext, boolean.class, value)); return true;
+        case "lazystartproducer":
+        case "lazyStartProducer": target.setLazyStartProducer(property(camelContext, boolean.class, value)); return true;
+        default: return false;
+        }
+    }
+
+    @Override
+    public Class<?> getOptionType(String name, boolean ignoreCase) {
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "autowiredenabled":
+        case "autowiredEnabled": return boolean.class;
+        case "lazystartproducer":
+        case "lazyStartProducer": return boolean.class;
+        default: return null;
+        }
+    }
+
+    @Override
+    public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
+        DummyComponent target = (DummyComponent) obj;
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "autowiredenabled":
+        case "autowiredEnabled": return target.isAutowiredEnabled();
+        case "lazystartproducer":
+        case "lazyStartProducer": return target.isLazyStartProducer();
+        default: return null;
+        }
+    }
+}
+
diff --git a/catalog/dummy-component/src/generated/java/org/apache/camel/component/dummy/DummyEndpointConfigurer.java b/catalog/dummy-component/src/generated/java/org/apache/camel/component/dummy/DummyEndpointConfigurer.java
new file mode 100644
index 00000000000..a067999a698
--- /dev/null
+++ b/catalog/dummy-component/src/generated/java/org/apache/camel/component/dummy/DummyEndpointConfigurer.java
@@ -0,0 +1,55 @@
+/* Generated by camel build tools - do NOT edit this file! */
+package org.apache.camel.component.dummy;
+
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.spi.ExtendedPropertyConfigurerGetter;
+import org.apache.camel.spi.PropertyConfigurerGetter;
+import org.apache.camel.spi.ConfigurerStrategy;
+import org.apache.camel.spi.GeneratedPropertyConfigurer;
+import org.apache.camel.util.CaseInsensitiveMap;
+import org.apache.camel.support.component.PropertyConfigurerSupport;
+
+/**
+ * Generated by camel build tools - do NOT edit this file!
+ */
+@SuppressWarnings("unchecked")
+public class DummyEndpointConfigurer extends PropertyConfigurerSupport implements GeneratedPropertyConfigurer, PropertyConfigurerGetter {
+
+    @Override
+    public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) {
+        DummyEndpoint target = (DummyEndpoint) obj;
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "amount": target.setAmount(property(camelContext, int.class, value)); return true;
+        case "celebrity": target.setCelebrity(property(camelContext, boolean.class, value)); return true;
+        case "lazystartproducer":
+        case "lazyStartProducer": target.setLazyStartProducer(property(camelContext, boolean.class, value)); return true;
+        default: return false;
+        }
+    }
+
+    @Override
+    public Class<?> getOptionType(String name, boolean ignoreCase) {
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "amount": return int.class;
+        case "celebrity": return boolean.class;
+        case "lazystartproducer":
+        case "lazyStartProducer": return boolean.class;
+        default: return null;
+        }
+    }
+
+    @Override
+    public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
+        DummyEndpoint target = (DummyEndpoint) obj;
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "amount": return target.getAmount();
+        case "celebrity": return target.isCelebrity();
+        case "lazystartproducer":
+        case "lazyStartProducer": return target.isLazyStartProducer();
+        default: return null;
+        }
+    }
+}
+
diff --git a/catalog/dummy-component/src/generated/java/org/apache/camel/component/dummy/DummyEndpointUriFactory.java b/catalog/dummy-component/src/generated/java/org/apache/camel/component/dummy/DummyEndpointUriFactory.java
new file mode 100644
index 00000000000..221f5b34569
--- /dev/null
+++ b/catalog/dummy-component/src/generated/java/org/apache/camel/component/dummy/DummyEndpointUriFactory.java
@@ -0,0 +1,71 @@
+/* Generated by camel build tools - do NOT edit this file! */
+package org.apache.camel.component.dummy;
+
+import java.net.URISyntaxException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.camel.spi.EndpointUriFactory;
+
+/**
+ * Generated by camel build tools - do NOT edit this file!
+ */
+public class DummyEndpointUriFactory extends org.apache.camel.support.component.EndpointUriFactorySupport implements EndpointUriFactory {
+
+    private static final String BASE = ":drink";
+
+    private static final Set<String> PROPERTY_NAMES;
+    private static final Set<String> SECRET_PROPERTY_NAMES;
+    private static final Set<String> MULTI_VALUE_PREFIXES;
+    static {
+        Set<String> props = new HashSet<>(4);
+        props.add("amount");
+        props.add("celebrity");
+        props.add("drink");
+        props.add("lazyStartProducer");
+        PROPERTY_NAMES = Collections.unmodifiableSet(props);
+        SECRET_PROPERTY_NAMES = Collections.emptySet();
+        MULTI_VALUE_PREFIXES = Collections.emptySet();
+    }
+
+    @Override
+    public boolean isEnabled(String scheme) {
+        return "dummy".equals(scheme);
+    }
+
+    @Override
+    public String buildUri(String scheme, Map<String, Object> properties, boolean encode) throws URISyntaxException {
+        String syntax = scheme + BASE;
+        String uri = syntax;
+
+        Map<String, Object> copy = new HashMap<>(properties);
+
+        uri = buildPathParameter(syntax, uri, "drink", null, true, copy);
+        uri = buildQueryParameters(uri, copy, encode);
+        return uri;
+    }
+
+    @Override
+    public Set<String> propertyNames() {
+        return PROPERTY_NAMES;
+    }
+
+    @Override
+    public Set<String> secretPropertyNames() {
+        return SECRET_PROPERTY_NAMES;
+    }
+
+    @Override
+    public Set<String> multiValuePrefixes() {
+        return MULTI_VALUE_PREFIXES;
+    }
+
+    @Override
+    public boolean isLenientProperties() {
+        return false;
+    }
+}
+
diff --git a/catalog/dummy-component/src/generated/resources/META-INF/services/org/apache/camel/component.properties b/catalog/dummy-component/src/generated/resources/META-INF/services/org/apache/camel/component.properties
new file mode 100644
index 00000000000..e315dbeb69f
--- /dev/null
+++ b/catalog/dummy-component/src/generated/resources/META-INF/services/org/apache/camel/component.properties
@@ -0,0 +1,7 @@
+# Generated by camel build tools - do NOT edit this file!
+components=dummy
+groupId=org.apache.camel
+artifactId=dummy-component
+version=4.0.0-SNAPSHOT
+projectName=Camel :: Catalog :: Dummy Component
+projectDescription=Camel Dummy Component
diff --git a/catalog/dummy-component/src/generated/resources/META-INF/services/org/apache/camel/component/dummy b/catalog/dummy-component/src/generated/resources/META-INF/services/org/apache/camel/component/dummy
new file mode 100644
index 00000000000..51937e75f91
--- /dev/null
+++ b/catalog/dummy-component/src/generated/resources/META-INF/services/org/apache/camel/component/dummy
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.component.dummy.DummyComponent
diff --git a/catalog/dummy-component/src/generated/resources/META-INF/services/org/apache/camel/configurer/dummy-component b/catalog/dummy-component/src/generated/resources/META-INF/services/org/apache/camel/configurer/dummy-component
new file mode 100644
index 00000000000..0ed3c4a9a1e
--- /dev/null
+++ b/catalog/dummy-component/src/generated/resources/META-INF/services/org/apache/camel/configurer/dummy-component
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.component.dummy.DummyComponentConfigurer
diff --git a/catalog/dummy-component/src/generated/resources/META-INF/services/org/apache/camel/configurer/dummy-endpoint b/catalog/dummy-component/src/generated/resources/META-INF/services/org/apache/camel/configurer/dummy-endpoint
new file mode 100644
index 00000000000..9989d45ef0d
--- /dev/null
+++ b/catalog/dummy-component/src/generated/resources/META-INF/services/org/apache/camel/configurer/dummy-endpoint
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.component.dummy.DummyEndpointConfigurer
diff --git a/catalog/dummy-component/src/generated/resources/META-INF/services/org/apache/camel/urifactory/dummy-endpoint b/catalog/dummy-component/src/generated/resources/META-INF/services/org/apache/camel/urifactory/dummy-endpoint
new file mode 100644
index 00000000000..a4e9e676409
--- /dev/null
+++ b/catalog/dummy-component/src/generated/resources/META-INF/services/org/apache/camel/urifactory/dummy-endpoint
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.component.dummy.DummyEndpointUriFactory
diff --git a/catalog/dummy-component/src/generated/resources/org/apache/camel/component/dummy/dummy.json b/catalog/dummy-component/src/generated/resources/org/apache/camel/component/dummy/dummy.json
new file mode 100644
index 00000000000..d0959ae2db2
--- /dev/null
+++ b/catalog/dummy-component/src/generated/resources/org/apache/camel/component/dummy/dummy.json
@@ -0,0 +1,34 @@
+{
+  "component": {
+    "kind": "component",
+    "name": "dummy",
+    "title": "Dummy",
+    "description": "Camel Dummy Component",
+    "deprecated": false,
+    "firstVersion": "2.19.0",
+    "label": "testing",
+    "javaType": "org.apache.camel.component.dummy.DummyComponent",
+    "supportLevel": "Stable",
+    "groupId": "org.apache.camel",
+    "artifactId": "dummy-component",
+    "version": "4.0.0-SNAPSHOT",
+    "scheme": "dummy",
+    "extendsScheme": "",
+    "syntax": "dummy:drink",
+    "async": false,
+    "api": false,
+    "consumerOnly": false,
+    "producerOnly": true,
+    "lenientProperties": false
+  },
+  "componentProperties": {
+    "lazyStartProducer": { "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail during star [...]
+    "autowiredEnabled": { "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching type, which t [...]
+  },
+  "properties": {
+    "drink": { "kind": "path", "displayName": "Drink", "group": "producer", "label": "", "required": true, "type": "object", "javaType": "org.apache.camel.component.dummy.Drinks", "enum": [ "Beer", "GinTonic", "Wine" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "What drink to order" },
+    "amount": { "kind": "parameter", "displayName": "Amount", "group": "producer", "label": "", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 1, "description": "Number of drinks in the order" },
+    "celebrity": { "kind": "parameter", "displayName": "Celebrity", "group": "producer", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Is this a famous person ordering" },
+    "lazyStartProducer": { "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may other [...]
+  }
+}
diff --git a/catalog/dummy-component/src/main/docs/dummy-component.adoc b/catalog/dummy-component/src/main/docs/dummy-component.adoc
new file mode 100644
index 00000000000..582e2ac687a
--- /dev/null
+++ b/catalog/dummy-component/src/main/docs/dummy-component.adoc
@@ -0,0 +1,29 @@
+= Dummy Component
+:doctitle: Dummy
+:shortname: dummy
+:artifactid: dummy-component
+:description: Camel Dummy Component
+:since: 2.19
+:supportlevel: Stable
+:component-header: Only producer is supported
+
+*Since Camel {since}*
+
+*{component-header}*
+
+*Dummy-Component* is an http://camel.apache.org/[Apache Camel] component that is used for
+various internal tests.
+
+// component-configure options: START
+// component-configure options: END
+
+// component options: START
+include::partial$component-configure-options.adoc[]
+include::partial$component-endpoint-options.adoc[]
+// component options: END
+
+// endpoint options: START
+// endpoint options: END
+
+// component headers: START
+// component headers: END
diff --git a/catalog/dummy-component/src/main/java/org/apache/camel/component/dummy/DummyEndpoint.java b/catalog/dummy-component/src/main/java/org/apache/camel/component/dummy/DummyEndpoint.java
index 80789a50e6b..51050e21e03 100644
--- a/catalog/dummy-component/src/main/java/org/apache/camel/component/dummy/DummyEndpoint.java
+++ b/catalog/dummy-component/src/main/java/org/apache/camel/component/dummy/DummyEndpoint.java
@@ -27,7 +27,9 @@ import org.apache.camel.spi.UriParam;
 import org.apache.camel.spi.UriPath;
 import org.apache.camel.support.DefaultEndpoint;
 
-@UriEndpoint(scheme = "dummy", syntax = "dummy:drink", title = "Dummy", category = { Category.TESTING }, producerOnly = true)
+@UriEndpoint(firstVersion = "2.19.0", scheme = "dummy", syntax = "dummy:drink", title = "Dummy",
+             category = { Category.TESTING },
+             producerOnly = true)
 public class DummyEndpoint extends DefaultEndpoint {
 
     @UriPath
diff --git a/parent/pom.xml b/parent/pom.xml
index 622874e3a2b..5161c91ea93 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -2438,6 +2438,11 @@
                 <artifactId>camel-zookeeper-master</artifactId>
                 <version>${project.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.apache.camel</groupId>
+                <artifactId>dummy-component</artifactId>
+                <version>${project.version}</version>
+            </dependency>
             <dependency>
                 <groupId>org.apache.camel.maven</groupId>
                 <artifactId>camel-debezium-maven-plugin</artifactId>