Continued maven-jlink-plugin

git-svn-id: https://svn.apache.org/repos/asf/maven/plugins/trunk@1763964 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/pom.xml b/pom.xml
index d2dc19c..0d1b72f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -61,6 +61,8 @@
 

   <properties>

     <mavenVersion>3.0</mavenVersion>

+    <maven.compiler.source>1.7</maven.compiler.source>

+    <maven.compiler.target>1.7</maven.compiler.target>

   </properties>

 

   <dependencies>

@@ -85,5 +87,59 @@
       <artifactId>commons-lang</artifactId>

       <version>2.4</version>

     </dependency>

+<!--     <dependency> -->

+<!--       <groupId>org.mockito</groupId> -->

+<!--       <artifactId>mockito-core</artifactId> -->

+<!--       <version>1.9.5</version> -->

+<!--       <scope>test</scope> -->

+<!--     </dependency> -->

+    <dependency>

+      <groupId>junit</groupId>

+      <artifactId>junit</artifactId>

+      <version>4.12</version>

+      <scope>test</scope>

+    </dependency>

+

+    <dependency>

+      <groupId>io.takari.maven.plugins</groupId>

+      <artifactId>takari-plugin-testing</artifactId>

+      <version>2.9.0</version>

+      <scope>test</scope>

+    </dependency>

+    <dependency> <!-- used by takari-plugin-testing, don't give it compile scope! -->

+      <groupId>org.apache.maven</groupId>

+      <artifactId>maven-compat</artifactId>

+      <version>${mavenVersion}</version>

+      <scope>test</scope>

+    </dependency>

+

   </dependencies>

+

+  <build>

+    <resources>

+      <resource>

+        <directory>src/main/filtered-resources</directory>

+        <filtering>true</filtering>

+      </resource>

+    </resources>

+  </build>

+<!--   <build> -->

+<!--     <plugins> -->

+<!--       <plugin> -->

+<!--         <groupId>io.takari.maven.plugins</groupId> -->

+<!--         <artifactId>takari-lifecycle-plugin</artifactId> -->

+<!--         <version>1.12.1</version> -->

+<!--         <extensions>true</extensions> -->

+<!--         <executions> -->

+<!--           <execution> -->

+<!--             <id>testProperties</id> -->

+<!--             <phase>process-test-resources</phase> -->

+<!--             <goals> -->

+<!--               <goal>testProperties</goal> -->

+<!--             </goals> -->

+<!--           </execution> -->

+<!--         </executions> -->

+<!--       </plugin> -->

+<!--     </plugins> -->

+<!--   </build> -->

 </project>

diff --git a/src/main/filtered-resources/META-INF/plexus/components.xml b/src/main/filtered-resources/META-INF/plexus/components.xml
new file mode 100644
index 0000000..b1554b1
--- /dev/null
+++ b/src/main/filtered-resources/META-INF/plexus/components.xml
@@ -0,0 +1,77 @@
+<?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.
+-->
+
+<component-set>
+  <components>
+    <!--
+     | JLINK
+     |-->
+    <component>
+      <role>org.apache.maven.artifact.handler.ArtifactHandler</role>
+      <role-hint>jlink</role-hint>
+      <implementation>org.apache.maven.artifact.handler.DefaultArtifactHandler</implementation>
+      <configuration>
+        <type>jlink</type>
+        <includesDependencies>true</includesDependencies>
+        <language>java</language>
+        <addedToClasspath>false</addedToClasspath>
+      </configuration>
+    </component>
+
+    <!--
+      | Defining the phases with their appropriate plugins
+      ! and versions which will be executed during the 'default'
+      ! life cycle.
+    -->
+    <!--
+     | JLINK
+     |-->
+    <component>
+      <role>org.apache.maven.lifecycle.mapping.LifecycleMapping</role>
+      <role-hint>jlink</role-hint>
+      <implementation>org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping</implementation>
+      <configuration>
+        <lifecycles>
+          <lifecycle>
+            <id>default</id>
+            <!-- START SNIPPET: jlink-lifecycle -->
+            <phases>
+              <process-resources>
+                org.apache.maven.plugins:maven-resources-plugin:3.0.1:resources
+              </process-resources>
+              <package>
+                org.apache.maven.plugins:maven-jlink-plugin:${project.version}:jlink
+              </package>
+              <install>
+                org.apache.maven.plugins:maven-install-plugin:2.5.2:install
+              </install>
+              <deploy>
+                org.apache.maven.plugins:maven-deploy-plugin:2.8.2:deploy
+              </deploy>
+            </phases>
+            <!-- END SNIPPET: jlink-lifecycle -->
+          </lifecycle>
+        </lifecycles>
+      </configuration>
+    </component>
+
+  </components>
+</component-set>
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 bda6813..4a90d1f 100644
--- a/src/main/java/org/apache/maven/plugins/jlink/AbstractJLinkMojo.java
+++ b/src/main/java/org/apache/maven/plugins/jlink/AbstractJLinkMojo.java
@@ -167,7 +167,7 @@
                 if ( StringUtils.isNotEmpty( output ) )

                 {

                     //Reconsider to use WARN / ERROR ?

-                    getLog().info( output );

+                    getLog().error( output );

                 }

 

                 StringBuilder msg = new StringBuilder( "\nExit code: " );

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 27eb088..8369cb9 100644
--- a/src/main/java/org/apache/maven/plugins/jlink/JLinkMojo.java
+++ b/src/main/java/org/apache/maven/plugins/jlink/JLinkMojo.java
@@ -1,5 +1,24 @@
 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 java.io.File;
 
 /*
@@ -22,14 +41,18 @@
  */
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.commons.lang.SystemUtils;
+import org.apache.maven.model.Dependency;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.plugins.annotations.LifecyclePhase;
 import org.apache.maven.plugins.annotations.Mojo;
 import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.plugins.annotations.ResolutionScope;
+import org.apache.maven.project.MavenProject;
 import org.codehaus.plexus.util.FileUtils;
 import org.codehaus.plexus.util.cli.Commandline;
 
@@ -58,7 +81,9 @@
 // TODO: Think if ResultionScope is needed here? May be we need to reconsider package phase?
 // May be it would be wise to put into PREPARE-PACKAGE and the generation of the final jimage in the package phase?
 // Furthermore It could make sense so we can change the conf files if needed...
-@Mojo( name = "jlink", requiresDependencyResolution = ResolutionScope.COMPILE, defaultPhase = LifecyclePhase.PACKAGE )
+// CHECKSTYLE_OFF: LineLength
+@Mojo( name = "jlink", requiresDependencyResolution = ResolutionScope.COMPILE, defaultPhase = LifecyclePhase.PACKAGE, requiresProject = true )
+// CHECKSTYLE_ON: LineLength
 public class JLinkMojo
     extends AbstractJLinkMojo
 {
@@ -75,10 +100,11 @@
     private Integer compression;
 
     /**
-     * Define the modulepath for the <code>JLink</code> call. <code>--module-path &lt;modulepath&gt;</code>
+     * Define the modulepath for the <code>JLink</code> call. <code>--module-path &lt;modulepath&gt;</code> TODO: The
+     * default should be the jmods folder of the JDK...
      */
-    @Parameter( required = true )
-    private File modulePath;
+    @Parameter
+    private List<String> modulePaths;
 
     /**
      * Limit the univers of observable modules. <code>--limit-modules &lt;mod&gt;[,&lt;mod&gt;...]</code>
@@ -99,12 +125,11 @@
     private File pluginModulePath;
 
     /**
-     * <code>--output &lt;path&gt;</code> 
+     * <code>--output &lt;path&gt;</code>
      * </p>
-     * TODO: Think about the default value? I'm not sure if something different would
-     * be better?
+     * TODO: Think about the default value? I'm not sure if something different would be better?
      */
-    @Parameter( defaultValue = "${project.build.output}/link-result" )
+    @Parameter( defaultValue = "${project.build.directory}/link-result" )
     private File outputDirectory;
 
     /**
@@ -119,27 +144,98 @@
         throws MojoExecutionException, MojoFailureException
     {
 
-        failIfParametersAreNotInTheirValidValueRanges();
-
-        String jLinkExecutable;
+        String jLinkExec;
         try
         {
-            jLinkExecutable = getJLinkExecutable();
+            jLinkExec = getJLinkExecutable();
         }
         catch ( IOException e )
         {
             throw new MojoFailureException( "Unable to find jlink command: " + e.getMessage(), e );
         }
 
+        getLog().info( "Toolchain in maven-jlink-plugin: jlink [ " + jLinkExec + " ]" );
+
+        // TODO: Find a more better and cleaner way?
+        File jLinkExecuteable = new File( jLinkExec );
+
+        // Really Hacky...
+        File jLinkParent = jLinkExecuteable.getParentFile().getParentFile();
+        File jmodsFolder = new File( jLinkParent, "jmods" );
+
+        getLog().debug( " Parent: " + jLinkParent.getAbsolutePath() );
+        getLog().debug( " jmodsFolder: " + jmodsFolder.getAbsolutePath() );
+
+        failIfParametersAreNotInTheirValidValueRanges();
+
         deleteOutputDirectoryIfItAlreadyExists();
 
+        List<MavenProject> sortedProjects = getSession().getProjectDependencyGraph().getSortedProjects();
+        for ( MavenProject mavenProject : sortedProjects )
+        {
+            getLog().info( "MavenProject: " + mavenProject.getBasedir() );
+        }
+
+        List<Dependency> dependencies = getSession().getCurrentProject().getDependencies();
+
+        List<MavenProject> modulesToAdd = new ArrayList<>();
+        for ( Dependency dependency : dependencies )
+        {
+            if ( "jmod".equals( dependency.getType() ) )
+            {
+                MavenProject mp = findDependencyInProjects( dependency );
+                // TODO: What about module name != artifactId which has been
+                // defined in module-info.java file!
+                modulesToAdd.add( mp );
+            }
+        }
+
+        if ( addModules == null )
+        {
+            addModules = new ArrayList<>();
+        }
+        for ( MavenProject mavenProject : modulesToAdd )
+        {
+            addModules.add( mavenProject.getArtifactId() );
+        }
+
+        if ( modulePaths == null )
+        {
+            modulePaths = new ArrayList<>();
+        }
+
+        // JDK mods folder
+        modulePaths.add( jmodsFolder.getAbsolutePath() );
+
+        for ( MavenProject mavenProject : modulesToAdd )
+        {
+            File output = new File( mavenProject.getBuild().getDirectory(), "jmods" );
+            modulePaths.add( output.getAbsolutePath() );
+        }
+
         // Synopsis
         // Usage: jlink <options> --module-path <modulepath> --add-modules <mods> --output <path>
         Commandline cmd = createJLinkCommandLine();
-        cmd.setExecutable( jLinkExecutable );
+        cmd.setExecutable( jLinkExec );
 
         executeCommand( cmd, outputDirectory );
-        
+
+    }
+
+    private MavenProject findDependencyInProjects( Dependency dep )
+    {
+        List<MavenProject> sortedProjects = getSession().getProjectDependencyGraph().getSortedProjects();
+        MavenProject result = null;
+        for ( MavenProject mavenProject : sortedProjects )
+        {
+            if ( dep.getGroupId().equals( mavenProject.getGroupId() )
+                && dep.getArtifactId().equals( mavenProject.getArtifactId() )
+                && dep.getVersion().equals( mavenProject.getVersion() ) )
+            {
+                result = mavenProject;
+            }
+        }
+        return result;
     }
 
     private void failIfParametersAreNotInTheirValidValueRanges()
@@ -152,6 +248,18 @@
             getLog().error( message );
             throw new MojoFailureException( message );
         }
+
+        // CHECK if this assumption here is correct?
+        // if ( modulePaths != null && ( !modulePaths.isEmpty() ) )
+        // {
+        //
+        // // FIXME: Need to check if the given paths exists? and if they are
+        // // folders?
+        // // String message = "The given module-paths parameter " + modulePath.getAbsolutePath()
+        // // + " is not a directory or does not exist.";
+        // // getLog().error( message );
+        // // throw new MojoFailureException( message );
+        // }
     }
 
     private void deleteOutputDirectoryIfItAlreadyExists()
@@ -163,6 +271,7 @@
             // otherwise JLink will fail with a message "Error: directory already exists: ..."
             try
             {
+                getLog().debug( "Deleting existing " + outputDirectory.getAbsolutePath() );
                 FileUtils.forceDelete( outputDirectory );
             }
             catch ( IOException e )
@@ -174,7 +283,7 @@
         }
     }
 
-    private Commandline createJLinkCommandLine()
+    Commandline createJLinkCommandLine()
     {
         Commandline cmd = new Commandline();
 
@@ -189,11 +298,11 @@
             cmd.createArg().setValue( compression.toString() );
         }
 
-        // CHECK if this assumption here is correct?
-        if ( modulePath != null && modulePath.exists() && modulePath.isDirectory() )
+        if ( modulePaths != null )
         {
             cmd.createArg().setValue( "--module-path" );
-            cmd.createArg().setFile( modulePath );
+            StringBuilder sb = getColonSeparateList( modulePaths );
+            cmd.createArg().setValue( sb.toString() );
         }
 
         if ( limitModules != null && !limitModules.isEmpty() )
@@ -219,6 +328,28 @@
         return cmd;
     }
 
+    private StringBuilder getColonSeparateList( List<String> modulePaths )
+    {
+        StringBuilder sb = new StringBuilder();
+        for ( String module : modulePaths )
+        {
+            if ( sb.length() > 0 )
+            {
+                // FIXME: Check this ?
+                if ( SystemUtils.IS_OS_WINDOWS )
+                {
+                    sb.append( ';' );
+                }
+                else
+                {
+                    sb.append( ':' );
+                }
+            }
+            sb.append( module );
+        }
+        return sb;
+    }
+
     private StringBuilder getCommaSeparatedList( List<String> modules )
     {
         StringBuilder sb = new StringBuilder();