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

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

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

    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:[email protected]";>[email protected]</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 via email to