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

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


The following commit(s) were added to refs/heads/main by this push:
     new 05ae5dc77c4 CAMEL-18412: camel-jbang - Add support for hawtio
05ae5dc77c4 is described below

commit 05ae5dc77c4d6aeb1b8627247298a9cb81210c9b
Author: Claus Ibsen <claus.ib...@gmail.com>
AuthorDate: Fri Aug 19 17:31:54 2022 +0200

    CAMEL-18412: camel-jbang - Add support for hawtio
---
 .../modules/ROOT/pages/camel-jbang.adoc            |  51 +++++++++
 dsl/camel-jbang/camel-jbang-core/pom.xml           |  15 +++
 .../dsl/jbang/core/commands/CamelCommand.java      |   2 +-
 .../dsl/jbang/core/commands/CamelJBangMain.java    |   4 +
 .../core/commands/jolokia/AvailablePortFinder.java | 113 +++++++++++++++++++
 .../dsl/jbang/core/commands/jolokia/Hawtio.java    | 124 +++++++++++++++++++++
 .../dsl/jbang/core/commands/jolokia/Jolokia.java   |  74 ++++++++++++
 .../camel/main/download/DependencyDownloader.java  |  10 ++
 .../download/DependencyDownloaderClassLoader.java  |   5 +
 .../camel/main/download/DownloadThreadPool.java    |  11 +-
 .../main/download/MavenDependencyDownloader.java   |  45 +++++---
 11 files changed, 433 insertions(+), 21 deletions(-)

diff --git a/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
index bb8f1f4c136..9fd0731765d 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-jbang.adoc
@@ -561,6 +561,57 @@ Stopping running Camel integration (pid: 42171)
 Stopping running Camel integration (pid: 44805)
 ----
 
+=== Using Jolokia and Hawtio
+
+The https://hawt.io/[Hawtio] web console allows inspecting running Camel 
applications, such
+as all the JMX management information, and not but least to visualize the 
Camel routes
+with live performance metrics. Hawtio is a handy tool for many years, and we 
have made it
+easy to use Hawtio with Camel JBang.
+
+To let Hawtio able to inspect the Camel integrations, then at first you need 
to attach
+the Jolokia JVM Agent in the running integration, this can be done as follows:
+
+[source,bash]
+----
+camel ps
+37928 camel run foo.yaml (age: 20h18m)
+44805 camel run dude.java (age: 58s)
+----
+
+With the PID you can then attach Jolokia:
+
+[source,bash]
+----
+camel jolokia 37928
+Started Jolokia for PID 37928
+http://127.0.0.1:8778/jolokia/
+----
+
+Then you can launch https://hawt.io/[Hawtio] using Camel JBang:
+
+[source,bash]
+----
+camel hawtio
+----
+
+This will automatically download and start Hawtio, and open in web browser.
+
+TIP: See `camel hawtio --help` for options.
+
+And when Hawtio launches in the web browser, click the _Discover_ tab which 
should
+list all the local available Jolokia Agents (yes you can use `camel jolokia 
PID` to connect
+to multiple different Camel integrations and from this list select which to 
load).
+
+Click the green _lightning_ icon to connect to running Camel integration (of 
choice).
+
+You can uninstall the Jolokia JVM Agent in a running Camel application when no 
longer needed:
+
+[source,bash]
+----
+camel jolokia 37928 --stop
+Stopped Jolokia for PID 37928
+----
+
 === Scripting from terminal using pipes
 
 You can also execute a Camel JBang file as a script that can be used for 
terminal scripting with pipes and filters.
diff --git a/dsl/camel-jbang/camel-jbang-core/pom.xml 
b/dsl/camel-jbang/camel-jbang-core/pom.xml
index fdca84698c7..84de066a0fe 100644
--- a/dsl/camel-jbang/camel-jbang-core/pom.xml
+++ b/dsl/camel-jbang/camel-jbang-core/pom.xml
@@ -58,6 +58,7 @@
             <artifactId>camel-resourceresolver-github</artifactId>
         </dependency>
 
+        <!-- cli -->
         <dependency>
             <groupId>commons-io</groupId>
             <artifactId>commons-io</artifactId>
@@ -67,6 +68,20 @@
             <artifactId>picocli</artifactId>
         </dependency>
 
+        <!-- jolokia -->
+        <dependency>
+            <groupId>org.jolokia</groupId>
+            <artifactId>jolokia-jvm</artifactId>
+            <version>1.7.1</version>
+        </dependency>
+        <!-- servlet for launching hawtio -->
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+            <version>${javax-servlet-api-version}</version>
+            <scope>optional</scope>
+        </dependency>
+
         <!-- logging -->
         <dependency>
             <groupId>org.slf4j</groupId>
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelCommand.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelCommand.java
index 029eadf5f2c..caa1c6f2ee9 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelCommand.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelCommand.java
@@ -20,7 +20,7 @@ import java.util.concurrent.Callable;
 
 import picocli.CommandLine;
 
-abstract class CamelCommand implements Callable<Integer> {
+public abstract class CamelCommand implements Callable<Integer> {
 
     public static final String PID_DIR = "${sys:user.home}/.camel";
 
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
index 3b7911d76cc..428e701c176 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
@@ -20,6 +20,8 @@ import java.util.concurrent.Callable;
 
 import org.apache.camel.catalog.CamelCatalog;
 import org.apache.camel.catalog.DefaultCamelCatalog;
+import org.apache.camel.dsl.jbang.core.commands.jolokia.Hawtio;
+import org.apache.camel.dsl.jbang.core.commands.jolokia.Jolokia;
 import picocli.CommandLine;
 import picocli.CommandLine.Command;
 
@@ -35,6 +37,8 @@ public class CamelJBangMain implements Callable<Integer> {
                 .addSubcommand("stop", new CommandLine(new StopProcess(main)))
                 .addSubcommand("init", new CommandLine(new Init(main)))
                 .addSubcommand("bind", new CommandLine(new Bind(main)))
+                .addSubcommand("jolokia", new CommandLine(new Jolokia(main)))
+                .addSubcommand("hawtio", new CommandLine(new Hawtio(main)))
                 .addSubcommand("pipe", new CommandLine(new Pipe(main)))
                 .addSubcommand("generate", new CommandLine(new 
CodeGenerator(main))
                         .addSubcommand("rest", new CommandLine(new 
CodeRestGenerator(main))))
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/jolokia/AvailablePortFinder.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/jolokia/AvailablePortFinder.java
new file mode 100644
index 00000000000..252cde0061b
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/jolokia/AvailablePortFinder.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dsl.jbang.core.commands.jolokia;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class AvailablePortFinder {
+
+    private static final AvailablePortFinder INSTANCE = new 
AvailablePortFinder();
+
+    private class Port implements AutoCloseable {
+        final int port;
+
+        public Port(int port) {
+            this.port = port;
+        }
+
+        public int getPort() {
+            return port;
+        }
+
+        public void release() {
+            AvailablePortFinder.this.release(this);
+        }
+
+        public String toString() {
+            return Integer.toString(port);
+        }
+
+        @Override
+        public void close() {
+            release();
+        }
+    }
+
+    private final Map<Integer, Port> portMapping = new ConcurrentHashMap<>();
+
+    synchronized void release(Port port) {
+        INSTANCE.portMapping.remove(port.getPort(), port);
+    }
+
+    /**
+     * Gets the next available port in the given range.
+     *
+     * @param  fromPort              port number start range.
+     * @param  toPort                port number end range.
+     *
+     * @throws IllegalStateException if there are no ports available
+     * @return                       the available port
+     */
+    public static int getNextAvailable(int fromPort, int toPort) {
+        try (Port port = INSTANCE.findPort(fromPort, toPort)) {
+            return port.getPort();
+        }
+    }
+
+    synchronized Port findPort(int fromPort, int toPort) {
+        for (int i = fromPort; i <= toPort; i++) {
+            try {
+                final int port = probePort(i);
+                Port p = new Port(port);
+                Port prv = INSTANCE.portMapping.putIfAbsent(port, p);
+                if (prv == null) {
+                    return p;
+                }
+            } catch (IllegalStateException e) {
+                // do nothing, let's try the next port
+            }
+        }
+        throw new IllegalStateException("Cannot find free port");
+    }
+
+    /**
+     * Probe a port to see if it is free
+     *
+     * @param  port                  an integer port number to be tested. If 
port is 0, then the next available port is
+     *                               returned.
+     * @throws IllegalStateException if the port is not free or, in case of 
port 0, if there are no ports available at
+     *                               all.
+     * @return                       the port number itself if the port is 
free or, in case of port 0, the first
+     *                               available port number.
+     */
+    private static int probePort(int port) {
+        try (ServerSocket ss = new ServerSocket()) {
+            ss.setReuseAddress(true);
+            ss.bind(new InetSocketAddress((InetAddress) null, port), 1);
+            int probedPort = ss.getLocalPort();
+            return probedPort;
+        } catch (IOException e) {
+            throw new IllegalStateException("Cannot find free port", e);
+        }
+    }
+
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/jolokia/Hawtio.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/jolokia/Hawtio.java
new file mode 100644
index 00000000000..844820e80a9
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/jolokia/Hawtio.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dsl.jbang.core.commands.jolokia;
+
+import java.awt.*;
+import java.lang.reflect.Method;
+import java.net.URI;
+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 picocli.CommandLine;
+import picocli.CommandLine.Command;
+
+@Command(name = "hawtio", description = "Launch Hawtio web console")
+public class Hawtio extends CamelCommand {
+
+    @CommandLine.Option(names = { "--version" },
+                        description = "Version of the Hawtio web console", 
defaultValue = "2.15.0")
+    private String version = "2.15.0";
+
+    @CommandLine.Option(names = { "--port" },
+                        description = "Port number to use for Hawtio web 
console", defaultValue = "8080")
+    private int port = 8080;
+
+    @CommandLine.Option(names = { "--openUrl" },
+                        description = "To automatic open hawtio web console in 
the web browser", defaultValue = "true")
+    private boolean openUrl = true;
+
+    private final CountDownLatch shutdownLatch = new CountDownLatch(1);
+
+    public Hawtio(CamelJBangMain main) {
+        super(main);
+    }
+
+    @Override
+    public Integer call() throws Exception {
+        ClassLoader cl = createClassLoader();
+
+        MavenDependencyDownloader downloader = new MavenDependencyDownloader();
+        downloader.setClassLoader(cl);
+        downloader.start();
+        // download hawtio embedded mode
+        downloader.downloadDependency("io.hawt", "hawtio-embedded", version);
+        // download war that has the web-console
+        MavenArtifact ma = downloader.downloadArtifact("io.hawt", 
"hawtio-war:war", version);
+        if (ma == null) {
+            System.err.println("Cannot download io.hawt:hawtio-war:war:" + 
version);
+            return 1;
+        }
+
+        String war = ma.getFile().getAbsolutePath();
+
+        // invoke hawtio main app that launches hawtio
+        try {
+            // turn off hawito auth
+            System.setProperty("hawtio.authenticationEnabled", "false");
+
+            // use CL from camel context that now has the downloaded JAR
+            Thread.currentThread().setContextClassLoader(cl);
+            Class<?> clazz = cl.loadClass("io.hawt.embedded.Main");
+            Object hawt = clazz.getDeclaredConstructor().newInstance();
+            Method m = clazz.getMethod("setWar", String.class);
+            ObjectHelper.invokeMethod(m, hawt, war);
+            m = clazz.getMethod("run");
+            ObjectHelper.invokeMethod(m, hawt);
+
+            if (openUrl) {
+                // open web browser
+                String url = "http://localhost:"; + port + "/hawtio";
+                System.setProperty("hawtio.url", url);
+                if (openUrl && Desktop.isDesktopSupported()) {
+                    try {
+                        Desktop.getDesktop().browse(new URI(url));
+                    } catch (Exception e) {
+                        System.err.println(String.format("Failed to open 
browser session, to access hawtio visit \"%s\"", url));
+                    }
+                }
+            }
+
+            // keep JVM running
+            installHangupInterceptor();
+            shutdownLatch.await();
+
+        } catch (Throwable e) {
+            System.err.println("Cannot launch hawtio due to: " + 
e.getMessage());
+            e.printStackTrace();
+            return 1;
+        } finally {
+            downloader.stop();
+        }
+
+        return 0;
+    }
+
+    private ClassLoader createClassLoader() {
+        ClassLoader parentCL = Hawtio.class.getClassLoader();
+        return new DependencyDownloaderClassLoader(parentCL);
+    }
+
+    private void installHangupInterceptor() {
+        Thread task = new Thread(shutdownLatch::countDown);
+        Runtime.getRuntime().addShutdownHook(task);
+    }
+
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/jolokia/Jolokia.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/jolokia/Jolokia.java
new file mode 100644
index 00000000000..08c13f919c0
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/jolokia/Jolokia.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dsl.jbang.core.commands.jolokia;
+
+import org.apache.camel.dsl.jbang.core.commands.CamelCommand;
+import org.apache.camel.dsl.jbang.core.commands.CamelJBangMain;
+import org.jolokia.jvmagent.client.command.CommandDispatcher;
+import org.jolokia.jvmagent.client.util.OptionsAndArgs;
+import org.jolokia.jvmagent.client.util.PlatformUtils;
+import org.jolokia.jvmagent.client.util.VirtualMachineHandlerOperations;
+import picocli.CommandLine;
+import picocli.CommandLine.Command;
+
+@Command(name = "jolokia", description = "Attach Jolokia JVM Agent to a 
running Camel integration")
+public class Jolokia extends CamelCommand {
+
+    @CommandLine.Parameters(description = "PID of running Camel integration", 
arity = "1")
+    private long pid;
+
+    @CommandLine.Option(names = { "--stop" },
+                        description = "Stops the Jolokia JVM Agent in the 
running Camel integration")
+    private boolean stop;
+
+    public Jolokia(CamelJBangMain main) {
+        super(main);
+    }
+
+    @Override
+    public Integer call() throws Exception {
+        int exitCode;
+
+        try {
+            OptionsAndArgs options;
+            if (stop) {
+                options = new OptionsAndArgs(null, "stop", "" + pid);
+            } else {
+                // find a new free port to use when starting a new connection
+                long port = AvailablePortFinder.getNextAvailable(8778, 10000);
+                options = new OptionsAndArgs(null, "--port", "" + port, 
"start", "" + pid);
+            }
+            VirtualMachineHandlerOperations vmHandler = 
PlatformUtils.createVMAccess(options);
+            CommandDispatcher dispatcher = new CommandDispatcher(options);
+
+            Object vm = options.needsVm() ? vmHandler.attachVirtualMachine() : 
null;
+            try {
+                exitCode = dispatcher.dispatchCommand(vm, vmHandler);
+            } finally {
+                if (vm != null) {
+                    vmHandler.detachAgent(vm);
+                }
+            }
+        } catch (Exception e) {
+            System.err.println("Cannot execute jolokia command due " + 
e.getMessage());
+            exitCode = 1;
+        }
+
+        return exitCode;
+    }
+
+}
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 5e0ccde36e4..f8edee21777 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
@@ -24,6 +24,16 @@ import org.apache.camel.StaticService;
  */
 public interface DependencyDownloader extends CamelContextAware, StaticService 
{
 
+    /**
+     * Classloader able to load from downloaded dependencies.
+     */
+    ClassLoader getClassLoader();
+
+    /**
+     * Sets the classloader to use that will be able to load from downloaded 
dependencies
+     */
+    void setClassLoader(ClassLoader classLoader);
+
     /**
      * Adds a listener to capture download activity
      */
diff --git 
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloaderClassLoader.java
 
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloaderClassLoader.java
index b01ab78a4eb..1655fcfbe5f 100644
--- 
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloaderClassLoader.java
+++ 
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloaderClassLoader.java
@@ -40,6 +40,11 @@ public class DependencyDownloaderClassLoader extends 
URLClassLoader {
         }
     }
 
+    @Override
+    public Class<?> loadClass(String name) throws ClassNotFoundException {
+        return super.loadClass(name);
+    }
+
     public List<String> getDownloaded() {
         return 
Arrays.stream(getURLs()).map(URL::getFile).collect(Collectors.toList());
     }
diff --git 
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DownloadThreadPool.java
 
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DownloadThreadPool.java
index 07dd293c646..7ff523c0a26 100644
--- 
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DownloadThreadPool.java
+++ 
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DownloadThreadPool.java
@@ -17,6 +17,7 @@
 package org.apache.camel.main.download;
 
 import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
@@ -83,13 +84,19 @@ class DownloadThreadPool extends ServiceSupport implements 
CamelContextAware {
 
     @Override
     protected void doBuild() throws Exception {
-        executorService = 
camelContext.getExecutorServiceManager().newCachedThreadPool(this, 
"MavenDownload");
+        if (camelContext != null) {
+            executorService = 
camelContext.getExecutorServiceManager().newCachedThreadPool(this, 
"MavenDownload");
+        } else {
+            executorService = Executors.newCachedThreadPool();
+        }
     }
 
     @Override
     protected void doShutdown() throws Exception {
-        if (executorService != null) {
+        if (executorService != null && camelContext != null) {
             camelContext.getExecutorServiceManager().shutdown(executorService);
+        } else if (executorService != null) {
+            executorService.shutdown();
         }
     }
 }
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 853cb5e1db4..46c5c4f03fe 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
@@ -45,6 +45,7 @@ public class MavenDependencyDownloader extends ServiceSupport 
implements Depende
 
     private String[] bootClasspath;
     private DownloadThreadPool threadPool;
+    private ClassLoader classLoader;
     private CamelContext camelContext;
     private final Set<DownloadListener> downloadListeners = new 
LinkedHashSet<>();
     private String repos;
@@ -60,6 +61,14 @@ public class MavenDependencyDownloader extends 
ServiceSupport implements Depende
         this.camelContext = camelContext;
     }
 
+    public ClassLoader getClassLoader() {
+        return classLoader;
+    }
+
+    public void setClassLoader(ClassLoader classLoader) {
+        this.classLoader = classLoader;
+    }
+
     @Override
     public void addDownloadListener(DownloadListener downloadListener) {
         CamelContextAware.trySetCamelContext(downloadListener, 
getCamelContext());
@@ -153,15 +162,15 @@ public class MavenDependencyDownloader extends 
ServiceSupport implements Depende
                     = 
MavenDependencyResolver.resolveDependenciesViaAether(deps, mavenRepos, false, 
fresh, transitively);
             LOG.debug("Resolved {} -> [{}]", gav, artifacts);
 
-            DependencyDownloaderClassLoader classLoader
-                    = (DependencyDownloaderClassLoader) 
camelContext.getApplicationContextClassLoader();
-
             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)) {
-                    classLoader.addFile(file);
+                    if (classLoader instanceof 
DependencyDownloaderClassLoader) {
+                        DependencyDownloaderClassLoader ddc = 
(DependencyDownloaderClassLoader) classLoader;
+                        ddc.addFile(file);
+                    }
                     LOG.trace("Added classpath: {}", a.getGav());
                 }
             }
@@ -234,22 +243,19 @@ public class MavenDependencyDownloader extends 
ServiceSupport implements Depende
             }
         }
 
-        if (camelContext.getApplicationContextClassLoader() != null) {
-            ClassLoader cl = camelContext.getApplicationContextClassLoader();
-            if (cl instanceof URLClassLoader) {
-                URLClassLoader ucl = (URLClassLoader) cl;
-                for (URL u : ucl.getURLs()) {
-                    String s = u.toString();
-                    if (s.contains(target)) {
-                        // trigger listener
-                        if (listener) {
-                            for (DownloadListener dl : downloadListeners) {
-                                dl.onDownloadDependency(groupId, artifactId, 
version);
-                            }
+        if (classLoader instanceof URLClassLoader) {
+            URLClassLoader ucl = (URLClassLoader) classLoader;
+            for (URL u : ucl.getURLs()) {
+                String s = u.toString();
+                if (s.contains(target)) {
+                    // trigger listener
+                    if (listener) {
+                        for (DownloadListener dl : downloadListeners) {
+                            dl.onDownloadDependency(groupId, artifactId, 
version);
                         }
-                        // already on classpath
-                        return true;
                     }
+                    // already on classpath
+                    return true;
                 }
             }
         }
@@ -258,6 +264,9 @@ public class MavenDependencyDownloader extends 
ServiceSupport implements Depende
 
     @Override
     protected void doBuild() throws Exception {
+        if (classLoader == null && camelContext != null) {
+            classLoader = camelContext.getApplicationContextClassLoader();
+        }
         threadPool = new DownloadThreadPool();
         threadPool.setCamelContext(camelContext);
         ServiceHelper.buildService(threadPool);

Reply via email to