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

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


The following commit(s) were added to refs/heads/master by this push:
     new f8bdf50  Java 9+ ToolProvider via multi-release jar.
f8bdf50 is described below

commit f8bdf5050c266854524aaa51eb36109c00ca692a
Author: Benjamin Marwell <bmarw...@apache.org>
AuthorDate: Tue Nov 24 18:53:35 2020 +0100

    Java 9+ ToolProvider via multi-release jar.
    
    Signed-off-by: rfscholte <rfscho...@apache.org>
---
 pom.xml                                            |  47 +++++
 .../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 ++++++++++
 .../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} |  41 ++---
 .../org/apache/maven/plugins/jlink/JLinkMojo.java  | 160 ++++++----------
 .../apache/maven/plugins/jlink/JLinkExecutor.java  | 143 +++++++++++++++
 12 files changed, 772 insertions(+), 286 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/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/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
new file mode 100644
index 0000000..3213736
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugins/jlink/AbstractJLinkExecutor.java
@@ -0,0 +1,63 @@
+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 java.io.File;
+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 Log log;
+
+    private final List<String> modulesToAdd = new ArrayList<>();
+    private final List<String> modulePaths = new ArrayList<>();
+
+    AbstractJLinkExecutor( Log log )
+    {
+        this.log = log;
+    }
+
+    protected Log getLog()
+    {
+        return this.log;
+    }
+
+    public abstract Optional<File> getJmodsFolder( /* nullable */ File 
sourceJdkModules );
+
+    public abstract int executeJlink( List<String> jlinkArgs ) 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..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,26 +20,19 @@ 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.Properties;
+import java.util.Optional;
 
-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:khmarba...@apache.org";>khmarba...@apache.org</a>
@@ -66,139 +59,12 @@ public abstract class AbstractJLinkMojo
     @Component
     private ToolchainManager toolchainManager;
 
-    protected String getJLinkExecutable()
-        throws IOException
+    protected JLinkExecutor getJlinkExecutor()
     {
-        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().orElse( null ), getLog() );
     }
 
-    protected Toolchain getToolchain()
+    protected Optional<Toolchain> getToolchain()
     {
         Toolchain tc = null;
 
@@ -207,12 +73,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,10 +102,10 @@ 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;
+        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/it/projects/MJLINK-40_includeLocales/verify.groovy 
b/src/main/java/org/apache/maven/plugins/jlink/JLinkExecutor.java
similarity index 52%
copy from src/it/projects/MJLINK-40_includeLocales/verify.groovy
copy to src/main/java/org/apache/maven/plugins/jlink/JLinkExecutor.java
index 1887547..7482adb 100644
--- a/src/it/projects/MJLINK-40_includeLocales/verify.groovy
+++ b/src/main/java/org/apache/maven/plugins/jlink/JLinkExecutor.java
@@ -1,3 +1,5 @@
+package org.apache.maven.plugins.jlink;
+
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -17,38 +19,19 @@
  * under the License.
  */
 
-import java.io.*;
-import java.util.*;
-import java.util.jar.*;
-import org.codehaus.plexus.util.*;
-
-boolean result = false;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.toolchain.Toolchain;
 
-try
+/**
+ * JDK 8-only Jlink executor.
+ *
+ * <p>As JDK8 does not ship jlink, a toolchain is required.</p>
+ */
+class JLinkExecutor extends AbstractJLinkToolchainExecutor
 {
-    File target = new File( basedir, "target" );
-    if ( !target.exists() || !target.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() )
+    JLinkExecutor( Toolchain toolchain, Log log )
     {
-        System.err.println( "jlinkArgs file is missing or is a directory." );
-        return false;
+        super( toolchain, log );
     }
 
-    def line = jlinkArgs.eachLine { line ->
-        if (line.equals('en,ja,de,*-IN'))
-        {
-            result = true;
-        }
-    }
 }
-catch( Throwable e )
-{
-    e.printStackTrace();
-}
-
-return result;
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..3256565 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;
@@ -29,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;
@@ -49,7 +50,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 +64,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 +272,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 +303,28 @@ 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 );
+
+        List<String> jlinkArgs = createJlinkArgs( pathsOfModules, modulesToAdd 
);
 
-        Commandline cmd;
         try
         {
-            cmd = createJLinkCommandLine( pathsOfModules, modulesToAdd );
+            jLinkExec.executeJlink( jlinkArgs );
         }
-        catch ( IOException e )
+        catch ( IllegalStateException e )
         {
-            throw new MojoExecutionException( e.getMessage() );
+            throw new MojoFailureException( "Unable to find jlink command: " + 
e.getMessage(), e );
         }
-        cmd.setExecutable( jLinkExec );
-
-        executeCommand( cmd, outputDirectoryImage );
 
         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 );
@@ -379,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 );
@@ -443,19 +423,9 @@ public class JLinkMojo
         return modulepathElements;
     }
 
-    private String getExecutable()
-        throws MojoFailureException
+    private JLinkExecutor getExecutor()
     {
-        String jLinkExec;
-        try
-        {
-            jLinkExec = getJLinkExecutable();
-        }
-        catch ( IOException e )
-        {
-            throw new MojoFailureException( "Unable to find jlink command: " + 
e.getMessage(), e );
-        }
-        return jLinkExec;
+        return getJlinkExecutor();
     }
 
     private boolean projectHasAlreadySetAnArtifact()
@@ -510,7 +480,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,130 +507,116 @@ public class JLinkMojo
         }
     }
 
-    private Commandline createJLinkCommandLine( Collection<String> 
pathsOfModules, Collection<String> modulesToAdd )
-        throws IOException
+    private List<String> createJlinkArgs( Collection<String> pathsOfModules,
+                                      Collection<String> modulesToAdd )
     {
-        File file = new File( 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();
-
-        Commandline cmd = new Commandline();
-        cmd.createArg().setValue( '@' + file.getAbsolutePath() );
 
-        return cmd;
+        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
new file mode 100644
index 0000000..d562816
--- /dev/null
+++ b/src/main/java9/org/apache/maven/plugins/jlink/JLinkExecutor.java
@@ -0,0 +1,143 @@
+/*
+ * 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.util.List;
+import java.util.Optional;
+import java.util.spi.ToolProvider;
+
+/**
+ * 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 AbstractJLinkToolchainExecutor
+{
+    private final ToolProvider toolProvider;
+
+    JLinkExecutor( Toolchain toolchain, Log log ) throws IOException
+    {
+        super( toolchain, log );
+        this.toolProvider = getJLinkExecutable();
+    }
+
+    protected final ToolProvider getJLinkExecutable()
+    {
+        return ToolProvider
+                .findFirst( "jlink" )
+                .orElseThrow( () -> new IllegalStateException( "No jlink tool 
found." ) );
+    }
+
+    @Override
+    public int executeJlink( List<String> jlinkArgs ) throws 
MojoExecutionException
+    {
+        if (getToolchain().isPresent())
+        {
+            return super.executeJlink( jlinkArgs );
+        }
+
+        if ( getLog().isDebugEnabled() )
+        {
+            // no quoted arguments ???
+            getLog().debug( this.toolProvider.name() + " " + jlinkArgs );
+        }
+
+        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, jlinkArgs.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(
+                        jlinkArgs ).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 );
+        }
+    }
+
+    @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();
+    }
+}

Reply via email to