You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2022/12/18 11:34:12 UTC

[camel] 03/03: CAMEL-18815: camel-jbang - Base package scan to search in downloaded JARs

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

commit 343319ff302eed55894c85cb16888553795c698a
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Sun Dec 18 12:32:29 2022 +0100

    CAMEL-18815: camel-jbang - Base package scan to search in downloaded JARs
---
 .../org/apache/camel/main/BaseMainSupport.java     |  10 +-
 .../java/org/apache/camel/main/KameletMain.java    |   2 +
 .../download/BasePackageScanDownloadListener.java  | 105 +++++++++++++++++++++
 3 files changed, 114 insertions(+), 3 deletions(-)

diff --git a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
index e5d6aa38f0a..6d1fe5e36de 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
@@ -491,6 +491,8 @@ public abstract class BaseMainSupport extends BaseService {
         // configure from main configuration properties
         doConfigureCamelContextFromMainConfiguration(camelContext, mainConfigurationProperties, autoConfiguredProperties);
 
+        configurePackageScan(camelContext);
+
         // try to load configuration classes
         loadConfigurations(camelContext);
 
@@ -594,9 +596,11 @@ public abstract class BaseMainSupport extends BaseService {
     protected void configurePackageScan(CamelContext camelContext) {
         if (mainConfigurationProperties.isBasePackageScanEnabled()) {
             // only set the base package if enabled
-            camelContext.adapt(ExtendedCamelContext.class).setBasePackageScan(mainConfigurationProperties.getBasePackageScan());
-            if (mainConfigurationProperties.getBasePackageScan() != null) {
-                LOG.info("Classpath scanning enabled from base package: {}", mainConfigurationProperties.getBasePackageScan());
+            String base = mainConfigurationProperties.getBasePackageScan();
+            String current = camelContext.adapt(ExtendedCamelContext.class).getBasePackageScan();
+            if (base != null && !base.equals(current)) {
+                camelContext.adapt(ExtendedCamelContext.class).setBasePackageScan(base);
+                LOG.info("Classpath scanning enabled from base package: {}", base);
             }
         }
     }
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java
index 9c31b64fba1..df29d50d8fb 100644
--- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/KameletMain.java
@@ -27,6 +27,7 @@ import org.apache.camel.ProducerTemplate;
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.impl.DefaultCamelContext;
 import org.apache.camel.main.download.AutoConfigureDownloadListener;
+import org.apache.camel.main.download.BasePackageScanDownloadListener;
 import org.apache.camel.main.download.CircuitBreakerDownloader;
 import org.apache.camel.main.download.CommandLineDependencyDownloader;
 import org.apache.camel.main.download.DependencyDownloaderClassLoader;
@@ -320,6 +321,7 @@ public class KameletMain extends MainCommandLineSupport {
             }
             downloader.addDownloadListener(new AutoConfigureDownloadListener());
             downloader.addArtifactDownloadListener(new TypeConverterLoaderDownloadListener());
+            downloader.addArtifactDownloadListener(new BasePackageScanDownloadListener());
 
             // register as extension
             try {
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/BasePackageScanDownloadListener.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/BasePackageScanDownloadListener.java
new file mode 100644
index 00000000000..cbb4e121f85
--- /dev/null
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/BasePackageScanDownloadListener.java
@@ -0,0 +1,105 @@
+/*
+ * 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.main.download;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.apache.camel.CamelConfiguration;
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
+import org.apache.camel.Configuration;
+import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.spi.CamelBeanPostProcessor;
+import org.apache.camel.spi.PackageScanClassResolver;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class BasePackageScanDownloadListener implements ArtifactDownloadListener, CamelContextAware {
+
+    private static final Logger LOG = LoggerFactory.getLogger(BasePackageScanDownloadListener.class);
+
+    private CamelContext camelContext;
+
+    private final Set<String> scanned = new HashSet<>();
+
+    @Override
+    public CamelContext getCamelContext() {
+        return camelContext;
+    }
+
+    @Override
+    public void setCamelContext(CamelContext camelContext) {
+        this.camelContext = camelContext;
+    }
+
+    @Override
+    public void onDownloadedFile(File file) {
+        String basePackage = camelContext.adapt(ExtendedCamelContext.class).getBasePackageScan();
+        if (basePackage != null) {
+            try {
+                basePackageScanConfiguration(basePackage, file);
+            } catch (Exception e) {
+                // ignore
+            }
+        }
+    }
+
+    protected void basePackageScanConfiguration(String basePackage, File file) throws Exception {
+        Collection<CamelConfiguration> configs = new ArrayList<>();
+        // we only want to scan via isolated classloader
+        PackageScanClassResolver pscr = camelContext.adapt(ExtendedCamelContext.class).getPackageScanClassResolver();
+        Set<Class<?>> found1 = pscr.findImplementations(CamelConfiguration.class, basePackage);
+        Set<Class<?>> found2 = pscr.findAnnotated(Configuration.class, basePackage);
+        Set<Class<?>> found = new LinkedHashSet<>();
+        found.addAll(found1);
+        found.addAll(found2);
+        for (Class<?> clazz : found) {
+            // avoid duplicate if we scan other JARs that can same class from previous downloads
+            String fqn = clazz.getName();
+            if (scanned.contains(fqn)) {
+                continue;
+            } else {
+                scanned.add(fqn);
+            }
+
+            // lets use Camel's injector so the class has some support for dependency injection
+            Object config = camelContext.getInjector().newInstance(clazz);
+            if (config instanceof CamelConfiguration) {
+                LOG.debug("Discovered CamelConfiguration class: {}", clazz);
+                CamelConfiguration cc = (CamelConfiguration) config;
+                configs.add(cc);
+            }
+        }
+
+        CamelBeanPostProcessor postProcessor = camelContext.adapt(ExtendedCamelContext.class).getBeanPostProcessor();
+        // prepare the directly configured instances
+        for (Object configuration : configs) {
+            postProcessor.postProcessBeforeInitialization(configuration, configuration.getClass().getName());
+            postProcessor.postProcessAfterInitialization(configuration, configuration.getClass().getName());
+        }
+        // invoke configure on configurations
+        for (CamelConfiguration config : configs) {
+            config.configure(camelContext);
+        }
+    }
+
+}