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/10/20 08:51:02 UTC
[camel] branch camel-3.18.x updated: CAMEL-18624: camel-jbang - Should load custom type converters when adding new JARs
This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch camel-3.18.x
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/camel-3.18.x by this push:
new 4b56d46f609 CAMEL-18624: camel-jbang - Should load custom type converters when adding new JARs
4b56d46f609 is described below
commit 4b56d46f6097d10b2a2a8bc02cd36e2a7672e560
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Thu Oct 20 10:26:02 2022 +0200
CAMEL-18624: camel-jbang - Should load custom type converters when adding new JARs
---
.../java/org/apache/camel/main/KameletMain.java | 7 +-
.../main/download/ArtifactDownloadListener.java | 34 +++++++
.../camel/main/download/DependencyDownloader.java | 5 +
.../main/download/MavenDependencyDownloader.java | 11 +++
.../TypeConverterLoaderDownloadListener.java | 105 +++++++++++++++++++++
5 files changed, 161 insertions(+), 1 deletion(-)
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 e4c71bf1a4e..4be699c531c 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
@@ -43,6 +43,7 @@ import org.apache.camel.main.download.DownloadListener;
import org.apache.camel.main.download.KameletMainInjector;
import org.apache.camel.main.download.KnownDependenciesResolver;
import org.apache.camel.main.download.MavenDependencyDownloader;
+import org.apache.camel.main.download.TypeConverterLoaderDownloadListener;
import org.apache.camel.main.http.VertxHttpServer;
import org.apache.camel.main.injection.AnnotationDependencyInjection;
import org.apache.camel.main.util.ExtraFilesClassLoader;
@@ -266,7 +267,10 @@ public class KameletMain extends MainCommandLineSupport {
DefaultCamelContext answer = new DefaultCamelContext(false);
answer.setLogJvmUptime(true);
if (download) {
- answer.setApplicationContextClassLoader(createApplicationContextClassLoader());
+ ClassLoader dynamicCL = createApplicationContextClassLoader();
+ answer.setApplicationContextClassLoader(dynamicCL);
+ answer.getPackageScanClassResolver().addClassLoader(dynamicCL);
+ answer.getPackageScanResourceResolver().addClassLoader(dynamicCL);
MavenDependencyDownloader downloader = new MavenDependencyDownloader();
downloader.setCamelContext(answer);
@@ -276,6 +280,7 @@ public class KameletMain extends MainCommandLineSupport {
downloader.addDownloadListener(downloadListener);
}
downloader.addDownloadListener(new AutoConfigureDownloadListener());
+ downloader.addArtifactDownloadListener(new TypeConverterLoaderDownloadListener());
// register as extension
try {
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/ArtifactDownloadListener.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/ArtifactDownloadListener.java
new file mode 100644
index 00000000000..619bccbc0b2
--- /dev/null
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/ArtifactDownloadListener.java
@@ -0,0 +1,34 @@
+/*
+ * 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;
+
+/**
+ * Listener for downloading a maven file (can be downloaded from a local cache)
+ */
+@FunctionalInterface
+public interface ArtifactDownloadListener {
+
+ /**
+ * After the artifact has been downloaded
+ *
+ * @param file the downloaded artifact as a file
+ */
+ void onDownloadedFile(File file);
+
+}
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..1bae328e570 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
@@ -29,6 +29,11 @@ public interface DependencyDownloader extends CamelContextAware, StaticService {
*/
void addDownloadListener(DownloadListener downloadListener);
+ /**
+ * Adds a listener to capture download activity
+ */
+ void addArtifactDownloadListener(ArtifactDownloadListener downloadListener);
+
String getRepos();
/**
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 130660862d8..bb95484a3be 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
@@ -48,6 +48,7 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
private DownloadThreadPool threadPool;
private CamelContext camelContext;
private final Set<DownloadListener> downloadListeners = new LinkedHashSet<>();
+ private final Set<ArtifactDownloadListener> artifactDownloadListeners = new LinkedHashSet<>();
private String repos;
private boolean fresh;
@@ -67,6 +68,12 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
downloadListeners.add(downloadListener);
}
+ @Override
+ public void addArtifactDownloadListener(ArtifactDownloadListener downloadListener) {
+ CamelContextAware.trySetCamelContext(downloadListener, getCamelContext());
+ artifactDownloadListeners.add(downloadListener);
+ }
+
@Override
public String getRepos() {
return repos;
@@ -163,6 +170,10 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende
if (!alreadyOnClasspath(a.getGav().getGroupId(), a.getGav().getArtifactId(),
a.getGav().getVersion(), false)) {
classLoader.addFile(file);
+ // trigger listener after downloaded and added to classloader
+ for (ArtifactDownloadListener listener : artifactDownloadListeners) {
+ listener.onDownloadedFile(file);
+ }
LOG.trace("Added classpath: {}", a.getGav());
}
}
diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/TypeConverterLoaderDownloadListener.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/TypeConverterLoaderDownloadListener.java
new file mode 100644
index 00000000000..a713f562fc4
--- /dev/null
+++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/TypeConverterLoaderDownloadListener.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.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
+import org.apache.camel.impl.converter.BaseTypeConverterRegistry;
+import org.apache.camel.spi.TypeConverterLoader;
+import org.apache.camel.util.IOHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TypeConverterLoaderDownloadListener implements ArtifactDownloadListener, CamelContextAware {
+
+ private static final Logger LOG = LoggerFactory.getLogger(TypeConverterLoaderDownloadListener.class);
+
+ private CamelContext camelContext;
+
+ @Override
+ public CamelContext getCamelContext() {
+ return camelContext;
+ }
+
+ @Override
+ public void setCamelContext(CamelContext camelContext) {
+ this.camelContext = camelContext;
+ }
+
+ @Override
+ public void onDownloadedFile(File file) {
+ try {
+ loadTypeConverters(file);
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+
+ protected void loadTypeConverters(File file) throws Exception {
+ // use isolated classloader to load the service file as we only want to check this file
+ // (and not what is already in the existing classloader)
+ DependencyDownloaderClassLoader cl = new DependencyDownloaderClassLoader(null);
+ cl.addFile(file);
+
+ // load names for custom type converters from the downloaded JAR
+ Collection<String> loaders = new ArrayList<>();
+ findTypeConverterLoaderClasses(loaders,
+ cl.getResourceAsStream(BaseTypeConverterRegistry.META_INF_SERVICES_TYPE_CONVERTER_LOADER));
+ findTypeConverterLoaderClasses(loaders,
+ cl.getResourceAsStream(BaseTypeConverterRegistry.META_INF_SERVICES_FALLBACK_TYPE_CONVERTER));
+ loadTypeConverters(loaders);
+ }
+
+ protected void findTypeConverterLoaderClasses(Collection<String> loaders, InputStream is) throws IOException {
+ if (is != null) {
+ BufferedReader reader = IOHelper.buffered(new InputStreamReader(is, StandardCharsets.UTF_8));
+ String line;
+ do {
+ line = reader.readLine();
+ if (line != null && !line.startsWith("#") && !line.isEmpty()) {
+ loaders.add(line);
+ }
+ } while (line != null);
+ IOHelper.close(reader);
+ }
+ }
+
+ protected void loadTypeConverters(Collection<String> loaders) throws ClassNotFoundException {
+ for (String name : loaders) {
+ LOG.debug("Resolving TypeConverterLoader: {}", name);
+ Class<?> clazz = getCamelContext().getClassResolver().resolveMandatoryClass(name);
+ Object obj = getCamelContext().getInjector().newInstance(clazz, false);
+ CamelContextAware.trySetCamelContext(obj, getCamelContext());
+ if (obj instanceof TypeConverterLoader) {
+ TypeConverterLoader loader = (TypeConverterLoader) obj;
+ CamelContextAware.trySetCamelContext(loader, getCamelContext());
+ LOG.debug("TypeConverterLoader: {} loading converters", name);
+ loader.load(getCamelContext().getTypeConverterRegistry());
+ }
+ }
+ }
+
+}