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 0940f345ab6 CAMEL-18204: camel-jbang - Export to quarkus should use quarkus catalog to know if the JARs are an extension or not to generate correct pom.xml 0940f345ab6 is described below commit 0940f345ab67cd4a2a93a4abb652f17f37632af4 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Tue Jun 21 12:31:18 2022 +0200 CAMEL-18204: camel-jbang - Export to quarkus should use quarkus catalog to know if the JARs are an extension or not to generate correct pom.xml --- .../dsl/jbang/core/commands/ExportQuarkus.java | 110 ++++++++++++++++++++- .../camel/dsl/jbang/core/common/XmlHelper.java | 58 +++++++++++ .../camel/main/download/DependencyDownloader.java | 22 ++++- .../main/download/MavenDependencyDownloader.java | 36 ++++++- 4 files changed, 221 insertions(+), 5 deletions(-) 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 8146be4ebb1..e9badb96529 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 @@ -22,7 +22,22 @@ import java.io.FileOutputStream; import java.io.InputStream; import java.util.Set; +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.catalog.CamelCatalog; +import org.apache.camel.catalog.DefaultCamelCatalog; +import org.apache.camel.catalog.RuntimeProvider; +import org.apache.camel.dsl.jbang.core.common.XmlHelper; +import org.apache.camel.main.KameletMain; +import org.apache.camel.main.download.MavenArtifact; +import org.apache.camel.main.download.MavenDependencyDownloader; import org.apache.camel.main.download.MavenGav; +import org.apache.camel.tooling.model.ArtifactModel; import org.apache.camel.util.FileUtil; import org.apache.camel.util.IOHelper; import org.apache.camel.util.OrderedProperties; @@ -30,6 +45,12 @@ import org.apache.commons.io.FileUtils; class ExportQuarkus extends Export { + private static final String DEFAULT_CAMEL_CATALOG = "org.apache.camel.catalog.DefaultCamelCatalog"; + private static final String QUARKUS_CATALOG_PROVIDER = "org.apache.camel.catalog.quarkus.QuarkusRuntimeProvider"; + + private String camelVersion = null; + private String camelQuarkusVersion = null; + public ExportQuarkus(CamelJBangMain main) { super(main); } @@ -129,11 +150,17 @@ class ExportQuarkus extends Export { String context = IOHelper.loadText(is); IOHelper.close(is); + CamelCatalog catalog = loadQuarkusCatalog(); + if (camelVersion == null) { + camelVersion = catalog.getCatalogVersion(); + } + context = context.replaceFirst("\\{\\{ \\.GroupId }}", ids[0]); context = context.replaceFirst("\\{\\{ \\.ArtifactId }}", ids[1]); context = context.replaceFirst("\\{\\{ \\.Version }}", ids[2]); context = context.replaceAll("\\{\\{ \\.QuarkusVersion }}", quarkusVersion); context = context.replaceFirst("\\{\\{ \\.JavaVersion }}", javaVersion); + context = context.replaceFirst("\\{\\{ \\.CamelVersion }}", camelVersion); OrderedProperties prop = new OrderedProperties(); prop.load(new FileInputStream(settings)); @@ -162,9 +189,17 @@ class ExportQuarkus extends Export { String v = gav.getVersion(); // transform to camel-quarkus extension GAV if ("org.apache.camel".equals(gid)) { - gid = "org.apache.camel.quarkus"; - aid = aid.replace("camel-", "camel-quarkus-"); - v = null; + String qaid = aid.replace("camel-", "camel-quarkus-"); + ArtifactModel<?> am = catalog.modelFromMavenGAV("org.apache.camel.quarkus", qaid, null); + if (am != null) { + // use quarkus extension + gid = am.getGroupId(); + aid = am.getArtifactId(); + v = null; // uses BOM so version should not be included + } else { + // there is no quarkus extension so use plain camel + v = camelVersion; + } } sb.append(" <dependency>\n"); sb.append(" <groupId>").append(gid).append("</groupId>\n"); @@ -191,4 +226,73 @@ class ExportQuarkus extends Export { return answer; } + private CamelCatalog loadQuarkusCatalog() { + CamelCatalog answer = new DefaultCamelCatalog(true); + + // use kamelet-main to dynamic download dependency via maven + KameletMain main = new KameletMain(); + try { + main.start(); + + // shrinkwrap does not return POM file as result (they are hardcoded to be filtered out) + // so after this we download a JAR and then use its File location to compute the file for the downloaded POM + MavenDependencyDownloader downloader = main.getCamelContext().hasService(MavenDependencyDownloader.class); + downloader.downloadArtifact("io.quarkus.platform", "quarkus-camel-bom:pom", quarkusVersion); + MavenArtifact ma = downloader.downloadArtifact("io.quarkus", "quarkus-core", quarkusVersion); + if (ma != null && ma.getFile() != null) { + String name = ma.getFile().getAbsolutePath(); + name = name.replace("io/quarkus/quarkus-core", "io/quarkus/platform/quarkus-camel-bom"); + name = name.replace("quarkus-core", "quarkus-camel-bom"); + name = name.replace(".jar", ".pom"); + File file = new File(name); + if (file.exists()) { + DocumentBuilderFactory dbf = XmlHelper.createDocumentBuilderFactory(); + DocumentBuilder db = dbf.newDocumentBuilder(); + Document dom = db.parse(file); + + // grab what exact camelVersion and camelQuarkusVersion we are using + NodeList nl = dom.getElementsByTagName("dependency"); + for (int i = 0; i < nl.getLength(); i++) { + Element node = (Element) nl.item(i); + String g = node.getElementsByTagName("groupId").item(0).getTextContent(); + String a = node.getElementsByTagName("artifactId").item(0).getTextContent(); + if ("org.apache.camel".equals(g) && "camel-core-engine".equals(a)) { + camelVersion = node.getElementsByTagName("version").item(0).getTextContent(); + } else if ("org.apache.camel.quarkus".equals(g) && "camel-quarkus-catalog".equals(a)) { + camelQuarkusVersion = node.getElementsByTagName("version").item(0).getTextContent(); + } + } + } + } + + if (camelQuarkusVersion != null) { + // download camel-quarkus-catalog we use to know if we have an extension or not + downloader.downloadDependency("org.apache.camel.quarkus", "camel-quarkus-catalog", camelQuarkusVersion); + + Class<RuntimeProvider> clazz = main.getCamelContext().getClassResolver().resolveClass(QUARKUS_CATALOG_PROVIDER, + RuntimeProvider.class); + if (clazz != null) { + RuntimeProvider provider = main.getCamelContext().getInjector().newInstance(clazz); + if (provider != null) { + // re-create answer with the classloader that loaded spring-boot to be able to load resources in this catalog + Class<CamelCatalog> clazz2 + = main.getCamelContext().getClassResolver().resolveClass(DEFAULT_CAMEL_CATALOG, + CamelCatalog.class); + answer = main.getCamelContext().getInjector().newInstance(clazz2); + answer.setRuntimeProvider(provider); + // use classloader that loaded spring-boot provider to ensure we can load its resources + answer.getVersionManager().setClassLoader(main.getCamelContext().getApplicationContextClassLoader()); + answer.enableCache(); + } + } + } + } catch (Exception e) { + // ignore + } finally { + main.stop(); + } + + return answer; + } + } diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/XmlHelper.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/XmlHelper.java new file mode 100644 index 00000000000..afc58f99cd9 --- /dev/null +++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/XmlHelper.java @@ -0,0 +1,58 @@ +/* + * 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.common; + +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.camel.util.ObjectHelper; + +public final class XmlHelper { + + private XmlHelper() { + } + + public static DocumentBuilderFactory createDocumentBuilderFactory() { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + factory.setIgnoringElementContentWhitespace(true); + factory.setIgnoringComments(true); + try { + // Set secure processing + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE); + } catch (ParserConfigurationException e) { + } + try { + // Disable the external-general-entities by default + factory.setFeature("http://xml.org/sax/features/external-general-entities", false); + } catch (ParserConfigurationException e) { + } + // setup the SecurityManager by default if it's apache xerces + try { + Class<?> smClass = ObjectHelper.loadClass("org.apache.xerces.util.SecurityManager"); + if (smClass != null) { + Object sm = smClass.getDeclaredConstructor().newInstance(); + // Here we just use the default setting of the SeurityManager + factory.setAttribute("http://apache.org/xml/properties/security-manager", sm); + } + } catch (Exception e) { + } + return factory; + } + +} 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 5823a85dbf0..153ac0d3050 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 @@ -46,7 +46,7 @@ public interface DependencyDownloader extends CamelContextAware, StaticService { void setFresh(boolean fresh); /** - * Downloads the dependency + * Downloads the dependency incl transitive dependencies * * @param groupId maven group id * @param artifactId maven artifact id @@ -54,6 +54,26 @@ public interface DependencyDownloader extends CamelContextAware, StaticService { */ void downloadDependency(String groupId, String artifactId, String version); + /** + * Downloads the dependency + * + * @param groupId maven group id + * @param artifactId maven artifact id + * @param version maven version + * @param transitively whether to include transitive dependencies + */ + void downloadDependency(String groupId, String artifactId, String version, boolean transitively); + + /** + * Downloads a single maven artifact (no transitive dependencies) + * + * @param groupId maven group id + * @param artifactId maven artifact id + * @param version maven version + * @return the artifact, or null if none found + */ + MavenArtifact downloadArtifact(String groupId, String artifactId, String version); + /** * Checks whether the dependency is already on the classpath * 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 1e11eae6ddb..cb1c5261743 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 @@ -89,6 +89,11 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende @Override public void downloadDependency(String groupId, String artifactId, String version) { + downloadDependency(groupId, artifactId, version, true); + } + + @Override + public void downloadDependency(String groupId, String artifactId, String version, boolean transitively) { // trigger listener if (downloadListener != null) { downloadListener.onDownloadDependency(groupId, artifactId, version); @@ -132,7 +137,7 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende } List<MavenArtifact> artifacts - = MavenDependencyResolver.resolveDependenciesViaAether(deps, mavenRepos, false, fresh, true); + = MavenDependencyResolver.resolveDependenciesViaAether(deps, mavenRepos, false, fresh, transitively); LOG.debug("Resolved {} -> [{}]", gav, artifacts); DependencyDownloaderClassLoader classLoader @@ -149,6 +154,35 @@ public class MavenDependencyDownloader extends ServiceSupport implements Depende }, 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<String> mavenRepos = new ArrayList<>(); + + // add maven central first + mavenRepos.add(MAVEN_CENTRAL_REPO); + // and custom repos + if (repos != null) { + mavenRepos.addAll(Arrays.stream(repos.split(",")).collect(Collectors.toList())); + } + // include Apache snapshot to make it easy to use upcoming releases + if ("org.apache.camel".equals(groupId) && version.contains("SNAPSHOT")) { + mavenRepos.add(APACHE_SNAPSHOT_REPO); + } + + List<MavenArtifact> artifacts + = MavenDependencyResolver.resolveDependenciesViaAether(deps, mavenRepos, false, fresh, false); + LOG.debug("Resolved {} -> [{}]", gav, artifacts); + + if (artifacts.size() == 1) { + return artifacts.get(0); + } + + return null; + } + public boolean alreadyOnClasspath(String groupId, String artifactId, String version) { return alreadyOnClasspath(groupId, artifactId, version, true); }