[maven-jlink-plugin] branch MJLINK-36 updated (8e99a1e -> e289a05)

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

[maven-jlink-plugin] branch MJLINK-36 updated (8e99a1e -> e289a05)

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

slachiewicz pushed a change to branch MJLINK-36
in repository https://gitbox.apache.org/repos/asf/maven-jlink-plugin.git.


    from 8e99a1e  [MJLINK-36] update maven to 3.1.1
     new edaa976  [MJLINK-36] Java9 ToolProvider via multi-release jar.
     new 73c4f02  [MJLINK-36] remove looking for jlink in JAVA_HOME etc. for Java 8.
     new d59574f  [MJLINK-36] update javadoc, simplifly Optional use.
     new 4c79bec  [MJLINK-36] skip unnecessary jlinkArgsFile.
     new e289a05  [MJLINK-36] Toolchain must always win. Add toolchain tests.

The 5 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:
 pom.xml                                            |  47 +++++
 .../invoker.properties                             |   3 +-
 .../pom.xml                                        |  28 ++-
 .../invoker.properties                             |   3 +-
 .../pom.xml                                        |  28 ++-
 .../MJLINK-40_includeLocales/verify.groovy         |  16 +-
 .../maven/plugins/jlink/AbstractJLinkExecutor.java |  63 +++++++
 .../maven/plugins/jlink/AbstractJLinkMojo.java     | 154 +---------------
 .../jlink/AbstractJLinkToolchainExecutor.java      | 204 +++++++++++++++++++++
 .../apache/maven/plugins/jlink/JLinkExecutor.java} |  24 +--
 .../org/apache/maven/plugins/jlink/JLinkMojo.java  | 160 ++++++----------
 .../apache/maven/plugins/jlink/JLinkExecutor.java  | 143 +++++++++++++++
 12 files changed, 589 insertions(+), 284 deletions(-)
 copy src/it/projects/{MJLINK-40_includeLocales => MJLINK-36_toolchainjdk8}/invoker.properties (92%)
 copy src/it/projects/{MJLINK-40_includeLocales => MJLINK-36_toolchainjdk8}/pom.xml (81%)
 copy src/it/projects/{MJLINK-40_includeLocales => MJLINK-36_toolchainjdk9}/invoker.properties (93%)
 copy src/it/projects/{MJLINK-40_includeLocales => MJLINK-36_toolchainjdk9}/pom.xml (81%)
 create mode 100644 src/main/java/org/apache/maven/plugins/jlink/AbstractJLinkExecutor.java
 create mode 100644 src/main/java/org/apache/maven/plugins/jlink/AbstractJLinkToolchainExecutor.java
 copy src/{it/projects/MJLINK-6_allowSetJmodPath/src/main/java/com/corporate/project/Main.java => main/java/org/apache/maven/plugins/jlink/JLinkExecutor.java} (68%)
 create mode 100644 src/main/java9/org/apache/maven/plugins/jlink/JLinkExecutor.java

Reply | Threaded
Open this post in threaded view
|

[maven-jlink-plugin] 01/05: [MJLINK-36] Java9 ToolProvider via multi-release jar.

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

slachiewicz pushed a commit to branch MJLINK-36
in repository https://gitbox.apache.org/repos/asf/maven-jlink-plugin.git

commit edaa976069a5457074a29dbec90d3573afd6740b
Author: Benjamin Marwell <[hidden email]>
AuthorDate: Fri Nov 13 21:23:30 2020 +0100

    [MJLINK-36] Java9 ToolProvider via multi-release jar.
---
 pom.xml                                            |  47 ++++++
 .../maven/plugins/jlink/AbstractJLinkExecutor.java |  72 +++++++++
 .../maven/plugins/jlink/AbstractJLinkMojo.java     | 149 +-----------------
 .../apache/maven/plugins/jlink/JLinkExecutor.java  | 171 ++++++++++++++++++++
 .../org/apache/maven/plugins/jlink/JLinkMojo.java  |  67 +++-----
 .../apache/maven/plugins/jlink/JLinkExecutor.java  | 175 +++++++++++++++++++++
 6 files changed, 493 insertions(+), 188 deletions(-)

diff --git a/pom.xml b/pom.xml
index da94e29..45e7acc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -199,6 +199,53 @@
   </reporting>
   <profiles>
     <profile>
+      <id>jdk9</id>
+      <activation>
+        <jdk>[9,)</jdk>
+      </activation>
+      <build>
+        <pluginManagement>
+          <plugins>
+            <plugin>
+              <groupId>org.apache.maven.plugins</groupId>
+              <artifactId>maven-compiler-plugin</artifactId>
+              <executions>
+                <execution>
+                  <id>jdk9</id>
+                  <goals>
+                    <goal>compile</goal>
+                  </goals>
+                  <configuration>
+                    <release>9</release>
+                    <multiReleaseOutput>true</multiReleaseOutput>
+                    <compileSourceRoots>
+                      <compileSourceRoot>${project.basedir}/src/main/java9</compileSourceRoot>
+                    </compileSourceRoots>
+                  </configuration>
+                </execution>
+              </executions>
+            </plugin>
+            <plugin>
+              <groupId>org.apache.maven.plugins</groupId>
+              <artifactId>maven-jar-plugin</artifactId>
+              <executions>
+                <execution>
+                  <id>default-jar</id>
+                  <configuration>
+                    <archive>
+                      <manifestEntries>
+                        <Multi-Release>true</Multi-Release>
+                      </manifestEntries>
+                    </archive>
+                  </configuration>
+                </execution>
+              </executions>
+            </plugin>
+          </plugins>
+        </pluginManagement>
+      </build>
+    </profile>
+    <profile>
       <id>run-its</id>
       <build>
         <plugins>
diff --git a/src/main/java/org/apache/maven/plugins/jlink/AbstractJLinkExecutor.java b/src/main/java/org/apache/maven/plugins/jlink/AbstractJLinkExecutor.java
new file mode 100644
index 0000000..16864b6
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugins/jlink/AbstractJLinkExecutor.java
@@ -0,0 +1,72 @@
+package org.apache.maven.plugins.jlink;
+
+/*
+ * 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.
+ */
+
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.toolchain.Toolchain;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+
+abstract class AbstractJLinkExecutor
+{
+    protected static final String JMODS = "jmods";
+
+    private final Toolchain toolchain;
+    private final Log log;
+
+    private final List<String> modulesToAdd = new ArrayList<>();
+    private final List<String> modulePaths = new ArrayList<>();
+
+    AbstractJLinkExecutor( Toolchain toolchain, Log log ) throws IOException
+    {
+        this.toolchain = toolchain;
+        this.log = log;
+    }
+
+    protected Toolchain getToolchain()
+    {
+        return this.toolchain;
+    }
+
+    protected Log getLog()
+    {
+        return this.log;
+    }
+
+    public abstract Optional<File> getJmodsFolder( /* nullable */ File sourceJdkModules );
+
+    public abstract int executeJlink( File argsFile ) throws MojoExecutionException;
+
+    public void addAllModules( Collection<String> modulesToAdd )
+    {
+        this.modulesToAdd.addAll( modulesToAdd );
+    }
+
+    public void addAllModulePaths( Collection<String> pathsOfModules )
+    {
+        this.modulePaths.addAll( pathsOfModules );
+    }
+}
diff --git a/src/main/java/org/apache/maven/plugins/jlink/AbstractJLinkMojo.java b/src/main/java/org/apache/maven/plugins/jlink/AbstractJLinkMojo.java
index 39e32ac..7443b76 100644
--- a/src/main/java/org/apache/maven/plugins/jlink/AbstractJLinkMojo.java
+++ b/src/main/java/org/apache/maven/plugins/jlink/AbstractJLinkMojo.java
@@ -25,21 +25,14 @@ import java.lang.reflect.Method;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
-import java.util.Properties;
 
-import org.apache.commons.lang3.SystemUtils;
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.plugin.AbstractMojo;
-import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugins.annotations.Component;
 import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.toolchain.Toolchain;
 import org.apache.maven.toolchain.ToolchainManager;
-import org.codehaus.plexus.util.StringUtils;
-import org.codehaus.plexus.util.cli.CommandLineException;
-import org.codehaus.plexus.util.cli.CommandLineUtils;
-import org.codehaus.plexus.util.cli.Commandline;
 
 /**
  * @author Karl Heinz Marbaise <a href="mailto:[hidden email]">[hidden email]</a>
@@ -66,136 +59,10 @@ public abstract class AbstractJLinkMojo
     @Component
     private ToolchainManager toolchainManager;
 
-    protected String getJLinkExecutable()
-        throws IOException
+    protected JLinkExecutor getJlinkExecutor()
+            throws IOException
     {
-        Toolchain tc = getToolchain();
-
-        String jLinkExecutable = null;
-        if ( tc != null )
-        {
-            jLinkExecutable = tc.findTool( "jlink" );
-        }
-
-        // TODO: Check if there exist a more elegant way?
-        String jLinkCommand = "jlink" + ( SystemUtils.IS_OS_WINDOWS ? ".exe" : "" );
-
-        File jLinkExe;
-
-        if ( StringUtils.isNotEmpty( jLinkExecutable ) )
-        {
-            jLinkExe = new File( jLinkExecutable );
-
-            if ( jLinkExe.isDirectory() )
-            {
-                jLinkExe = new File( jLinkExe, jLinkCommand );
-            }
-
-            if ( SystemUtils.IS_OS_WINDOWS && jLinkExe.getName().indexOf( '.' ) < 0 )
-            {
-                jLinkExe = new File( jLinkExe.getPath() + ".exe" );
-            }
-
-            if ( !jLinkExe.isFile() )
-            {
-                throw new IOException( "The jlink executable '" + jLinkExe + "' doesn't exist or is not a file." );
-            }
-            return jLinkExe.getAbsolutePath();
-        }
-
-        // ----------------------------------------------------------------------
-        // Try to find jlink from System.getProperty( "java.home" )
-        // By default, System.getProperty( "java.home" ) = JRE_HOME and JRE_HOME
-        // should be in the JDK_HOME
-        // ----------------------------------------------------------------------
-        jLinkExe = new File( SystemUtils.getJavaHome() + File.separator + ".." + File.separator + "bin", jLinkCommand );
-
-        // ----------------------------------------------------------------------
-        // Try to find javadocExe from JAVA_HOME environment variable
-        // ----------------------------------------------------------------------
-        if ( !jLinkExe.exists() || !jLinkExe.isFile() )
-        {
-            Properties env = CommandLineUtils.getSystemEnvVars();
-            String javaHome = env.getProperty( "JAVA_HOME" );
-            if ( StringUtils.isEmpty( javaHome ) )
-            {
-                throw new IOException( "The environment variable JAVA_HOME is not correctly set." );
-            }
-            if ( !new File( javaHome ).getCanonicalFile().exists()
-                || new File( javaHome ).getCanonicalFile().isFile() )
-            {
-                throw new IOException( "The environment variable JAVA_HOME=" + javaHome
-                    + " doesn't exist or is not a valid directory." );
-            }
-
-            jLinkExe = new File( javaHome + File.separator + "bin", jLinkCommand );
-        }
-
-        if ( !jLinkExe.getCanonicalFile().exists() || !jLinkExe.getCanonicalFile().isFile() )
-        {
-            throw new IOException( "The jlink executable '" + jLinkExe
-                + "' doesn't exist or is not a file. Verify the JAVA_HOME environment variable." );
-        }
-
-        return jLinkExe.getAbsolutePath();
-    }
-
-    protected void executeCommand( Commandline cmd, File outputDirectory )
-        throws MojoExecutionException
-    {
-        if ( getLog().isDebugEnabled() )
-        {
-            // no quoted arguments ???
-            getLog().debug( CommandLineUtils.toString( cmd.getCommandline() ).replaceAll( "'", "" ) );
-        }
-
-        CommandLineUtils.StringStreamConsumer err = new CommandLineUtils.StringStreamConsumer();
-        CommandLineUtils.StringStreamConsumer out = new CommandLineUtils.StringStreamConsumer();
-        try
-        {
-            int exitCode = CommandLineUtils.executeCommandLine( cmd, out, err );
-
-            String output = ( StringUtils.isEmpty( out.getOutput() ) ? null : '\n' + out.getOutput().trim() );
-
-            if ( exitCode != 0 )
-            {
-
-                if ( StringUtils.isNotEmpty( output ) )
-                {
-                    // Reconsider to use WARN / ERROR ?
-                   //  getLog().error( output );
-                    for ( String outputLine : output.split( "\n" ) )
-                    {
-                        getLog().error( outputLine );
-                    }
-                }
-
-                StringBuilder msg = new StringBuilder( "\nExit code: " );
-                msg.append( exitCode );
-                if ( StringUtils.isNotEmpty( err.getOutput() ) )
-                {
-                    msg.append( " - " ).append( err.getOutput() );
-                }
-                msg.append( '\n' );
-                msg.append( "Command line was: " ).append( cmd ).append( '\n' ).append( '\n' );
-
-                throw new MojoExecutionException( msg.toString() );
-            }
-
-            if ( StringUtils.isNotEmpty( output ) )
-            {
-                //getLog().info( output );
-                for ( String outputLine : output.split( "\n" ) )
-                {
-                    getLog().info( outputLine );
-                }
-            }
-        }
-        catch ( CommandLineException e )
-        {
-            throw new MojoExecutionException( "Unable to execute jlink command: " + e.getMessage(), e );
-        }
-
+        return new JLinkExecutor( getToolchain(), getLog() );
     }
 
     protected Toolchain getToolchain()
@@ -207,12 +74,12 @@ public abstract class AbstractJLinkMojo
             // Maven 3.3.1 has plugin execution scoped Toolchain Support
             try
             {
-                Method getToolchainsMethod = toolchainManager.getClass().getMethod( "getToolchains", MavenSession.class,
-                                                                                    String.class, Map.class );
+                Method getToolchainsMethod = toolchainManager.getClass().getMethod( "getToolchains",
+                        MavenSession.class, String.class, Map.class );
 
                 @SuppressWarnings( "unchecked" )
-                List<Toolchain> tcs =
-                    (List<Toolchain>) getToolchainsMethod.invoke( toolchainManager, session, "jdk", jdkToolchain );
+                List<Toolchain> tcs = (List<Toolchain>) getToolchainsMethod.invoke( toolchainManager, getSession(),
+                        "jdk", jdkToolchain );
 
                 if ( tcs != null && tcs.size() > 0 )
                 {
@@ -236,7 +103,7 @@ public abstract class AbstractJLinkMojo
         if ( tc == null )
         {
             // TODO: Check if we should make the type configurable?
-            tc = toolchainManager.getToolchainFromBuildContext( "jdk", session );
+            tc = toolchainManager.getToolchainFromBuildContext( "jdk", getSession() );
         }
 
         return tc;
diff --git a/src/main/java/org/apache/maven/plugins/jlink/JLinkExecutor.java b/src/main/java/org/apache/maven/plugins/jlink/JLinkExecutor.java
new file mode 100644
index 0000000..edd0746
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugins/jlink/JLinkExecutor.java
@@ -0,0 +1,171 @@
+package org.apache.maven.plugins.jlink;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.lang3.SystemUtils;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.toolchain.Toolchain;
+import org.codehaus.plexus.util.StringUtils;
+import org.codehaus.plexus.util.cli.CommandLineUtils;
+import org.codehaus.plexus.util.cli.Commandline;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Optional;
+import java.util.Properties;
+
+/**
+ * JDK 8-only Jlink executor.
+ *
+ * <p>As JDK8 does not ship jlink, either a toolchain or JAVA_HOME is required.</p>
+ */
+class JLinkExecutor extends AbstractJLinkExecutor
+{
+    private final String jLinkExec;
+
+    JLinkExecutor( Toolchain toolchain, Log log ) throws IOException
+    {
+        super( toolchain, log );
+        this.jLinkExec = getJLinkExecutable();
+    }
+
+    public File getJlinkExecutable()
+    {
+        return new File( this.jLinkExec );
+    }
+
+    @Override
+    public Optional<File> getJmodsFolder( /* nullable */ File sourceJdkModules )
+    {
+        // Really Hacky...do we have a better solution to find the jmods directory of the JDK?
+        File jLinkParent = getJlinkExecutable().getParentFile().getParentFile();
+        File jmodsFolder;
+        if ( sourceJdkModules != null && sourceJdkModules.isDirectory() )
+        {
+            jmodsFolder = new File( sourceJdkModules, JMODS );
+        }
+        else
+        {
+            jmodsFolder = new File( jLinkParent, JMODS );
+        }
+
+        getLog().debug( " Parent: " + jLinkParent.getAbsolutePath() );
+        getLog().debug( " jmodsFolder: " + jmodsFolder.getAbsolutePath() );
+
+        return Optional.of( jmodsFolder );
+    }
+
+    /**
+     * Execute JLink via any means.
+     *
+     * @return the exit code ({@code 0} on success).
+     */
+    @Override
+    public int executeJlink( File argsFile )
+    {
+        getLog().info( "Toolchain in maven-jlink-plugin: jlink [ " + this.jLinkExec + " ]" );
+
+        Commandline cmd = createJLinkCommandLine( argsFile );
+        cmd.setExecutable( this.jLinkExec );
+
+        throw new UnsupportedOperationException( "not implemented" );
+    }
+
+    private Commandline createJLinkCommandLine( File argsFile )
+    {
+        Commandline cmd = new Commandline();
+        cmd.createArg().setValue( '@' + argsFile.getAbsolutePath() );
+
+        return cmd;
+    }
+
+
+    protected final String getJLinkExecutable() throws IOException
+    {
+        String jLinkExecutable = null;
+        if ( getToolchain() != null )
+        {
+            jLinkExecutable = getToolchain().findTool( "jlink" );
+        }
+
+        // TODO: Check if there exist a more elegant way?
+        String jLinkCommand = "jlink" + ( SystemUtils.IS_OS_WINDOWS ? ".exe" : "" );
+
+        File jLinkExe;
+
+        if ( StringUtils.isNotEmpty( jLinkExecutable ) )
+        {
+            jLinkExe = new File( jLinkExecutable );
+
+            if ( jLinkExe.isDirectory() )
+            {
+                jLinkExe = new File( jLinkExe, jLinkCommand );
+            }
+
+            if ( SystemUtils.IS_OS_WINDOWS && jLinkExe.getName().indexOf( '.' ) < 0 )
+            {
+                jLinkExe = new File( jLinkExe.getPath() + ".exe" );
+            }
+
+            if ( !jLinkExe.isFile() )
+            {
+                throw new IOException( "The jlink executable '" + jLinkExe + "' doesn't exist or is not a file." );
+            }
+            return jLinkExe.getAbsolutePath();
+        }
+
+        // ----------------------------------------------------------------------
+        // Try to find jlink from System.getProperty( "java.home" )
+        // By default, System.getProperty( "java.home" ) = JRE_HOME and JRE_HOME
+        // should be in the JDK_HOME
+        // ----------------------------------------------------------------------
+        jLinkExe = new File( SystemUtils.getJavaHome() + File.separator + ".." + File.separator + "bin", jLinkCommand );
+
+        // ----------------------------------------------------------------------
+        // Try to find javadocExe from JAVA_HOME environment variable
+        // ----------------------------------------------------------------------
+        if ( !jLinkExe.exists() || !jLinkExe.isFile() )
+        {
+            Properties env = CommandLineUtils.getSystemEnvVars();
+            String javaHome = env.getProperty( "JAVA_HOME" );
+            if ( StringUtils.isEmpty( javaHome ) )
+            {
+                throw new IOException( "The environment variable JAVA_HOME is not correctly set." );
+            }
+            if ( !new File( javaHome ).getCanonicalFile().exists() || new File( javaHome ).getCanonicalFile().isFile() )
+            {
+                throw new IOException(
+                        "The environment variable JAVA_HOME=" + javaHome
+                                + " doesn't exist or is not a valid directory." );
+            }
+
+            jLinkExe = new File( javaHome + File.separator + "bin", jLinkCommand );
+        }
+
+        if ( !jLinkExe.getCanonicalFile().exists() || !jLinkExe.getCanonicalFile().isFile() )
+        {
+            throw new IOException(
+                    "The jlink executable '" + jLinkExe
+                            + "' doesn't exist or is not a file. Verify the JAVA_HOME environment variable." );
+        }
+
+        return jLinkExe.getAbsolutePath();
+    }
+}
diff --git a/src/main/java/org/apache/maven/plugins/jlink/JLinkMojo.java b/src/main/java/org/apache/maven/plugins/jlink/JLinkMojo.java
index 14bebdc..790859e 100644
--- a/src/main/java/org/apache/maven/plugins/jlink/JLinkMojo.java
+++ b/src/main/java/org/apache/maven/plugins/jlink/JLinkMojo.java
@@ -49,7 +49,6 @@ import org.codehaus.plexus.languages.java.jpms.LocationManager;
 import org.codehaus.plexus.languages.java.jpms.ResolvePathsRequest;
 import org.codehaus.plexus.languages.java.jpms.ResolvePathsResult;
 import org.codehaus.plexus.util.FileUtils;
-import org.codehaus.plexus.util.cli.Commandline;
 
 /**
  * The JLink goal is intended to create a Java Run Time Image file based on
@@ -64,8 +63,6 @@ import org.codehaus.plexus.util.cli.Commandline;
 public class JLinkMojo
     extends AbstractJLinkMojo
 {
-    private static final String JMODS = "jmods";
-
     @Component
     private LocationManager locationManager;
 
@@ -274,41 +271,20 @@ public class JLinkMojo
     @Parameter( defaultValue = "${project.build.finalName}", readonly = true )
     private String finalName;
 
-    public void execute()
-        throws MojoExecutionException, MojoFailureException
+    @Override
+    public void execute() throws MojoExecutionException, MojoFailureException
     {
-
-        String jLinkExec = getExecutable();
-
-        getLog().info( "Toolchain in maven-jlink-plugin: jlink [ " + jLinkExec + " ]" );
-
-        // TODO: Find a more better and cleaner way?
-        File jLinkExecuteable = new File( jLinkExec );
-
-        // Really Hacky...do we have a better solution to find the jmods directory of the JDK?
-        File jLinkParent = jLinkExecuteable.getParentFile().getParentFile();
-        File jmodsFolder;
-        if ( sourceJdkModules != null && sourceJdkModules.isDirectory() )
-        {
-            jmodsFolder = new File ( sourceJdkModules, JMODS );
-        }
-        else
-        {
-            jmodsFolder = new File( jLinkParent, JMODS );
-        }
-
-        getLog().debug( " Parent: " + jLinkParent.getAbsolutePath() );
-        getLog().debug( " jmodsFolder: " + jmodsFolder.getAbsolutePath() );
-
         failIfParametersAreNotInTheirValidValueRanges();
 
         ifOutputDirectoryExistsDelteIt();
 
+        JLinkExecutor jLinkExec = getExecutor();
         Collection<String> modulesToAdd = new ArrayList<>();
         if ( addModules != null )
         {
             modulesToAdd.addAll( addModules );
         }
+        jLinkExec.addAllModules( modulesToAdd );
 
         Collection<String> pathsOfModules = new ArrayList<>();
         if ( modulePaths != null )
@@ -326,27 +302,29 @@ public class JLinkMojo
         }
 
         // The jmods directory of the JDK
-        pathsOfModules.add( jmodsFolder.getAbsolutePath() );
+        jLinkExec.getJmodsFolder( this.sourceJdkModules ).ifPresent(
+                jmodsFolder -> pathsOfModules.add( jmodsFolder.getAbsolutePath() )
+        );
+        jLinkExec.addAllModulePaths( pathsOfModules );
 
-        Commandline cmd;
+        File argsFile;
         try
         {
-            cmd = createJLinkCommandLine( pathsOfModules, modulesToAdd );
+            argsFile = createJlinkArgsFile( pathsOfModules, modulesToAdd );
         }
         catch ( IOException e )
         {
             throw new MojoExecutionException( e.getMessage() );
         }
-        cmd.setExecutable( jLinkExec );
 
-        executeCommand( cmd, outputDirectoryImage );
+        jLinkExec.executeJlink( argsFile );
 
         File createZipArchiveFromImage = createZipArchiveFromImage( buildDirectory, outputDirectoryImage );
 
         if ( projectHasAlreadySetAnArtifact() )
         {
             throw new MojoExecutionException( "You have to use a classifier "
-                + "to attach supplemental artifacts to the project instead of replacing them." );
+                            + "to attach supplemental artifacts to the project instead of replacing them." );
         }
 
         getProject().getArtifact().setFile( createZipArchiveFromImage );
@@ -443,13 +421,12 @@ public class JLinkMojo
         return modulepathElements;
     }
 
-    private String getExecutable()
-        throws MojoFailureException
+    private JLinkExecutor getExecutor() throws MojoFailureException
     {
-        String jLinkExec;
+        JLinkExecutor jLinkExec;
         try
         {
-            jLinkExec = getJLinkExecutable();
+            jLinkExec = getJlinkExecutor();
         }
         catch ( IOException e )
         {
@@ -510,7 +487,7 @@ public class JLinkMojo
         if ( endian != null && ( !"big".equals( endian ) && !"little".equals( endian ) ) )
         {
             String message = "The given endian parameter " + endian
-                + " does not contain one of the following values: 'little' or 'big'.";
+                    + " does not contain one of the following values: 'little' or 'big'.";
             getLog().error( message );
             throw new MojoFailureException( message );
         }
@@ -537,10 +514,10 @@ public class JLinkMojo
         }
     }
 
-    private Commandline createJLinkCommandLine( Collection<String> pathsOfModules, Collection<String> modulesToAdd )
-        throws IOException
+    private File createJlinkArgsFile( Collection<String> pathsOfModules,
+                                      Collection<String> modulesToAdd ) throws IOException
     {
-        File file = new File( outputDirectoryImage.getParentFile(), "jlinkArgs" );
+        File file = new File( this.outputDirectoryImage.getParentFile(), "jlinkArgs" );
         if ( !getLog().isDebugEnabled() )
         {
             file.deleteOnExit();
@@ -656,11 +633,7 @@ public class JLinkMojo
             argsFile.println( "--verbose" );
         }
         argsFile.close();
-
-        Commandline cmd = new Commandline();
-        cmd.createArg().setValue( '@' + file.getAbsolutePath() );
-
-        return cmd;
+        return file;
     }
 
     private boolean hasIncludeLocales()
diff --git a/src/main/java9/org/apache/maven/plugins/jlink/JLinkExecutor.java b/src/main/java9/org/apache/maven/plugins/jlink/JLinkExecutor.java
new file mode 100644
index 0000000..02c4333
--- /dev/null
+++ b/src/main/java9/org/apache/maven/plugins/jlink/JLinkExecutor.java
@@ -0,0 +1,175 @@
+/*
+ * 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.maven.plugins.jlink;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.toolchain.Toolchain;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.Files;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Optional;
+import java.util.spi.ToolProvider;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+class JLinkExecutor extends AbstractJLinkExecutor
+{
+
+    private final ToolProvider toolProvider;
+
+    JLinkExecutor( Toolchain toolchain, Log log ) throws IOException
+    {
+        super( toolchain, log );
+        this.toolProvider = getJLinkExecutable();
+    }
+
+    @Override
+    public Optional<File> getJmodsFolder( /* nullable */ File sourceJdkModules )
+    {
+        if ( sourceJdkModules != null && sourceJdkModules.isDirectory() )
+        {
+            return Optional.of( new File( sourceJdkModules, JMODS ) );
+        }
+
+        // ToolProvider does not need jmods folder to be set.
+        return Optional.empty();
+    }
+
+    protected final ToolProvider getJLinkExecutable()
+    {
+        Optional<ToolProvider> jlink = ToolProvider.findFirst( "jlink" );
+
+        if ( !jlink.isPresent() )
+        {
+            throw new IllegalStateException( "No jlink tool found." );
+        }
+
+        return jlink.orElseThrow( NoSuchElementException::new );
+    }
+
+
+    protected Stream<String> argsfileToArgs( File argsFile )
+    {
+        try
+        {
+            List<String> strings = Files.readAllLines( argsFile.toPath() );
+            Deque<String> out = new ArrayDeque<>();
+
+            for ( String line : strings )
+            {
+                if ( line.startsWith( "-" ) )
+                {
+                    out.add( line );
+                    continue;
+                }
+
+                if ( line.startsWith( "\"" ) && line.endsWith( "\"" ) )
+                {
+                    out.add( line.substring( 1, line.lastIndexOf( "\"" ) ) );
+                    continue;
+                }
+
+                out.add( line );
+            }
+
+            return out.stream();
+        }
+        catch ( IOException e )
+        {
+            throw new IllegalStateException( "Unable to read jlinkArgs file: " + argsFile.getAbsolutePath() );
+        }
+
+    }
+
+    @Override
+    public int executeJlink( File argsFile ) throws MojoExecutionException
+    {
+        List<String> actualArgs = this.argsfileToArgs( argsFile ).collect( Collectors.toList() );
+
+        if ( getLog().isDebugEnabled() )
+        {
+            // no quoted arguments ???
+            getLog().debug( this.toolProvider.name() + " " + actualArgs );
+        }
+
+        try ( ByteArrayOutputStream baosErr = new ByteArrayOutputStream();
+              PrintWriter err = new PrintWriter( baosErr );
+              ByteArrayOutputStream baosOut = new ByteArrayOutputStream();
+              PrintWriter out = new PrintWriter( baosOut ) )
+        {
+            int exitCode = this.toolProvider.run( out, err, actualArgs.toArray( new String[0] ) );
+            out.flush();
+            err.flush();
+
+            String outAsString = baosOut.toString( "UTF-8" );
+            String output = ( StringUtils.isEmpty( outAsString ) ? null : '\n' + outAsString.trim() );
+
+            if ( exitCode != 0 )
+            {
+                if ( StringUtils.isNotEmpty( output ) )
+                {
+                    // Reconsider to use WARN / ERROR ?
+                    //  getLog().error( output );
+                    for ( String outputLine : output.split( "\n" ) )
+                    {
+                        getLog().error( outputLine );
+                    }
+                }
+
+                StringBuilder msg = new StringBuilder( "\nExit code: " );
+                msg.append( exitCode );
+                String errAsString = baosErr.toString();
+                if ( StringUtils.isNotEmpty( errAsString ) )
+                {
+                    msg.append( " - " ).append( errAsString );
+                }
+                msg.append( '\n' );
+                msg.append( "Command line was: " ).append( this.toolProvider.name() ).append( ' ' ).append(
+                        actualArgs ).append( '\n' ).append( '\n' );
+
+                throw new MojoExecutionException( msg.toString() );
+            }
+
+            if ( StringUtils.isNotEmpty( output ) )
+            {
+                //getLog().info( output );
+                for ( String outputLine : output.split( "\n" ) )
+                {
+                    getLog().info( outputLine );
+                }
+            }
+
+            return exitCode;
+        }
+        catch ( IOException e )
+        {
+            throw new MojoExecutionException( "Unable to execute jlink command: " + e.getMessage(), e );
+        }
+    }
+}

Reply | Threaded
Open this post in threaded view
|

[maven-jlink-plugin] 02/05: [MJLINK-36] remove looking for jlink in JAVA_HOME etc. for Java 8.

slachiewicz
In reply to this post by slachiewicz
This is an automated email from the ASF dual-hosted git repository.

slachiewicz pushed a commit to branch MJLINK-36
in repository https://gitbox.apache.org/repos/asf/maven-jlink-plugin.git

commit 73c4f026b053f5fd18d7f717403506b6b7ba718b
Author: Benjamin Marwell <[hidden email]>
AuthorDate: Mon Nov 16 11:15:15 2020 +0100

    [MJLINK-36] remove looking for jlink in JAVA_HOME etc. for Java 8.
---
 .../apache/maven/plugins/jlink/JLinkExecutor.java  | 74 ++++++----------------
 1 file changed, 20 insertions(+), 54 deletions(-)

diff --git a/src/main/java/org/apache/maven/plugins/jlink/JLinkExecutor.java b/src/main/java/org/apache/maven/plugins/jlink/JLinkExecutor.java
index edd0746..51d2991 100644
--- a/src/main/java/org/apache/maven/plugins/jlink/JLinkExecutor.java
+++ b/src/main/java/org/apache/maven/plugins/jlink/JLinkExecutor.java
@@ -23,13 +23,11 @@ import org.apache.commons.lang3.SystemUtils;
 import org.apache.maven.plugin.logging.Log;
 import org.apache.maven.toolchain.Toolchain;
 import org.codehaus.plexus.util.StringUtils;
-import org.codehaus.plexus.util.cli.CommandLineUtils;
 import org.codehaus.plexus.util.cli.Commandline;
 
 import java.io.File;
 import java.io.IOException;
 import java.util.Optional;
-import java.util.Properties;
 
 /**
  * JDK 8-only Jlink executor.
@@ -99,73 +97,41 @@ class JLinkExecutor extends AbstractJLinkExecutor
 
     protected final String getJLinkExecutable() throws IOException
     {
-        String jLinkExecutable = null;
-        if ( getToolchain() != null )
+        if ( getToolchain() == null )
         {
-            jLinkExecutable = getToolchain().findTool( "jlink" );
+            getLog().error( "Either JDK9+ or a toolchain "
+                    + "pointing to a JDK9+ containing a jlink binary is required." );
+            getLog().info( "See https://maven.apache.org/guides/mini/guide-using-toolchains.html "
+                    + "for mor information." );
+            throw new IllegalStateException( "Running on JDK8 and no toolchain found." );
+        }
+
+        String jLinkExecutable = getToolchain().findTool( "jlink" );
+
+        if ( StringUtils.isEmpty( jLinkExecutable ) )
+        {
+            throw new IOException( "The jlink executable '" + jLinkExecutable + "' doesn't exist or is not a file." );
         }
 
         // TODO: Check if there exist a more elegant way?
         String jLinkCommand = "jlink" + ( SystemUtils.IS_OS_WINDOWS ? ".exe" : "" );
 
-        File jLinkExe;
+        File jLinkExe = new File( jLinkExecutable );
 
-        if ( StringUtils.isNotEmpty( jLinkExecutable ) )
+        if ( jLinkExe.isDirectory() )
         {
-            jLinkExe = new File( jLinkExecutable );
-
-            if ( jLinkExe.isDirectory() )
-            {
-                jLinkExe = new File( jLinkExe, jLinkCommand );
-            }
-
-            if ( SystemUtils.IS_OS_WINDOWS && jLinkExe.getName().indexOf( '.' ) < 0 )
-            {
-                jLinkExe = new File( jLinkExe.getPath() + ".exe" );
-            }
-
-            if ( !jLinkExe.isFile() )
-            {
-                throw new IOException( "The jlink executable '" + jLinkExe + "' doesn't exist or is not a file." );
-            }
-            return jLinkExe.getAbsolutePath();
+            jLinkExe = new File( jLinkExe, jLinkCommand );
         }
 
-        // ----------------------------------------------------------------------
-        // Try to find jlink from System.getProperty( "java.home" )
-        // By default, System.getProperty( "java.home" ) = JRE_HOME and JRE_HOME
-        // should be in the JDK_HOME
-        // ----------------------------------------------------------------------
-        jLinkExe = new File( SystemUtils.getJavaHome() + File.separator + ".." + File.separator + "bin", jLinkCommand );
-
-        // ----------------------------------------------------------------------
-        // Try to find javadocExe from JAVA_HOME environment variable
-        // ----------------------------------------------------------------------
-        if ( !jLinkExe.exists() || !jLinkExe.isFile() )
+        if ( SystemUtils.IS_OS_WINDOWS && jLinkExe.getName().indexOf( '.' ) < 0 )
         {
-            Properties env = CommandLineUtils.getSystemEnvVars();
-            String javaHome = env.getProperty( "JAVA_HOME" );
-            if ( StringUtils.isEmpty( javaHome ) )
-            {
-                throw new IOException( "The environment variable JAVA_HOME is not correctly set." );
-            }
-            if ( !new File( javaHome ).getCanonicalFile().exists() || new File( javaHome ).getCanonicalFile().isFile() )
-            {
-                throw new IOException(
-                        "The environment variable JAVA_HOME=" + javaHome
-                                + " doesn't exist or is not a valid directory." );
-            }
-
-            jLinkExe = new File( javaHome + File.separator + "bin", jLinkCommand );
+            jLinkExe = new File( jLinkExe.getPath() + ".exe" );
         }
 
-        if ( !jLinkExe.getCanonicalFile().exists() || !jLinkExe.getCanonicalFile().isFile() )
+        if ( !jLinkExe.isFile() )
         {
-            throw new IOException(
-                    "The jlink executable '" + jLinkExe
-                            + "' doesn't exist or is not a file. Verify the JAVA_HOME environment variable." );
+            throw new IOException( "The jlink executable '" + jLinkExe + "' doesn't exist or is not a file." );
         }
-
         return jLinkExe.getAbsolutePath();
     }
 }

Reply | Threaded
Open this post in threaded view
|

[maven-jlink-plugin] 03/05: [MJLINK-36] update javadoc, simplifly Optional use.

slachiewicz
In reply to this post by slachiewicz
This is an automated email from the ASF dual-hosted git repository.

slachiewicz pushed a commit to branch MJLINK-36
in repository https://gitbox.apache.org/repos/asf/maven-jlink-plugin.git

commit d59574f15956f7874a0618ea80d5beef82c60a1f
Author: Benjamin Marwell <[hidden email]>
AuthorDate: Mon Nov 16 11:40:06 2020 +0100

    [MJLINK-36] update javadoc, simplifly Optional use.
---
 .../org/apache/maven/plugins/jlink/JLinkExecutor.java  |  2 +-
 .../org/apache/maven/plugins/jlink/JLinkExecutor.java  | 18 +++++++++---------
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/src/main/java/org/apache/maven/plugins/jlink/JLinkExecutor.java b/src/main/java/org/apache/maven/plugins/jlink/JLinkExecutor.java
index 51d2991..f025458 100644
--- a/src/main/java/org/apache/maven/plugins/jlink/JLinkExecutor.java
+++ b/src/main/java/org/apache/maven/plugins/jlink/JLinkExecutor.java
@@ -32,7 +32,7 @@ import java.util.Optional;
 /**
  * JDK 8-only Jlink executor.
  *
- * <p>As JDK8 does not ship jlink, either a toolchain or JAVA_HOME is required.</p>
+ * <p>As JDK8 does not ship jlink, a toolchain is required.</p>
  */
 class JLinkExecutor extends AbstractJLinkExecutor
 {
diff --git a/src/main/java9/org/apache/maven/plugins/jlink/JLinkExecutor.java b/src/main/java9/org/apache/maven/plugins/jlink/JLinkExecutor.java
index 02c4333..c78b8c3 100644
--- a/src/main/java9/org/apache/maven/plugins/jlink/JLinkExecutor.java
+++ b/src/main/java9/org/apache/maven/plugins/jlink/JLinkExecutor.java
@@ -32,12 +32,17 @@ import java.nio.file.Files;
 import java.util.ArrayDeque;
 import java.util.Deque;
 import java.util.List;
-import java.util.NoSuchElementException;
 import java.util.Optional;
 import java.util.spi.ToolProvider;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+/**
+ * JDK9+ executor for jlink.
+ *
+ * <p>This implementation uses the JDK9+ Toolprovider SPI to find and execute jlink.
+ * This way, no fork needs to be created.</p>
+ */
 class JLinkExecutor extends AbstractJLinkExecutor
 {
 
@@ -63,14 +68,9 @@ class JLinkExecutor extends AbstractJLinkExecutor
 
     protected final ToolProvider getJLinkExecutable()
     {
-        Optional<ToolProvider> jlink = ToolProvider.findFirst( "jlink" );
-
-        if ( !jlink.isPresent() )
-        {
-            throw new IllegalStateException( "No jlink tool found." );
-        }
-
-        return jlink.orElseThrow( NoSuchElementException::new );
+        return ToolProvider
+                .findFirst( "jlink" )
+                .orElseThrow( () -> new IllegalStateException( "No jlink tool found." ) );
     }
 
 

Reply | Threaded
Open this post in threaded view
|

[maven-jlink-plugin] 04/05: [MJLINK-36] skip unnecessary jlinkArgsFile.

slachiewicz
In reply to this post by slachiewicz
This is an automated email from the ASF dual-hosted git repository.

slachiewicz pushed a commit to branch MJLINK-36
in repository https://gitbox.apache.org/repos/asf/maven-jlink-plugin.git

commit 4c79bec3c5395de8649880b3078d4489934b9a34
Author: Benjamin Marwell <[hidden email]>
AuthorDate: Mon Nov 16 12:04:51 2020 +0100

    [MJLINK-36] skip unnecessary jlinkArgsFile.
---
 .../MJLINK-40_includeLocales/verify.groovy         | 16 ++--
 .../maven/plugins/jlink/AbstractJLinkExecutor.java |  2 +-
 .../apache/maven/plugins/jlink/JLinkExecutor.java  |  9 ++-
 .../org/apache/maven/plugins/jlink/JLinkMojo.java  | 93 +++++++++-------------
 .../apache/maven/plugins/jlink/JLinkExecutor.java  | 49 +-----------
 5 files changed, 52 insertions(+), 117 deletions(-)

diff --git a/src/it/projects/MJLINK-40_includeLocales/verify.groovy b/src/it/projects/MJLINK-40_includeLocales/verify.groovy
index 1887547..c32508b 100644
--- a/src/it/projects/MJLINK-40_includeLocales/verify.groovy
+++ b/src/it/projects/MJLINK-40_includeLocales/verify.groovy
@@ -26,21 +26,15 @@ boolean result = false;
 
 try
 {
-    File target = new File( basedir, "target" );
-    if ( !target.exists() || !target.isDirectory() )
+    File buildLog = new File( basedir, "build.log" );
+    if ( !buildLog.exists() || buildLog.isDirectory() )
     {
-        System.err.println( "target file is missing or not a directory." );
-        return false;
-    }
-    File jlinkArgs = new File( target, "jlinkArgs" );
-    if ( !jlinkArgs.exists() || jlinkArgs.isDirectory() )
-    {
-        System.err.println( "jlinkArgs file is missing or is a directory." );
+        System.err.println( "build.log file is missing or is a directory." );
         return false;
     }
 
-    def line = jlinkArgs.eachLine { line ->
-        if (line.equals('en,ja,de,*-IN'))
+    def line = buildLog.eachLine { line ->
+        if (line.contains('--include-locales, en,ja,de,*-IN'))
         {
             result = true;
         }
diff --git a/src/main/java/org/apache/maven/plugins/jlink/AbstractJLinkExecutor.java b/src/main/java/org/apache/maven/plugins/jlink/AbstractJLinkExecutor.java
index 16864b6..f6a6799 100644
--- a/src/main/java/org/apache/maven/plugins/jlink/AbstractJLinkExecutor.java
+++ b/src/main/java/org/apache/maven/plugins/jlink/AbstractJLinkExecutor.java
@@ -58,7 +58,7 @@ abstract class AbstractJLinkExecutor
 
     public abstract Optional<File> getJmodsFolder( /* nullable */ File sourceJdkModules );
 
-    public abstract int executeJlink( File argsFile ) throws MojoExecutionException;
+    public abstract int executeJlink( List<String> jlinkArgs ) throws MojoExecutionException;
 
     public void addAllModules( Collection<String> modulesToAdd )
     {
diff --git a/src/main/java/org/apache/maven/plugins/jlink/JLinkExecutor.java b/src/main/java/org/apache/maven/plugins/jlink/JLinkExecutor.java
index f025458..a9299c3 100644
--- a/src/main/java/org/apache/maven/plugins/jlink/JLinkExecutor.java
+++ b/src/main/java/org/apache/maven/plugins/jlink/JLinkExecutor.java
@@ -27,6 +27,7 @@ import org.codehaus.plexus.util.cli.Commandline;
 
 import java.io.File;
 import java.io.IOException;
+import java.util.List;
 import java.util.Optional;
 
 /**
@@ -76,20 +77,20 @@ class JLinkExecutor extends AbstractJLinkExecutor
      * @return the exit code ({@code 0} on success).
      */
     @Override
-    public int executeJlink( File argsFile )
+    public int executeJlink( List<String> jlinkArgs )
     {
         getLog().info( "Toolchain in maven-jlink-plugin: jlink [ " + this.jLinkExec + " ]" );
 
-        Commandline cmd = createJLinkCommandLine( argsFile );
+        Commandline cmd = createJLinkCommandLine( jlinkArgs );
         cmd.setExecutable( this.jLinkExec );
 
         throw new UnsupportedOperationException( "not implemented" );
     }
 
-    private Commandline createJLinkCommandLine( File argsFile )
+    private Commandline createJLinkCommandLine( List<String> jlinkArgs )
     {
         Commandline cmd = new Commandline();
-        cmd.createArg().setValue( '@' + argsFile.getAbsolutePath() );
+        jlinkArgs.forEach( arg -> cmd.createArg().setValue( arg ) );
 
         return cmd;
     }
diff --git a/src/main/java/org/apache/maven/plugins/jlink/JLinkMojo.java b/src/main/java/org/apache/maven/plugins/jlink/JLinkMojo.java
index 790859e..c1ebfb6 100644
--- a/src/main/java/org/apache/maven/plugins/jlink/JLinkMojo.java
+++ b/src/main/java/org/apache/maven/plugins/jlink/JLinkMojo.java
@@ -21,7 +21,6 @@ package org.apache.maven.plugins.jlink;
 
 import java.io.File;
 import java.io.IOException;
-import java.io.PrintStream;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -307,17 +306,9 @@ public class JLinkMojo
         );
         jLinkExec.addAllModulePaths( pathsOfModules );
 
-        File argsFile;
-        try
-        {
-            argsFile = createJlinkArgsFile( pathsOfModules, modulesToAdd );
-        }
-        catch ( IOException e )
-        {
-            throw new MojoExecutionException( e.getMessage() );
-        }
+        List<String> jlinkArgs = createJlinkArgs( pathsOfModules, modulesToAdd );
 
-        jLinkExec.executeJlink( argsFile );
+        jLinkExec.executeJlink( jlinkArgs );
 
         File createZipArchiveFromImage = createZipArchiveFromImage( buildDirectory, outputDirectoryImage );
 
@@ -514,126 +505,116 @@ public class JLinkMojo
         }
     }
 
-    private File createJlinkArgsFile( Collection<String> pathsOfModules,
-                                      Collection<String> modulesToAdd ) throws IOException
+    private List<String> createJlinkArgs( Collection<String> pathsOfModules,
+                                      Collection<String> modulesToAdd )
     {
-        File file = new File( this.outputDirectoryImage.getParentFile(), "jlinkArgs" );
-        if ( !getLog().isDebugEnabled() )
-        {
-            file.deleteOnExit();
-        }
-        file.getParentFile().mkdirs();
-        file.createNewFile();
-
-        PrintStream argsFile = new PrintStream( file );
+        List<String> jlinkArgs = new ArrayList<>();
 
         if ( stripDebug )
         {
-            argsFile.println( "--strip-debug" );
+            jlinkArgs.add( "--strip-debug" );
         }
 
         if ( bindServices )
         {
-            argsFile.println( "--bind-services" );
+            jlinkArgs.add( "--bind-services" );
         }
 
         if ( endian != null )
         {
-            argsFile.println( "--endian" );
-            argsFile.println( endian );
+            jlinkArgs.add( "--endian" );
+            jlinkArgs.add( endian );
         }
         if ( ignoreSigningInformation )
         {
-            argsFile.println( "--ignore-signing-information" );
+            jlinkArgs.add( "--ignore-signing-information" );
         }
         if ( compress != null )
         {
-            argsFile.println( "--compress" );
-            argsFile.println( compress );
+            jlinkArgs.add( "--compress" );
+            jlinkArgs.add( compress + "" );
         }
         if ( launcher != null )
         {
-            argsFile.println( "--launcher" );
-            argsFile.println( launcher );
+            jlinkArgs.add( "--launcher" );
+            jlinkArgs.add( launcher );
         }
 
         if ( disablePlugin != null )
         {
-            argsFile.println( "--disable-plugin" );
-            argsFile.append( '"' ).append( disablePlugin ).println( '"' );
+            jlinkArgs.add( "--disable-plugin" );
+            jlinkArgs.add( disablePlugin );
 
         }
         if ( pathsOfModules != null )
         {
             // @formatter:off
-            argsFile.println( "--module-path" );
-            argsFile.append( '"' )
-                .append( getPlatformDependSeparateList( pathsOfModules )
-                         .replace( "\\", "\\\\" ) ).println( '"' );
+            jlinkArgs.add( "--module-path" );
+            jlinkArgs.add( getPlatformDependSeparateList( pathsOfModules ).replace( "\\", "\\\\" ) );
             // @formatter:off
         }
 
         if ( noHeaderFiles )
         {
-            argsFile.println( "--no-header-files" );
+            jlinkArgs.add( "--no-header-files" );
         }
 
         if ( noManPages )
         {
-            argsFile.println( "--no-man-pages" );
+            jlinkArgs.add( "--no-man-pages" );
         }
 
         if ( hasSuggestProviders() )
         {
-            argsFile.println( "--suggest-providers" );
+            jlinkArgs.add( "--suggest-providers" );
             String sb = getCommaSeparatedList( suggestProviders );
-            argsFile.println( sb );
+            jlinkArgs.add( sb );
         }
 
         if ( hasLimitModules() )
         {
-            argsFile.println( "--limit-modules" );
+            jlinkArgs.add( "--limit-modules" );
             String sb = getCommaSeparatedList( limitModules );
-            argsFile.println( sb );
+            jlinkArgs.add( sb );
         }
 
         if ( !modulesToAdd.isEmpty() )
         {
-            argsFile.println( "--add-modules" );
+            jlinkArgs.add( "--add-modules" );
             // This must be name of the module and *NOT* the name of the
             // file! Can we somehow pre check this information to fail early?
             String sb = getCommaSeparatedList( modulesToAdd );
-            argsFile.append( '"' ).append( sb.replace( "\\", "\\\\" ) ).println( '"' );
+            jlinkArgs.add( sb.replace( "\\", "\\\\" ) );
         }
 
         if ( hasIncludeLocales() )
         {
-            argsFile.println( "--add-modules" );
-            argsFile.println( "jdk.localedata" );
-            argsFile.println( "--include-locales" );
+            jlinkArgs.add( "--add-modules" );
+            jlinkArgs.add( "jdk.localedata" );
+            jlinkArgs.add( "--include-locales" );
             String sb = getCommaSeparatedList( includeLocales );
-            argsFile.println( sb );
+            jlinkArgs.add( sb );
         }
 
         if ( pluginModulePath != null )
         {
-            argsFile.println( "--plugin-module-path" );
+            jlinkArgs.add( "--plugin-module-path" );
             StringBuilder sb = convertSeparatedModulePathToPlatformSeparatedModulePath( pluginModulePath );
-            argsFile.append( '"' ).append( sb.toString().replace( "\\", "\\\\" ) ).println( '"' );
+            jlinkArgs.add( sb.toString().replace( "\\", "\\\\" ) );
         }
 
         if ( buildDirectory != null )
         {
-            argsFile.println( "--output" );
-            argsFile.println( outputDirectoryImage );
+            jlinkArgs.add( "--output" );
+            jlinkArgs.add( outputDirectoryImage.getAbsolutePath() );
         }
 
         if ( verbose )
         {
-            argsFile.println( "--verbose" );
+            jlinkArgs.add( "--verbose" );
         }
-        argsFile.close();
-        return file;
+
+        return Collections.unmodifiableList( jlinkArgs );
     }
 
     private boolean hasIncludeLocales()
diff --git a/src/main/java9/org/apache/maven/plugins/jlink/JLinkExecutor.java b/src/main/java9/org/apache/maven/plugins/jlink/JLinkExecutor.java
index c78b8c3..7310a3e 100644
--- a/src/main/java9/org/apache/maven/plugins/jlink/JLinkExecutor.java
+++ b/src/main/java9/org/apache/maven/plugins/jlink/JLinkExecutor.java
@@ -28,14 +28,9 @@ import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.nio.file.Files;
-import java.util.ArrayDeque;
-import java.util.Deque;
 import java.util.List;
 import java.util.Optional;
 import java.util.spi.ToolProvider;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
 
 /**
  * JDK9+ executor for jlink.
@@ -73,49 +68,13 @@ class JLinkExecutor extends AbstractJLinkExecutor
                 .orElseThrow( () -> new IllegalStateException( "No jlink tool found." ) );
     }
 
-
-    protected Stream<String> argsfileToArgs( File argsFile )
-    {
-        try
-        {
-            List<String> strings = Files.readAllLines( argsFile.toPath() );
-            Deque<String> out = new ArrayDeque<>();
-
-            for ( String line : strings )
-            {
-                if ( line.startsWith( "-" ) )
-                {
-                    out.add( line );
-                    continue;
-                }
-
-                if ( line.startsWith( "\"" ) && line.endsWith( "\"" ) )
-                {
-                    out.add( line.substring( 1, line.lastIndexOf( "\"" ) ) );
-                    continue;
-                }
-
-                out.add( line );
-            }
-
-            return out.stream();
-        }
-        catch ( IOException e )
-        {
-            throw new IllegalStateException( "Unable to read jlinkArgs file: " + argsFile.getAbsolutePath() );
-        }
-
-    }
-
     @Override
-    public int executeJlink( File argsFile ) throws MojoExecutionException
+    public int executeJlink( List<String> jlinkArgs ) throws MojoExecutionException
     {
-        List<String> actualArgs = this.argsfileToArgs( argsFile ).collect( Collectors.toList() );
-
         if ( getLog().isDebugEnabled() )
         {
             // no quoted arguments ???
-            getLog().debug( this.toolProvider.name() + " " + actualArgs );
+            getLog().debug( this.toolProvider.name() + " " + jlinkArgs );
         }
 
         try ( ByteArrayOutputStream baosErr = new ByteArrayOutputStream();
@@ -123,7 +82,7 @@ class JLinkExecutor extends AbstractJLinkExecutor
               ByteArrayOutputStream baosOut = new ByteArrayOutputStream();
               PrintWriter out = new PrintWriter( baosOut ) )
         {
-            int exitCode = this.toolProvider.run( out, err, actualArgs.toArray( new String[0] ) );
+            int exitCode = this.toolProvider.run( out, err, jlinkArgs.toArray( new String[0] ) );
             out.flush();
             err.flush();
 
@@ -151,7 +110,7 @@ class JLinkExecutor extends AbstractJLinkExecutor
                 }
                 msg.append( '\n' );
                 msg.append( "Command line was: " ).append( this.toolProvider.name() ).append( ' ' ).append(
-                        actualArgs ).append( '\n' ).append( '\n' );
+                        jlinkArgs ).append( '\n' ).append( '\n' );
 
                 throw new MojoExecutionException( msg.toString() );
             }

Reply | Threaded
Open this post in threaded view
|

[maven-jlink-plugin] 05/05: [MJLINK-36] Toolchain must always win. Add toolchain tests.

slachiewicz
In reply to this post by slachiewicz
This is an automated email from the ASF dual-hosted git repository.

slachiewicz pushed a commit to branch MJLINK-36
in repository https://gitbox.apache.org/repos/asf/maven-jlink-plugin.git

commit e289a05a9791628cd0e9591593439a089851b4cf
Author: Benjamin Marwell <[hidden email]>
AuthorDate: Tue Nov 17 13:27:53 2020 +0100

    [MJLINK-36] Toolchain must always win. Add toolchain tests.
---
 .../MJLINK-36_toolchainjdk8/invoker.properties     |  20 ++
 src/it/projects/MJLINK-36_toolchainjdk8/pom.xml    |  95 ++++++++++
 .../MJLINK-36_toolchainjdk9/invoker.properties     |  20 ++
 src/it/projects/MJLINK-36_toolchainjdk9/pom.xml    |  95 ++++++++++
 .../maven/plugins/jlink/AbstractJLinkExecutor.java |  11 +-
 .../maven/plugins/jlink/AbstractJLinkMojo.java     |   9 +-
 .../jlink/AbstractJLinkToolchainExecutor.java      | 204 +++++++++++++++++++++
 .../apache/maven/plugins/jlink/JLinkExecutor.java  | 105 +----------
 .../org/apache/maven/plugins/jlink/JLinkMojo.java  |  32 ++--
 .../apache/maven/plugins/jlink/JLinkExecutor.java  |  37 ++--
 10 files changed, 481 insertions(+), 147 deletions(-)

diff --git a/src/it/projects/MJLINK-36_toolchainjdk8/invoker.properties b/src/it/projects/MJLINK-36_toolchainjdk8/invoker.properties
new file mode 100644
index 0000000..d3282c7
--- /dev/null
+++ b/src/it/projects/MJLINK-36_toolchainjdk8/invoker.properties
@@ -0,0 +1,20 @@
+# 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.
+
+invoker.java.version = 1.8
+invoker.goals = clean install
+invoker.toolchain.jdk.version = 11
diff --git a/src/it/projects/MJLINK-36_toolchainjdk8/pom.xml b/src/it/projects/MJLINK-36_toolchainjdk8/pom.xml
new file mode 100644
index 0000000..f6a37cd
--- /dev/null
+++ b/src/it/projects/MJLINK-36_toolchainjdk8/pom.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.maven.plugins.jlink.its</groupId>
+  <artifactId>mjlink36-toolchain-jdk8</artifactId>
+  <version>1.0.0-SNAPSHOT</version>
+  <packaging>jlink</packaging>
+
+  <properties>
+    <maven.compiler.source>1.9</maven.compiler.source>
+    <maven.compiler.target>1.9</maven.compiler.target>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <!-- use a dependency with a module-info.class -->
+      <artifactId>asm</artifactId>
+      <groupId>org.ow2.asm</groupId>
+      <version>6.0</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-toolchains-plugin</artifactId>
+        <version>1.1</version>
+        <executions>
+          <execution>
+            <goals>
+              <goal>toolchain</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <toolchains>
+            <jdk>
+              <version>11</version>
+            </jdk>
+          </toolchains>
+        </configuration>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jlink-plugin</artifactId>
+        <version>@project.version@</version>
+        <extensions>true</extensions>
+        <configuration>
+          <noHeaderFiles>true</noHeaderFiles>
+          <noManPages>true</noManPages>
+          <verbose>true</verbose>
+        </configuration>
+      </plugin>
+    </plugins>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-compiler-plugin</artifactId>
+          <version>3.8.0</version>
+          <configuration>
+            <source>${maven.compiler.source}</source>
+            <target>${maven.compiler.target}</target>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+  </build>
+
+</project>
diff --git a/src/it/projects/MJLINK-36_toolchainjdk9/invoker.properties b/src/it/projects/MJLINK-36_toolchainjdk9/invoker.properties
new file mode 100644
index 0000000..271bf45
--- /dev/null
+++ b/src/it/projects/MJLINK-36_toolchainjdk9/invoker.properties
@@ -0,0 +1,20 @@
+# 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.
+
+invoker.java.version = 9+
+invoker.goals = clean install
+invoker.toolchain.jdk.version = 11
diff --git a/src/it/projects/MJLINK-36_toolchainjdk9/pom.xml b/src/it/projects/MJLINK-36_toolchainjdk9/pom.xml
new file mode 100644
index 0000000..ab371a9
--- /dev/null
+++ b/src/it/projects/MJLINK-36_toolchainjdk9/pom.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.maven.plugins.jlink.its</groupId>
+  <artifactId>mjlink36-toolchain-jdk9</artifactId>
+  <version>1.0.0-SNAPSHOT</version>
+  <packaging>jlink</packaging>
+
+  <properties>
+    <maven.compiler.source>1.9</maven.compiler.source>
+    <maven.compiler.target>1.9</maven.compiler.target>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <!-- use a dependency with a module-info.class -->
+      <artifactId>asm</artifactId>
+      <groupId>org.ow2.asm</groupId>
+      <version>6.0</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-toolchains-plugin</artifactId>
+        <version>1.1</version>
+        <executions>
+          <execution>
+            <goals>
+              <goal>toolchain</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <toolchains>
+            <jdk>
+              <version>11</version>
+            </jdk>
+          </toolchains>
+        </configuration>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jlink-plugin</artifactId>
+        <version>@project.version@</version>
+        <extensions>true</extensions>
+        <configuration>
+          <noHeaderFiles>true</noHeaderFiles>
+          <noManPages>true</noManPages>
+          <verbose>true</verbose>
+        </configuration>
+      </plugin>
+    </plugins>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-compiler-plugin</artifactId>
+          <version>3.8.0</version>
+          <configuration>
+            <source>${maven.compiler.source}</source>
+            <target>${maven.compiler.target}</target>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+  </build>
+
+</project>
diff --git a/src/main/java/org/apache/maven/plugins/jlink/AbstractJLinkExecutor.java b/src/main/java/org/apache/maven/plugins/jlink/AbstractJLinkExecutor.java
index f6a6799..3213736 100644
--- a/src/main/java/org/apache/maven/plugins/jlink/AbstractJLinkExecutor.java
+++ b/src/main/java/org/apache/maven/plugins/jlink/AbstractJLinkExecutor.java
@@ -21,10 +21,8 @@ package org.apache.maven.plugins.jlink;
 
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.logging.Log;
-import org.apache.maven.toolchain.Toolchain;
 
 import java.io.File;
-import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
@@ -34,23 +32,16 @@ abstract class AbstractJLinkExecutor
 {
     protected static final String JMODS = "jmods";
 
-    private final Toolchain toolchain;
     private final Log log;
 
     private final List<String> modulesToAdd = new ArrayList<>();
     private final List<String> modulePaths = new ArrayList<>();
 
-    AbstractJLinkExecutor( Toolchain toolchain, Log log ) throws IOException
+    AbstractJLinkExecutor( Log log )
     {
-        this.toolchain = toolchain;
         this.log = log;
     }
 
-    protected Toolchain getToolchain()
-    {
-        return this.toolchain;
-    }
-
     protected Log getLog()
     {
         return this.log;
diff --git a/src/main/java/org/apache/maven/plugins/jlink/AbstractJLinkMojo.java b/src/main/java/org/apache/maven/plugins/jlink/AbstractJLinkMojo.java
index 7443b76..74bef13 100644
--- a/src/main/java/org/apache/maven/plugins/jlink/AbstractJLinkMojo.java
+++ b/src/main/java/org/apache/maven/plugins/jlink/AbstractJLinkMojo.java
@@ -20,11 +20,11 @@ package org.apache.maven.plugins.jlink;
  */
 
 import java.io.File;
-import java.io.IOException;
 import java.lang.reflect.Method;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.plugin.AbstractMojo;
@@ -60,12 +60,11 @@ public abstract class AbstractJLinkMojo
     private ToolchainManager toolchainManager;
 
     protected JLinkExecutor getJlinkExecutor()
-            throws IOException
     {
-        return new JLinkExecutor( getToolchain(), getLog() );
+        return new JLinkExecutor( getToolchain().orElse( null ), getLog() );
     }
 
-    protected Toolchain getToolchain()
+    protected Optional<Toolchain> getToolchain()
     {
         Toolchain tc = null;
 
@@ -106,7 +105,7 @@ public abstract class AbstractJLinkMojo
             tc = toolchainManager.getToolchainFromBuildContext( "jdk", getSession() );
         }
 
-        return tc;
+        return Optional.ofNullable( tc );
     }
 
     protected MavenProject getProject()
diff --git a/src/main/java/org/apache/maven/plugins/jlink/AbstractJLinkToolchainExecutor.java b/src/main/java/org/apache/maven/plugins/jlink/AbstractJLinkToolchainExecutor.java
new file mode 100644
index 0000000..a38a9c7
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugins/jlink/AbstractJLinkToolchainExecutor.java
@@ -0,0 +1,204 @@
+package org.apache.maven.plugins.jlink;
+
+/*
+ * 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.
+ */
+
+import org.apache.commons.lang3.SystemUtils;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.shared.utils.cli.CommandLineException;
+import org.apache.maven.shared.utils.cli.CommandLineUtils;
+import org.apache.maven.shared.utils.cli.Commandline;
+import org.apache.maven.toolchain.Toolchain;
+import org.codehaus.plexus.util.StringUtils;
+
+import java.io.File;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Optional;
+
+abstract class AbstractJLinkToolchainExecutor extends AbstractJLinkExecutor
+{
+    private final Toolchain toolchain;
+
+    AbstractJLinkToolchainExecutor( Toolchain toolchain, Log log )
+    {
+        super( log );
+        this.toolchain = toolchain;
+    }
+
+    protected Optional<Toolchain> getToolchain()
+    {
+        return Optional.ofNullable( this.toolchain );
+    }
+
+    /**
+     * Execute JLink via toolchain.
+     *
+     * @return the exit code ({@code 0} on success).
+     */
+    @Override
+    public int executeJlink( List<String> jlinkArgs ) throws MojoExecutionException
+    {
+        File jlinkExecutable = getJlinkExecutable();
+        getLog().info( "Toolchain in maven-jlink-plugin: jlink [ " + jlinkExecutable + " ]" );
+
+        Commandline cmd = createJLinkCommandLine( jlinkArgs );
+        cmd.setExecutable( jlinkExecutable.getAbsolutePath() );
+
+        return executeCommand( cmd );
+    }
+
+    private File getJlinkExecutable()
+    {
+        return new File( getJLinkExecutable() );
+    }
+
+    @Override
+    public Optional<File> getJmodsFolder( /* nullable */ File sourceJdkModules )
+    {
+        // Really Hacky...do we have a better solution to find the jmods directory of the JDK?
+        File jLinkParent = getJlinkExecutable().getParentFile().getParentFile();
+        File jmodsFolder;
+        if ( sourceJdkModules != null && sourceJdkModules.isDirectory() )
+        {
+            jmodsFolder = new File( sourceJdkModules, JMODS );
+        }
+        else
+        {
+            jmodsFolder = new File( jLinkParent, JMODS );
+        }
+
+        getLog().debug( " Parent: " + jLinkParent.getAbsolutePath() );
+        getLog().debug( " jmodsFolder: " + jmodsFolder.getAbsolutePath() );
+
+        return Optional.of( jmodsFolder );
+    }
+
+    private Commandline createJLinkCommandLine( List<String> jlinkArgs )
+    {
+        Commandline cmd = new Commandline();
+        jlinkArgs.forEach( arg -> cmd.createArg().setValue( arg ) );
+
+        return cmd;
+    }
+
+    private String getJLinkExecutable()
+    {
+        Optional<Toolchain> toolchain = getToolchain();
+
+        if ( !toolchain.isPresent() )
+        {
+            getLog().error( "Either JDK9+ or a toolchain "
+                    + "pointing to a JDK9+ containing a jlink binary is required." );
+            getLog().info( "See https://maven.apache.org/guides/mini/guide-using-toolchains.html "
+                    + "for mor information." );
+            throw new IllegalStateException( "Running on JDK8 and no toolchain found." );
+        }
+
+        String jLinkExecutable = toolchain.orElseThrow( NoSuchElementException::new ).findTool( "jlink" );
+
+        if ( StringUtils.isEmpty( jLinkExecutable ) )
+        {
+            throw new IllegalStateException( "The jlink executable '"
+                    + jLinkExecutable + "' doesn't exist or is not a file." );
+        }
+
+        // TODO: Check if there exist a more elegant way?
+        String jLinkCommand = "jlink" + ( SystemUtils.IS_OS_WINDOWS ? ".exe" : "" );
+
+        File jLinkExe = new File( jLinkExecutable );
+
+        if ( jLinkExe.isDirectory() )
+        {
+            jLinkExe = new File( jLinkExe, jLinkCommand );
+        }
+
+        if ( SystemUtils.IS_OS_WINDOWS && jLinkExe.getName().indexOf( '.' ) < 0 )
+        {
+            jLinkExe = new File( jLinkExe.getPath() + ".exe" );
+        }
+
+        if ( !jLinkExe.isFile() )
+        {
+            throw new IllegalStateException( "The jlink executable '"
+                    + jLinkExe + "' doesn't exist or is not a file." );
+        }
+        return jLinkExe.getAbsolutePath();
+    }
+
+    private int executeCommand( Commandline cmd )
+            throws MojoExecutionException
+    {
+        if ( getLog().isDebugEnabled() )
+        {
+            // no quoted arguments ???
+            getLog().debug( CommandLineUtils.toString( cmd.getCommandline() ).replaceAll( "'", "" ) );
+        }
+
+        CommandLineUtils.StringStreamConsumer err = new CommandLineUtils.StringStreamConsumer();
+        CommandLineUtils.StringStreamConsumer out = new CommandLineUtils.StringStreamConsumer();
+        try
+        {
+            int exitCode = CommandLineUtils.executeCommandLine( cmd, out, err );
+
+            String output = ( StringUtils.isEmpty( out.getOutput() ) ? null : '\n' + out.getOutput().trim() );
+
+            if ( exitCode != 0 )
+            {
+
+                if ( StringUtils.isNotEmpty( output ) )
+                {
+                    // Reconsider to use WARN / ERROR ?
+                    //  getLog().error( output );
+                    for ( String outputLine : output.split( "\n" ) )
+                    {
+                        getLog().error( outputLine );
+                    }
+                }
+
+                StringBuilder msg = new StringBuilder( "\nExit code: " );
+                msg.append( exitCode );
+                if ( StringUtils.isNotEmpty( err.getOutput() ) )
+                {
+                    msg.append( " - " ).append( err.getOutput() );
+                }
+                msg.append( '\n' );
+                msg.append( "Command line was: " ).append( cmd ).append( '\n' ).append( '\n' );
+
+                throw new MojoExecutionException( msg.toString() );
+            }
+
+            if ( StringUtils.isNotEmpty( output ) )
+            {
+                //getLog().info( output );
+                for ( String outputLine : output.split( "\n" ) )
+                {
+                    getLog().info( outputLine );
+                }
+            }
+
+            return exitCode;
+        }
+        catch ( CommandLineException e )
+        {
+            throw new MojoExecutionException( "Unable to execute jlink command: " + e.getMessage(), e );
+        }
+    }
+}
diff --git a/src/main/java/org/apache/maven/plugins/jlink/JLinkExecutor.java b/src/main/java/org/apache/maven/plugins/jlink/JLinkExecutor.java
index a9299c3..7482adb 100644
--- a/src/main/java/org/apache/maven/plugins/jlink/JLinkExecutor.java
+++ b/src/main/java/org/apache/maven/plugins/jlink/JLinkExecutor.java
@@ -19,120 +19,19 @@ package org.apache.maven.plugins.jlink;
  * under the License.
  */
 
-import org.apache.commons.lang3.SystemUtils;
 import org.apache.maven.plugin.logging.Log;
 import org.apache.maven.toolchain.Toolchain;
-import org.codehaus.plexus.util.StringUtils;
-import org.codehaus.plexus.util.cli.Commandline;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.List;
-import java.util.Optional;
 
 /**
  * JDK 8-only Jlink executor.
  *
  * <p>As JDK8 does not ship jlink, a toolchain is required.</p>
  */
-class JLinkExecutor extends AbstractJLinkExecutor
+class JLinkExecutor extends AbstractJLinkToolchainExecutor
 {
-    private final String jLinkExec;
-
-    JLinkExecutor( Toolchain toolchain, Log log ) throws IOException
+    JLinkExecutor( Toolchain toolchain, Log log )
     {
         super( toolchain, log );
-        this.jLinkExec = getJLinkExecutable();
-    }
-
-    public File getJlinkExecutable()
-    {
-        return new File( this.jLinkExec );
-    }
-
-    @Override
-    public Optional<File> getJmodsFolder( /* nullable */ File sourceJdkModules )
-    {
-        // Really Hacky...do we have a better solution to find the jmods directory of the JDK?
-        File jLinkParent = getJlinkExecutable().getParentFile().getParentFile();
-        File jmodsFolder;
-        if ( sourceJdkModules != null && sourceJdkModules.isDirectory() )
-        {
-            jmodsFolder = new File( sourceJdkModules, JMODS );
-        }
-        else
-        {
-            jmodsFolder = new File( jLinkParent, JMODS );
-        }
-
-        getLog().debug( " Parent: " + jLinkParent.getAbsolutePath() );
-        getLog().debug( " jmodsFolder: " + jmodsFolder.getAbsolutePath() );
-
-        return Optional.of( jmodsFolder );
-    }
-
-    /**
-     * Execute JLink via any means.
-     *
-     * @return the exit code ({@code 0} on success).
-     */
-    @Override
-    public int executeJlink( List<String> jlinkArgs )
-    {
-        getLog().info( "Toolchain in maven-jlink-plugin: jlink [ " + this.jLinkExec + " ]" );
-
-        Commandline cmd = createJLinkCommandLine( jlinkArgs );
-        cmd.setExecutable( this.jLinkExec );
-
-        throw new UnsupportedOperationException( "not implemented" );
     }
 
-    private Commandline createJLinkCommandLine( List<String> jlinkArgs )
-    {
-        Commandline cmd = new Commandline();
-        jlinkArgs.forEach( arg -> cmd.createArg().setValue( arg ) );
-
-        return cmd;
-    }
-
-
-    protected final String getJLinkExecutable() throws IOException
-    {
-        if ( getToolchain() == null )
-        {
-            getLog().error( "Either JDK9+ or a toolchain "
-                    + "pointing to a JDK9+ containing a jlink binary is required." );
-            getLog().info( "See https://maven.apache.org/guides/mini/guide-using-toolchains.html "
-                    + "for mor information." );
-            throw new IllegalStateException( "Running on JDK8 and no toolchain found." );
-        }
-
-        String jLinkExecutable = getToolchain().findTool( "jlink" );
-
-        if ( StringUtils.isEmpty( jLinkExecutable ) )
-        {
-            throw new IOException( "The jlink executable '" + jLinkExecutable + "' doesn't exist or is not a file." );
-        }
-
-        // TODO: Check if there exist a more elegant way?
-        String jLinkCommand = "jlink" + ( SystemUtils.IS_OS_WINDOWS ? ".exe" : "" );
-
-        File jLinkExe = new File( jLinkExecutable );
-
-        if ( jLinkExe.isDirectory() )
-        {
-            jLinkExe = new File( jLinkExe, jLinkCommand );
-        }
-
-        if ( SystemUtils.IS_OS_WINDOWS && jLinkExe.getName().indexOf( '.' ) < 0 )
-        {
-            jLinkExe = new File( jLinkExe.getPath() + ".exe" );
-        }
-
-        if ( !jLinkExe.isFile() )
-        {
-            throw new IOException( "The jlink executable '" + jLinkExe + "' doesn't exist or is not a file." );
-        }
-        return jLinkExe.getAbsolutePath();
-    }
 }
diff --git a/src/main/java/org/apache/maven/plugins/jlink/JLinkMojo.java b/src/main/java/org/apache/maven/plugins/jlink/JLinkMojo.java
index c1ebfb6..3256565 100644
--- a/src/main/java/org/apache/maven/plugins/jlink/JLinkMojo.java
+++ b/src/main/java/org/apache/maven/plugins/jlink/JLinkMojo.java
@@ -28,6 +28,8 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.NoSuchElementException;
+import java.util.Optional;
 
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.plugin.MojoExecutionException;
@@ -308,7 +310,14 @@ public class JLinkMojo
 
         List<String> jlinkArgs = createJlinkArgs( pathsOfModules, modulesToAdd );
 
-        jLinkExec.executeJlink( jlinkArgs );
+        try
+        {
+            jLinkExec.executeJlink( jlinkArgs );
+        }
+        catch ( IllegalStateException e )
+        {
+            throw new MojoFailureException( "Unable to find jlink command: " + e.getMessage(), e );
+        }
 
         File createZipArchiveFromImage = createZipArchiveFromImage( buildDirectory, outputDirectoryImage );
 
@@ -348,10 +357,12 @@ public class JLinkMojo
 
             ResolvePathsRequest<File> request = ResolvePathsRequest.ofFiles( dependencyArtifacts );
 
-            Toolchain toolchain = getToolchain();
-            if ( toolchain != null && toolchain instanceof DefaultJavaToolChain )
+            Optional<Toolchain> toolchain = getToolchain();
+            if ( toolchain.isPresent()
+                    && toolchain.orElseThrow( NoSuchElementException::new ) instanceof DefaultJavaToolChain )
             {
-                request.setJdkHome( new File( ( (DefaultJavaToolChain) toolchain ).getJavaHome() ) );
+                Toolchain toolcahin1 = toolchain.orElseThrow( NoSuchElementException::new );
+                request.setJdkHome( new File( ( (DefaultJavaToolChain) toolcahin1 ).getJavaHome() ) );
             }
 
             ResolvePathsResult<File> resolvePathsResult = locationManager.resolvePaths( request );
@@ -412,18 +423,9 @@ public class JLinkMojo
         return modulepathElements;
     }
 
-    private JLinkExecutor getExecutor() throws MojoFailureException
+    private JLinkExecutor getExecutor()
     {
-        JLinkExecutor jLinkExec;
-        try
-        {
-            jLinkExec = getJlinkExecutor();
-        }
-        catch ( IOException e )
-        {
-            throw new MojoFailureException( "Unable to find jlink command: " + e.getMessage(), e );
-        }
-        return jLinkExec;
+        return getJlinkExecutor();
     }
 
     private boolean projectHasAlreadySetAnArtifact()
diff --git a/src/main/java9/org/apache/maven/plugins/jlink/JLinkExecutor.java b/src/main/java9/org/apache/maven/plugins/jlink/JLinkExecutor.java
index 7310a3e..d562816 100644
--- a/src/main/java9/org/apache/maven/plugins/jlink/JLinkExecutor.java
+++ b/src/main/java9/org/apache/maven/plugins/jlink/JLinkExecutor.java
@@ -38,9 +38,8 @@ import java.util.spi.ToolProvider;
  * <p>This implementation uses the JDK9+ Toolprovider SPI to find and execute jlink.
  * This way, no fork needs to be created.</p>
  */
-class JLinkExecutor extends AbstractJLinkExecutor
+class JLinkExecutor extends AbstractJLinkToolchainExecutor
 {
-
     private final ToolProvider toolProvider;
 
     JLinkExecutor( Toolchain toolchain, Log log ) throws IOException
@@ -49,18 +48,6 @@ class JLinkExecutor extends AbstractJLinkExecutor
         this.toolProvider = getJLinkExecutable();
     }
 
-    @Override
-    public Optional<File> getJmodsFolder( /* nullable */ File sourceJdkModules )
-    {
-        if ( sourceJdkModules != null && sourceJdkModules.isDirectory() )
-        {
-            return Optional.of( new File( sourceJdkModules, JMODS ) );
-        }
-
-        // ToolProvider does not need jmods folder to be set.
-        return Optional.empty();
-    }
-
     protected final ToolProvider getJLinkExecutable()
     {
         return ToolProvider
@@ -71,6 +58,11 @@ class JLinkExecutor extends AbstractJLinkExecutor
     @Override
     public int executeJlink( List<String> jlinkArgs ) throws MojoExecutionException
     {
+        if (getToolchain().isPresent())
+        {
+            return super.executeJlink( jlinkArgs );
+        }
+
         if ( getLog().isDebugEnabled() )
         {
             // no quoted arguments ???
@@ -131,4 +123,21 @@ class JLinkExecutor extends AbstractJLinkExecutor
             throw new MojoExecutionException( "Unable to execute jlink command: " + e.getMessage(), e );
         }
     }
+
+    @Override
+    public Optional<File> getJmodsFolder( /* nullable */ File sourceJdkModules )
+    {
+        if ( getToolchain().isPresent())
+        {
+            return super.getJmodsFolder( sourceJdkModules );
+        }
+
+        if ( sourceJdkModules != null && sourceJdkModules.isDirectory() )
+        {
+            return Optional.of( new File( sourceJdkModules, JMODS ) );
+        }
+
+        // ToolProvider does not need jmods folder to be set.
+        return Optional.empty();
+    }
 }