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 <[email protected]> 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); + } + } + +}
