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 2021/04/01 13:33:14 UTC

[camel] branch master updated (1fa7369 -> df11cff)

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

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


    from 1fa7369  CAMEL-16185 - AWS S3: improve multipart support - streaming upload
     new 64c5464  CAMEL-16419: camel-maven-plugin - Add prepare-fatjar goal for better support of packaging Camel JARs to a fat-jar
     new df11cff  CAMEL-16419: camel-maven-plugin - Add prepare-fatjar goal for better support of packaging Camel JARs to a fat-jar

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../impl/converter/BaseTypeConverterRegistry.java  |  22 +-
 .../src/main/docs/camel-maven-plugin.adoc          |  74 ++++++
 .../org/apache/camel/maven/DynamicClassLoader.java |  25 +-
 .../org/apache/camel/maven/PrepareFatJarMojo.java  | 262 +++++++++++++++++++++
 4 files changed, 366 insertions(+), 17 deletions(-)
 copy components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/Defaults.java => tooling/maven/camel-maven-plugin/src/main/java/org/apache/camel/maven/DynamicClassLoader.java (56%)
 create mode 100644 tooling/maven/camel-maven-plugin/src/main/java/org/apache/camel/maven/PrepareFatJarMojo.java

[camel] 01/02: CAMEL-16419: camel-maven-plugin - Add prepare-fatjar goal for better support of packaging Camel JARs to a fat-jar

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 64c5464181f716a35f868c98bab991801c3bc6d9
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Thu Apr 1 15:22:12 2021 +0200

    CAMEL-16419: camel-maven-plugin - Add prepare-fatjar goal for better support of packaging Camel JARs to a fat-jar
---
 .../impl/converter/BaseTypeConverterRegistry.java  |  22 +-
 .../org/apache/camel/maven/DynamicClassLoader.java |  40 ++++
 .../org/apache/camel/maven/PrepareFatJarMojo.java  | 262 +++++++++++++++++++++
 3 files changed, 317 insertions(+), 7 deletions(-)

diff --git a/core/camel-base/src/main/java/org/apache/camel/impl/converter/BaseTypeConverterRegistry.java b/core/camel-base/src/main/java/org/apache/camel/impl/converter/BaseTypeConverterRegistry.java
index 15b7c26..3c0396b 100644
--- a/core/camel-base/src/main/java/org/apache/camel/impl/converter/BaseTypeConverterRegistry.java
+++ b/core/camel-base/src/main/java/org/apache/camel/impl/converter/BaseTypeConverterRegistry.java
@@ -51,6 +51,8 @@ import org.slf4j.LoggerFactory;
  */
 public abstract class BaseTypeConverterRegistry extends CoreTypeConverterRegistry {
 
+    private static final String META_INF_SERVICES_UBER_TYPE_CONVERTER_LOADER
+            = "META-INF/services/org/apache/camel/UberTypeConverterLoader";
     public static final String META_INF_SERVICES_TYPE_CONVERTER_LOADER
             = "META-INF/services/org/apache/camel/TypeConverterLoader";
     public static final String META_INF_SERVICES_FALLBACK_TYPE_CONVERTER
@@ -171,14 +173,21 @@ public abstract class BaseTypeConverterRegistry extends CoreTypeConverterRegistr
 
     /**
      * Finds the type converter loader classes from the classpath looking for text files on the classpath at the
-     * {@link #META_INF_SERVICES_TYPE_CONVERTER_LOADER} location.
+     * {@link #META_INF_SERVICES_UBER_TYPE_CONVERTER_LOADER} and {@link #META_INF_SERVICES_TYPE_CONVERTER_LOADER}
+     * locations.
      */
     protected Collection<String> findTypeConverterLoaderClasses() throws IOException {
-        Set<String> loaders = new LinkedHashSet<>();
-        Collection<URL> loaderResources = getLoaderUrls();
+        Collection<String> loaders = new LinkedHashSet<>();
+        findTypeConverterLoaderClasses(loaders, META_INF_SERVICES_UBER_TYPE_CONVERTER_LOADER);
+        findTypeConverterLoaderClasses(loaders, META_INF_SERVICES_TYPE_CONVERTER_LOADER);
+        return loaders;
+    }
+
+    protected void findTypeConverterLoaderClasses(Collection<String> loaders, String basePath) throws IOException {
+        Collection<URL> loaderResources = getLoaderUrls(basePath);
         for (URL url : loaderResources) {
             LOG.debug("Loading file {} to retrieve list of type converters, from url: {}",
-                    META_INF_SERVICES_TYPE_CONVERTER_LOADER, url);
+                    basePath, url);
             BufferedReader reader = IOHelper.buffered(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8));
             String line;
             do {
@@ -189,13 +198,12 @@ public abstract class BaseTypeConverterRegistry extends CoreTypeConverterRegistr
             } while (line != null);
             IOHelper.close(reader);
         }
-        return loaders;
     }
 
-    protected Collection<URL> getLoaderUrls() throws IOException {
+    protected Collection<URL> getLoaderUrls(String basePath) throws IOException {
         List<URL> loaderResources = new ArrayList<>();
         for (ClassLoader classLoader : resolver.getClassLoaders()) {
-            Enumeration<URL> resources = classLoader.getResources(META_INF_SERVICES_TYPE_CONVERTER_LOADER);
+            Enumeration<URL> resources = classLoader.getResources(basePath);
             while (resources.hasMoreElements()) {
                 URL url = resources.nextElement();
                 loaderResources.add(url);
diff --git a/tooling/maven/camel-maven-plugin/src/main/java/org/apache/camel/maven/DynamicClassLoader.java b/tooling/maven/camel-maven-plugin/src/main/java/org/apache/camel/maven/DynamicClassLoader.java
new file mode 100644
index 0000000..5d9d669
--- /dev/null
+++ b/tooling/maven/camel-maven-plugin/src/main/java/org/apache/camel/maven/DynamicClassLoader.java
@@ -0,0 +1,40 @@
+/*
+ * 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.maven;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Iterator;
+import java.util.List;
+
+class DynamicClassLoader extends URLClassLoader {
+
+    public DynamicClassLoader(URL[] urls, ClassLoader parent) {
+        super(urls, parent);
+    }
+
+    public static DynamicClassLoader createDynamicClassLoaderFromUrls(List<URL> classpathElements) {
+        final URL[] urls = new URL[classpathElements.size()];
+        int i = 0;
+        for (Iterator<URL> it = classpathElements.iterator(); it.hasNext(); i++) {
+            urls[i] = it.next();
+        }
+        // no parent classloader as we only want to load from the given URLs
+        return new DynamicClassLoader(urls, null);
+    }
+
+}
diff --git a/tooling/maven/camel-maven-plugin/src/main/java/org/apache/camel/maven/PrepareFatJarMojo.java b/tooling/maven/camel-maven-plugin/src/main/java/org/apache/camel/maven/PrepareFatJarMojo.java
new file mode 100644
index 0000000..8a3d43e
--- /dev/null
+++ b/tooling/maven/camel-maven-plugin/src/main/java/org/apache/camel/maven/PrepareFatJarMojo.java
@@ -0,0 +1,262 @@
+/*
+ * 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.maven;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.factory.ArtifactFactory;
+import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
+import org.apache.maven.artifact.resolver.filter.ExcludesArtifactFilter;
+import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
+import org.apache.maven.artifact.versioning.VersionRange;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.Exclusion;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.Component;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.plugins.annotations.ResolutionScope;
+import org.apache.maven.project.MavenProject;
+
+@Mojo(name = "prepare-fatjar", threadSafe = true, requiresDependencyResolution = ResolutionScope.COMPILE,
+      defaultPhase = LifecyclePhase.PREPARE_PACKAGE)
+public class PrepareFatJarMojo extends AbstractMojo {
+
+    private static final String GENERATED_MSG = "Generated by camel build tools - do NOT edit this file!";
+    private static final String NL = "\n";
+
+    private static final String META_INF_SERVICES_TYPE_CONVERTER_LOADER
+            = "META-INF/services/org/apache/camel/TypeConverterLoader";
+
+    private static final String META_INF_SERVICES_UBER_TYPE_CONVERTER_LOADER
+            = "META-INF/services/org/apache/camel/UberTypeConverterLoader";
+
+    private DynamicClassLoader projectClassLoader;
+
+    @Parameter(property = "project", required = true, readonly = true)
+    private MavenProject project;
+    @Parameter(defaultValue = "${project.build.outputDirectory}")
+    private File classesDirectory;
+    @Component
+    private ArtifactFactory artifactFactory;
+
+    @Override
+    public void execute() throws MojoExecutionException, MojoFailureException {
+        Collection<String> loaders = findTypeConverterLoaderClasses();
+        if (loaders.isEmpty()) {
+            return;
+        }
+
+        getLog().info("Found " + loaders.size() + " Camel type converter loaders from project classpath");
+
+        // prepare output to generate
+        StringBuilder sb = new StringBuilder();
+        sb.append("# ");
+        sb.append(GENERATED_MSG);
+        sb.append(NL);
+        sb.append(String.join(NL, loaders));
+        sb.append(NL);
+
+        String data = sb.toString();
+
+        File file = new File(classesDirectory, META_INF_SERVICES_UBER_TYPE_CONVERTER_LOADER);
+        try {
+            writeFile(file, data);
+        } catch (IOException e) {
+            throw new MojoFailureException("Error updating " + file, e);
+        }
+    }
+
+    private void writeFile(File file, String data) throws IOException {
+        Path path = file.toPath();
+        Files.createDirectories(path.getParent());
+        Files.write(path, data.getBytes(StandardCharsets.UTF_8), StandardOpenOption.WRITE, StandardOpenOption.CREATE,
+                StandardOpenOption.TRUNCATE_EXISTING);
+    }
+
+    /**
+     * Finds the type converter loader classes from the classpath looking for text files on the classpath at the
+     * {@link #META_INF_SERVICES_TYPE_CONVERTER_LOADER} location.
+     */
+    protected Collection<String> findTypeConverterLoaderClasses() {
+        Set<String> loaders = new LinkedHashSet<>();
+
+        try {
+            Enumeration<URL> loaderResources = getProjectClassLoader().getResources(META_INF_SERVICES_TYPE_CONVERTER_LOADER);
+            while (loaderResources.hasMoreElements()) {
+                URL url = loaderResources.nextElement();
+                getLog().debug("Loading file " + META_INF_SERVICES_TYPE_CONVERTER_LOADER
+                               + " to retrieve list of type converters, from url: " + url);
+                BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8));
+                String line;
+                do {
+                    line = reader.readLine();
+                    if (line != null && !line.startsWith("#") && !line.isEmpty()) {
+                        loaders.add(line);
+                    }
+                } while (line != null);
+                try {
+                    reader.close();
+                } catch (Exception e) {
+                    // ignore
+                }
+            }
+        } catch (Exception e) {
+            getLog().warn("Error finding type converters due to " + e.getMessage());
+        }
+
+        return loaders;
+    }
+
+    protected final DynamicClassLoader getProjectClassLoader() throws MojoExecutionException {
+        if (projectClassLoader == null) {
+            List<URL> urls = new ArrayList<>();
+            // need to include project compile dependencies (code similar to camel-maven-plugin)
+            addRelevantProjectDependenciesToClasspath(urls, false);
+            projectClassLoader = DynamicClassLoader.createDynamicClassLoaderFromUrls(urls);
+        }
+        return projectClassLoader;
+    }
+
+    /**
+     * Add any relevant project dependencies to the classpath. Takes includeProjectDependencies into consideration.
+     *
+     * @param path classpath of {@link URL} objects
+     */
+    private void addRelevantProjectDependenciesToClasspath(List<URL> path, boolean testClasspathOnly)
+            throws MojoExecutionException {
+        try {
+            getLog().debug("Project Dependencies will be included.");
+
+            if (testClasspathOnly) {
+                URL testClasses = new File(project.getBuild().getTestOutputDirectory()).toURI().toURL();
+                getLog().debug("Adding to classpath : " + testClasses);
+                path.add(testClasses);
+            } else {
+                URL mainClasses = new File(project.getBuild().getOutputDirectory()).toURI().toURL();
+                getLog().debug("Adding to classpath : " + mainClasses);
+                path.add(mainClasses);
+            }
+
+            Set<Artifact> dependencies = project.getArtifacts();
+
+            // system scope dependencies are not returned by maven 2.0. See
+            // MEXEC-17
+            dependencies.addAll(getAllNonTestScopedDependencies());
+
+            Iterator<Artifact> iter = dependencies.iterator();
+            while (iter.hasNext()) {
+                Artifact classPathElement = iter.next();
+                getLog().debug("Adding project dependency artifact: " + classPathElement.getArtifactId()
+                               + " to classpath");
+                File file = classPathElement.getFile();
+                if (file != null) {
+                    path.add(file.toURI().toURL());
+                }
+            }
+
+        } catch (MalformedURLException e) {
+            throw new MojoExecutionException("Error during setting up classpath", e);
+        }
+    }
+
+    private Collection<Artifact> getAllNonTestScopedDependencies() throws MojoExecutionException {
+        List<Artifact> answer = new ArrayList<>();
+
+        for (Artifact artifact : getAllDependencies()) {
+
+            // do not add test artifacts
+            if (!artifact.getScope().equals(Artifact.SCOPE_TEST)) {
+                answer.add(artifact);
+            }
+        }
+        return answer;
+    }
+
+    // generic method to retrieve all the transitive dependencies
+    private Collection<Artifact> getAllDependencies() throws MojoExecutionException {
+        List<Artifact> artifacts = new ArrayList<>();
+
+        for (Iterator<?> dependencies = project.getDependencies().iterator(); dependencies.hasNext();) {
+            Dependency dependency = (Dependency) dependencies.next();
+
+            String groupId = dependency.getGroupId();
+            String artifactId = dependency.getArtifactId();
+
+            VersionRange versionRange;
+            try {
+                versionRange = VersionRange.createFromVersionSpec(dependency.getVersion());
+            } catch (InvalidVersionSpecificationException e) {
+                throw new MojoExecutionException("unable to parse version", e);
+            }
+
+            String type = dependency.getType();
+            if (type == null) {
+                type = "jar";
+            }
+            String classifier = dependency.getClassifier();
+            boolean optional = dependency.isOptional();
+            String scope = dependency.getScope();
+            if (scope == null) {
+                scope = Artifact.SCOPE_COMPILE;
+            }
+
+            if (this.artifactFactory != null) {
+                Artifact art = this.artifactFactory.createDependencyArtifact(groupId, artifactId, versionRange,
+                        type, classifier, scope, null, optional);
+
+                if (scope.equalsIgnoreCase(Artifact.SCOPE_SYSTEM)) {
+                    art.setFile(new File(dependency.getSystemPath()));
+                }
+
+                List<String> exclusions = new ArrayList<>();
+                for (Exclusion exclusion : dependency.getExclusions()) {
+                    exclusions.add(exclusion.getGroupId() + ":" + exclusion.getArtifactId());
+                }
+
+                ArtifactFilter newFilter = new ExcludesArtifactFilter(exclusions);
+
+                art.setDependencyFilter(newFilter);
+
+                artifacts.add(art);
+            }
+        }
+
+        return artifacts;
+    }
+
+}

[camel] 02/02: CAMEL-16419: camel-maven-plugin - Add prepare-fatjar goal for better support of packaging Camel JARs to a fat-jar

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit df11cff73565b537d91111c07f612285e64a71f2
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Thu Apr 1 15:31:34 2021 +0200

    CAMEL-16419: camel-maven-plugin - Add prepare-fatjar goal for better support of packaging Camel JARs to a fat-jar
---
 .../src/main/docs/camel-maven-plugin.adoc          | 74 ++++++++++++++++++++++
 1 file changed, 74 insertions(+)

diff --git a/tooling/maven/camel-maven-plugin/src/main/docs/camel-maven-plugin.adoc b/tooling/maven/camel-maven-plugin/src/main/docs/camel-maven-plugin.adoc
index fff2323..227faa0 100644
--- a/tooling/maven/camel-maven-plugin/src/main/docs/camel-maven-plugin.adoc
+++ b/tooling/maven/camel-maven-plugin/src/main/docs/camel-maven-plugin.adoc
@@ -3,6 +3,7 @@
 The Camel Maven Plugin supports the following goals
 
  - camel:run - To run your Camel application
+ - camel:prepare-fatjar - To prepare your Camel application for being packaged as a fat-jar (such as by maven-assembly-plugin)
 
 == camel:run
 
@@ -138,3 +139,76 @@ Then the plugin watches this directory. This allows you to edit the source code
 Notice its only changes of Camel routes, eg `<routes>`, or `<route>` which is supported.
 You cannot change Spring or OSGi Blueprint `<bean>` elements.
 
+
+== camel:prepare-fatjar
+
+The `camel:prepare-fatjar` goal of the Camel Maven Plugin is used to prepare your Camel application
+for being packaged as a _fat jar_. The goal scans the Maven dependencies to discover Camel JARs and
+extract if they have type converters, which gets merged together into a single _uber_ file stored
+in `target/classes/META-INF/services/org/apache/camel/UberTypeConverterLoader`.
+
+This _uber_ loader file contains all the combined type converters the Camel application uses at runtime.
+They are merged together into this single file.
+
+This is needed as otherwise the _fat jar_ maven plugins (such as maven-assembly-plugin, or maven-shade-plugin)
+causes the `TypeConverterLoader` files to be overwritten in the assembled JAR which causes not all type converters
+to be loaded by Camel.
+
+The `UberTypeConverterLoader` ensures they all type converters gets loaded as this file contains all the known
+type converter files.
+
+To use this goal, you can add the following to your Camel application `pom.xml` file:
+
+[source,xml]
+----
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>camel-maven-plugin</artifactId>
+        <version>${camel.version}</version>
+        <executions>
+          <execution>
+            <goals>
+              <goal>prepare-fatjar</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+----
+
+For example to use this with the `maven-assembly-plugin` you can do as below.
+Remember to specify the class name of *your* main class where it says `com.foo.NameOfMainClass`:
+
+[source,xml]
+----
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>camel-maven-plugin</artifactId>
+        <version>${camel.version}</version>
+        <executions>
+          <execution>
+            <goals>
+              <goal>prepare-fatjar</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-assembly-plugin</artifactId>
+        <configuration>
+          <archive>
+            <manifest>
+              <mainClass>com.foo.NameOfMainClass</mainClass>
+            </manifest>
+          </archive>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+----