View Javadoc
1   package org.apache.maven.plugins.jdeprscan;
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.Method;
25  import java.util.Collections;
26  import java.util.List;
27  import java.util.Map;
28  import java.util.Properties;
29  import java.util.StringTokenizer;
30  
31  import org.apache.commons.lang3.SystemUtils;
32  import org.apache.maven.execution.MavenSession;
33  import org.apache.maven.plugin.AbstractMojo;
34  import org.apache.maven.plugin.MojoExecutionException;
35  import org.apache.maven.plugin.MojoFailureException;
36  import org.apache.maven.plugins.annotations.Component;
37  import org.apache.maven.plugins.annotations.Parameter;
38  import org.apache.maven.toolchain.Toolchain;
39  import org.apache.maven.toolchain.ToolchainManager;
40  import org.codehaus.plexus.util.StringUtils;
41  import org.codehaus.plexus.util.cli.CommandLineException;
42  import org.codehaus.plexus.util.cli.CommandLineUtils;
43  import org.codehaus.plexus.util.cli.Commandline;
44  
45  /**
46   * Abstract class for all mojos
47   * 
48   * @author Robert Scholte
49   * @since 3.0.0
50   */
51  public abstract class AbstractJDeprScanMojo
52      extends AbstractMojo
53  {
54      @Parameter( defaultValue = "${session}", readonly = true, required = true )
55      private MavenSession session;
56      
57      @Component
58      private ToolchainManager toolchainManager;
59  
60      @Override
61      public void execute()
62          throws MojoExecutionException, MojoFailureException
63      {
64          String jExecutable;
65          try
66          {
67              jExecutable = getJDeprScanExecutable();
68          }
69          catch ( IOException e )
70          {
71              throw new MojoFailureException( "Unable to find jdeprscan command: " + e.getMessage(), e );
72          }
73  
74          // Synopsis
75          // jdeprscan [options] {dir|jar|class} ...
76          Commandline cmd = new Commandline();
77          cmd.setExecutable( jExecutable );
78  
79          addJDeprScanOptions( cmd );
80  
81          executeJDeprScanCommandLine( cmd, getConsumer() );
82          
83          verify();
84      }
85      
86      protected CommandLineUtils.StringStreamConsumer getConsumer()
87      {
88        return null;    
89      }
90      
91      protected void verify() throws MojoExecutionException
92      {
93      }
94      
95      protected abstract boolean isForRemoval();
96  
97      protected void addJDeprScanOptions( Commandline cmd ) throws MojoFailureException
98      {
99          if ( isForRemoval() )
100         {
101             cmd.createArg().setValue( "--for-removal" );
102         }
103     }
104 
105     private String getJDeprScanExecutable()
106         throws IOException
107     {
108         Toolchain tc = getToolchain();
109 
110         String jdeprscanExecutable = null;
111         if ( tc != null )
112         {
113             jdeprscanExecutable = tc.findTool( "jdeprscan" );
114         }
115 
116         String jdepsCommand = "jdeprscan" + ( SystemUtils.IS_OS_WINDOWS ? ".exe" : "" );
117 
118         File jdeprscanExe;
119 
120         if ( StringUtils.isNotEmpty( jdeprscanExecutable ) )
121         {
122             jdeprscanExe = new File( jdeprscanExecutable );
123 
124             if ( jdeprscanExe.isDirectory() )
125             {
126                 jdeprscanExe = new File( jdeprscanExe, jdepsCommand );
127             }
128 
129             if ( SystemUtils.IS_OS_WINDOWS && jdeprscanExe.getName().indexOf( '.' ) < 0 )
130             {
131                 jdeprscanExe = new File( jdeprscanExe.getPath() + ".exe" );
132             }
133 
134             if ( !jdeprscanExe.isFile() )
135             {
136                 throw new IOException( "The jdeprscan executable '" + jdeprscanExe
137                     + "' doesn't exist or is not a file." );
138             }
139             return jdeprscanExe.getAbsolutePath();
140         }
141 
142         jdeprscanExe =
143             new File( SystemUtils.getJavaHome() + File.separator + ".." + File.separator + "sh", jdepsCommand );
144 
145         // ----------------------------------------------------------------------
146         // Try to find jdepsExe from JAVA_HOME environment variable
147         // ----------------------------------------------------------------------
148         if ( !jdeprscanExe.exists() || !jdeprscanExe.isFile() )
149         {
150             Properties env = CommandLineUtils.getSystemEnvVars();
151             String javaHome = env.getProperty( "JAVA_HOME" );
152             if ( StringUtils.isEmpty( javaHome ) )
153             {
154                 throw new IOException( "The environment variable JAVA_HOME is not correctly set." );
155             }
156             if ( ( !new File( javaHome ).getCanonicalFile().exists() )
157                 || ( new File( javaHome ).getCanonicalFile().isFile() ) )
158             {
159                 throw new IOException( "The environment variable JAVA_HOME=" + javaHome
160                     + " doesn't exist or is not a valid directory." );
161             }
162 
163             jdeprscanExe = new File( javaHome + File.separator + "bin", jdepsCommand );
164         }
165 
166         if ( !jdeprscanExe.getCanonicalFile().exists() || !jdeprscanExe.getCanonicalFile().isFile() )
167         {
168             throw new IOException( "The jdeps executable '" + jdeprscanExe
169                 + "' doesn't exist or is not a file. Verify the JAVA_HOME environment variable." );
170         }
171 
172         return jdeprscanExe.getAbsolutePath();
173     }
174 
175     private void executeJDeprScanCommandLine( Commandline cmd,
176                                           CommandLineUtils.StringStreamConsumer consumer )
177         throws MojoExecutionException
178     {
179         if ( getLog().isDebugEnabled() )
180         {
181             // no quoted arguments
182             getLog().debug( "Executing: " + CommandLineUtils.toString( cmd.getCommandline() ).replaceAll( "'", "" ) );
183         }
184 
185         CommandLineUtils.StringStreamConsumer err = new CommandLineUtils.StringStreamConsumer();
186         CommandLineUtils.StringStreamConsumer out;
187         if ( consumer != null )
188         {
189             out = consumer;
190         }
191         else
192         {
193             out = new CommandLineUtils.StringStreamConsumer();
194         }
195 
196         try
197         {
198             int exitCode = CommandLineUtils.executeCommandLine( cmd, out, err );
199 
200             String output = ( StringUtils.isEmpty( out.getOutput() ) ? null : '\n' + out.getOutput().trim() );
201 
202             if ( StringUtils.isNotEmpty( output ) )
203             {
204                 getLog().info( output );
205             }
206 
207             if ( exitCode != 0 )
208             {
209                 StringBuilder msg = new StringBuilder( "\nExit code: " );
210                 msg.append( exitCode );
211                 if ( StringUtils.isNotEmpty( err.getOutput() ) )
212                 {
213                     msg.append( " - " ).append( err.getOutput() );
214                 }
215                 msg.append( '\n' );
216                 msg.append( "Command line was: " ).append( cmd ).append( '\n' ).append( '\n' );
217 
218                 throw new MojoExecutionException( msg.toString() );
219             }
220 
221         }
222         catch ( CommandLineException e )
223         {
224             throw new MojoExecutionException( "Unable to execute jdeprscan command: " + e.getMessage(), e );
225         }
226 
227         // ----------------------------------------------------------------------
228         // Handle JDeprScan warnings
229         // ----------------------------------------------------------------------
230 
231         if ( StringUtils.isNotEmpty( err.getOutput() ) && getLog().isWarnEnabled() )
232         {
233             getLog().warn( "JDeprScan Warnings" );
234 
235             StringTokenizer token = new StringTokenizer( err.getOutput(), "\n" );
236             while ( token.hasMoreTokens() )
237             {
238                 String current = token.nextToken().trim();
239 
240                 getLog().warn( current );
241             }
242         }
243     }
244 
245     private Toolchain getToolchain()
246     {
247         Toolchain tc = null;
248         if ( toolchainManager != null )
249         {
250             tc = toolchainManager.getToolchainFromBuildContext( "jdk", session );
251 
252             if ( tc == null )
253             {
254                 // Maven 3.2.6 has plugin execution scoped Toolchain Support
255                 try
256                 {
257                     Method getToolchainsMethod =
258                         toolchainManager.getClass().getMethod( "getToolchains", MavenSession.class, String.class,
259                                                                Map.class );
260 
261                     @SuppressWarnings( "unchecked" )
262                     List<Toolchain> tcs =
263                         (List<Toolchain>) getToolchainsMethod.invoke( toolchainManager, session, "jdk",
264                                                                       Collections.singletonMap( "version", "[9,)" ) );
265 
266                     if ( tcs != null && tcs.size() > 0 )
267                     {
268                         // pick up latest, jdeps of JDK9 has more options compared to JDK8
269                         tc = tcs.get( tcs.size() - 1 );
270                     }
271                 }
272                 catch ( ReflectiveOperationException e )
273                 {
274                     // ignore
275                 }
276                 catch ( SecurityException e )
277                 {
278                     // ignore
279                 }
280                 catch ( IllegalArgumentException e )
281                 {
282                     // ignore
283                 }
284             }
285         }
286 
287         return tc;
288     }
289 }