View Javadoc
1   package org.apache.maven.plugins.jmod;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.io.IOException;
24  import java.lang.reflect.InvocationTargetException;
25  import java.lang.reflect.Method;
26  import java.util.List;
27  import java.util.Map;
28  import java.util.Properties;
29  
30  import org.apache.commons.lang3.SystemUtils;
31  import org.apache.maven.execution.MavenSession;
32  import org.apache.maven.plugin.AbstractMojo;
33  import org.apache.maven.plugin.MojoExecutionException;
34  import org.apache.maven.plugins.annotations.Component;
35  import org.apache.maven.plugins.annotations.Parameter;
36  import org.apache.maven.project.MavenProject;
37  import org.apache.maven.toolchain.Toolchain;
38  import org.apache.maven.toolchain.ToolchainManager;
39  import org.codehaus.plexus.util.StringUtils;
40  import org.codehaus.plexus.util.cli.CommandLineException;
41  import org.codehaus.plexus.util.cli.CommandLineUtils;
42  import org.codehaus.plexus.util.cli.Commandline;
43  
44  /**
45   * This contains the code to handle toolchains and the execution of the command which is similar to code in
46   * maven-jlink-plugin (maven-jdeps-plugin?). Later we need to think about a way to combine that code to reduce
47   * duplication.
48   * 
49   * @author Karl Heinz Marbaise <a href="mailto:khmarbaise@apache.org">khmarbaise@apache.org</a>
50   */
51  public abstract class AbstractJModMojo
52      extends AbstractMojo
53  {
54  
55      @Parameter( defaultValue = "${project}", readonly = true, required = true )
56      private MavenProject project;
57  
58      @Parameter( defaultValue = "${session}", readonly = true, required = true )
59      private MavenSession session;
60  
61      @Component
62      private ToolchainManager toolchainManager;
63  
64      /**
65       * <p>
66       * Specify the requirements for this jdk toolchain. This overrules the toolchain selected by the
67       * maven-toolchain-plugin.
68       * </p>
69       * <strong>note:</strong> requires at least Maven 3.3.1
70       */
71      @Parameter
72      private Map<String, String> jdkToolchain;
73      
74      // TODO: Check how to prevent code duplication in maven-jlink, maven-jmod and maven-jdeps plugin?
75      protected String getJModExecutable()
76          throws IOException
77      {
78          Toolchain tc = getToolchain();
79  
80          String jModExecutable = null;
81          if ( tc != null )
82          {
83              jModExecutable = tc.findTool( "jmod" );
84          }
85  
86          String jModCommand = "jmod" + ( SystemUtils.IS_OS_WINDOWS ? ".exe" : "" );
87  
88          File jModExe;
89  
90          if ( StringUtils.isNotEmpty( jModExecutable ) )
91          {
92              jModExe = new File( jModExecutable );
93  
94              if ( jModExe.isDirectory() )
95              {
96                  jModExe = new File( jModExe, jModCommand );
97              }
98  
99              if ( SystemUtils.IS_OS_WINDOWS && jModExe.getName().indexOf( '.' ) < 0 )
100             {
101                 jModExe = new File( jModExe.getPath() + ".exe" );
102             }
103 
104             if ( !jModExe.isFile() )
105             {
106                 throw new IOException( "The jmod executable '" + jModExe + "' doesn't exist or is not a file." );
107             }
108             return jModExe.getAbsolutePath();
109         }
110 
111         // ----------------------------------------------------------------------
112         // Try to find jmod from System.getProperty( "java.home" )
113         // By default, System.getProperty( "java.home" ) = JRE_HOME and JRE_HOME
114         // should be in the JDK_HOME
115         // ----------------------------------------------------------------------
116         jModExe = new File( SystemUtils.getJavaHome() + File.separator + ".." + File.separator + "bin", jModCommand );
117 
118         // ----------------------------------------------------------------------
119         // Try to find jmod from JAVA_HOME environment variable
120         // ----------------------------------------------------------------------
121         if ( !jModExe.exists() || !jModExe.isFile() )
122         {
123             Properties env = CommandLineUtils.getSystemEnvVars();
124             String javaHome = env.getProperty( "JAVA_HOME" );
125             if ( StringUtils.isEmpty( javaHome ) )
126             {
127                 throw new IOException( "The environment variable JAVA_HOME is not correctly set." );
128             }
129             if ( ( !new File( javaHome ).getCanonicalFile().exists() )
130                 || ( new File( javaHome ).getCanonicalFile().isFile() ) )
131             {
132                 throw new IOException( "The environment variable JAVA_HOME=" + javaHome
133                     + " doesn't exist or is not a valid directory." );
134             }
135 
136             jModExe = new File( javaHome + File.separator + "bin", jModCommand );
137         }
138 
139         if ( !jModExe.getCanonicalFile().exists() || !jModExe.getCanonicalFile().isFile() )
140         {
141             throw new IOException( "The jmod executable '" + jModExe
142                 + "' doesn't exist or is not a file. Verify the JAVA_HOME environment variable." );
143         }
144 
145         return jModExe.getAbsolutePath();
146     }
147 
148     protected boolean projectHasAlreadySetAnArtifact()
149     {
150         if ( getProject().getArtifact().getFile() != null )
151         {
152             return getProject().getArtifact().getFile().isFile();
153         }
154         else
155         {
156             return false;
157         }
158     }
159 
160     protected void executeCommand( Commandline cmd, File outputDirectory )
161         throws MojoExecutionException
162     {
163         if ( getLog().isDebugEnabled() )
164         {
165             // no quoted arguments ???
166             getLog().debug( CommandLineUtils.toString( cmd.getCommandline() ).replaceAll( "'", "" ) );
167         }
168 
169         CommandLineUtils.StringStreamConsumer err = new CommandLineUtils.StringStreamConsumer();
170         CommandLineUtils.StringStreamConsumer out = new CommandLineUtils.StringStreamConsumer();
171         try
172         {
173             int exitCode = CommandLineUtils.executeCommandLine( cmd, out, err );
174 
175             String output = ( StringUtils.isEmpty( out.getOutput() ) ? null : '\n' + out.getOutput().trim() );
176 
177             if ( exitCode != 0 )
178             {
179                 if ( StringUtils.isNotEmpty( output ) )
180                 {
181                     // Reconsider to use WARN / ERROR ?
182                     getLog().info( output );
183                 }
184 
185                 StringBuilder msg = new StringBuilder( "\nExit code: " );
186                 msg.append( exitCode );
187                 if ( StringUtils.isNotEmpty( err.getOutput() ) )
188                 {
189                     msg.append( " - " ).append( err.getOutput() );
190                 }
191                 msg.append( '\n' );
192                 msg.append( "Command line was: " ).append( cmd ).append( '\n' ).append( '\n' );
193 
194                 throw new MojoExecutionException( msg.toString() );
195             }
196 
197             if ( StringUtils.isNotEmpty( output ) )
198             {
199                 String[] splitLines = StringUtils.split( output, "\n" );
200                 for ( String outputLine : splitLines )
201                 {
202                     getLog().info( outputLine );
203                 }
204             }
205         }
206         catch ( CommandLineException e )
207         {
208             throw new MojoExecutionException( "Unable to execute jmod command: " + e.getMessage(), e );
209         }
210 
211     }
212 
213     /**
214      * Convert a list into a
215      * 
216      * @param modules The list of modules.
217      * @return The string with the module list which is separated by {@code ,}.
218      */
219     protected String getCommaSeparatedList( List<String> modules )
220     {
221         StringBuilder sb = new StringBuilder();
222         for ( String module : modules )
223         {
224             if ( sb.length() > 0 )
225             {
226                 sb.append( ',' );
227             }
228             sb.append( module );
229         }
230         return sb.toString();
231     }
232 
233     protected Toolchain getToolchain()
234     {
235         Toolchain tc = null;
236 
237         if ( jdkToolchain != null )
238         {
239             // Maven 3.3.1 has plugin execution scoped Toolchain Support
240             try
241             {
242                 Method getToolchainsMethod = toolchainManager.getClass().getMethod( "getToolchains", MavenSession.class,
243                                                                                     String.class, Map.class );
244 
245                 @SuppressWarnings( "unchecked" )
246                 List<Toolchain> tcs =
247                     (List<Toolchain>) getToolchainsMethod.invoke( toolchainManager, session, "jdk", jdkToolchain );
248 
249                 if ( tcs != null && tcs.size() > 0 )
250                 {
251                     tc = tcs.get( 0 );
252                 }
253             }
254             catch ( NoSuchMethodException e )
255             {
256                 // ignore
257             }
258             catch ( SecurityException e )
259             {
260                 // ignore
261             }
262             catch ( IllegalAccessException e )
263             {
264                 // ignore
265             }
266             catch ( IllegalArgumentException e )
267             {
268                 // ignore
269             }
270             catch ( InvocationTargetException e )
271             {
272                 // ignore
273             }
274         }
275 
276         if ( tc == null )
277         {
278             // TODO: Check if we should make the type configurable?
279             tc = toolchainManager.getToolchainFromBuildContext( "jdk", session );
280         }
281 
282         return tc;
283     }
284     public MavenProject getProject()
285     {
286         return project;
287     }
288 
289     public MavenSession getSession()
290     {
291         return session;
292     }
293 
294 }