View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.plugins.jdeprscan;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.lang.reflect.Method;
24  import java.util.Collections;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.Properties;
28  import java.util.StringTokenizer;
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.plugin.MojoFailureException;
35  import org.apache.maven.plugins.annotations.Parameter;
36  import org.apache.maven.toolchain.Toolchain;
37  import org.apache.maven.toolchain.ToolchainManager;
38  import org.codehaus.plexus.util.StringUtils;
39  import org.codehaus.plexus.util.cli.CommandLineException;
40  import org.codehaus.plexus.util.cli.CommandLineUtils;
41  import org.codehaus.plexus.util.cli.Commandline;
42  
43  /**
44   * Abstract class for all mojos
45   *
46   * @author Robert Scholte
47   * @since 3.0.0
48   */
49  public abstract class AbstractJDeprScanMojo extends AbstractMojo {
50      @Parameter(defaultValue = "${session}", readonly = true, required = true)
51      private MavenSession session;
52  
53      private final ToolchainManager toolchainManager;
54  
55      protected AbstractJDeprScanMojo(ToolchainManager toolchainManager) {
56          this.toolchainManager = toolchainManager;
57      }
58  
59      @Override
60      public void execute() throws MojoExecutionException, MojoFailureException {
61          String jExecutable;
62          try {
63              jExecutable = getJDeprScanExecutable();
64          } catch (IOException e) {
65              throw new MojoFailureException("Unable to find jdeprscan command: " + e.getMessage(), e);
66          }
67  
68          // Synopsis
69          // jdeprscan [options] {dir|jar|class} ...
70          Commandline cmd = new Commandline();
71          cmd.setExecutable(jExecutable);
72  
73          addJDeprScanOptions(cmd);
74  
75          executeJDeprScanCommandLine(cmd, getConsumer());
76  
77          verify();
78      }
79  
80      protected CommandLineUtils.StringStreamConsumer getConsumer() {
81          return null;
82      }
83  
84      protected void verify() throws MojoExecutionException {}
85  
86      protected abstract boolean isForRemoval();
87  
88      protected void addJDeprScanOptions(Commandline cmd) throws MojoFailureException {
89          if (isForRemoval()) {
90              cmd.createArg().setValue("--for-removal");
91          }
92      }
93  
94      private String getJDeprScanExecutable() throws IOException {
95          Toolchain tc = getToolchain();
96  
97          String jdeprscanExecutable = null;
98          if (tc != null) {
99              jdeprscanExecutable = tc.findTool("jdeprscan");
100         }
101 
102         String jdepsCommand = "jdeprscan" + (SystemUtils.IS_OS_WINDOWS ? ".exe" : "");
103 
104         File jdeprscanExe;
105 
106         if (StringUtils.isNotEmpty(jdeprscanExecutable)) {
107             jdeprscanExe = new File(jdeprscanExecutable);
108 
109             if (jdeprscanExe.isDirectory()) {
110                 jdeprscanExe = new File(jdeprscanExe, jdepsCommand);
111             }
112 
113             if (SystemUtils.IS_OS_WINDOWS && jdeprscanExe.getName().indexOf('.') < 0) {
114                 jdeprscanExe = new File(jdeprscanExe.getPath() + ".exe");
115             }
116 
117             if (!jdeprscanExe.isFile()) {
118                 throw new IOException(
119                         "The jdeprscan executable '" + jdeprscanExe + "' doesn't exist or is not a file.");
120             }
121             return jdeprscanExe.getAbsolutePath();
122         }
123 
124         jdeprscanExe =
125                 new File(SystemUtils.getJavaHome() + File.separator + ".." + File.separator + "sh", jdepsCommand);
126 
127         // ----------------------------------------------------------------------
128         // Try to find jdepsExe from JAVA_HOME environment variable
129         // ----------------------------------------------------------------------
130         if (!jdeprscanExe.exists() || !jdeprscanExe.isFile()) {
131             Properties env = CommandLineUtils.getSystemEnvVars();
132             String javaHome = env.getProperty("JAVA_HOME");
133             if (StringUtils.isEmpty(javaHome)) {
134                 throw new IOException("The environment variable JAVA_HOME is not correctly set.");
135             }
136             if ((!new File(javaHome).getCanonicalFile().exists())
137                     || (new File(javaHome).getCanonicalFile().isFile())) {
138                 throw new IOException("The environment variable JAVA_HOME=" + javaHome
139                         + " doesn't exist or is not a valid directory.");
140             }
141 
142             jdeprscanExe = new File(javaHome + File.separator + "bin", jdepsCommand);
143         }
144 
145         if (!jdeprscanExe.getCanonicalFile().exists()
146                 || !jdeprscanExe.getCanonicalFile().isFile()) {
147             throw new IOException("The jdeps executable '" + jdeprscanExe
148                     + "' doesn't exist or is not a file. Verify the JAVA_HOME environment variable.");
149         }
150 
151         return jdeprscanExe.getAbsolutePath();
152     }
153 
154     private void executeJDeprScanCommandLine(Commandline cmd, CommandLineUtils.StringStreamConsumer consumer)
155             throws MojoExecutionException {
156         if (getLog().isDebugEnabled()) {
157             // no quoted arguments
158             getLog().debug("Executing: "
159                     + CommandLineUtils.toString(cmd.getCommandline()).replaceAll("'", ""));
160         }
161 
162         CommandLineUtils.StringStreamConsumer err = new CommandLineUtils.StringStreamConsumer();
163         CommandLineUtils.StringStreamConsumer out;
164         if (consumer != null) {
165             out = consumer;
166         } else {
167             out = new CommandLineUtils.StringStreamConsumer();
168         }
169 
170         try {
171             int exitCode = CommandLineUtils.executeCommandLine(cmd, out, err);
172 
173             String output = (StringUtils.isEmpty(out.getOutput())
174                     ? null
175                     : '\n' + out.getOutput().trim());
176 
177             if (StringUtils.isNotEmpty(output)) {
178                 getLog().info(output);
179             }
180 
181             if (exitCode != 0) {
182                 StringBuilder msg = new StringBuilder("\nExit code: ");
183                 msg.append(exitCode);
184                 if (StringUtils.isNotEmpty(err.getOutput())) {
185                     msg.append(" - ").append(err.getOutput());
186                 }
187                 msg.append('\n');
188                 msg.append("Command line was: ").append(cmd).append('\n').append('\n');
189 
190                 throw new MojoExecutionException(msg.toString());
191             }
192 
193         } catch (CommandLineException e) {
194             throw new MojoExecutionException("Unable to execute jdeprscan command: " + e.getMessage(), e);
195         }
196 
197         // ----------------------------------------------------------------------
198         // Handle JDeprScan warnings
199         // ----------------------------------------------------------------------
200 
201         if (StringUtils.isNotEmpty(err.getOutput()) && getLog().isWarnEnabled()) {
202             getLog().warn("JDeprScan Warnings");
203 
204             StringTokenizer token = new StringTokenizer(err.getOutput(), "\n");
205             while (token.hasMoreTokens()) {
206                 String current = token.nextToken().trim();
207 
208                 getLog().warn(current);
209             }
210         }
211     }
212 
213     private Toolchain getToolchain() {
214         Toolchain tc = null;
215         if (toolchainManager != null) {
216             tc = toolchainManager.getToolchainFromBuildContext("jdk", session);
217 
218             if (tc == null) {
219                 // Maven 3.3.0 has plugin execution scoped Toolchain Support
220                 try {
221                     Method getToolchainsMethod = toolchainManager
222                             .getClass()
223                             .getMethod("getToolchains", MavenSession.class, String.class, Map.class);
224 
225                     @SuppressWarnings("unchecked")
226                     List<Toolchain> tcs = (List<Toolchain>) getToolchainsMethod.invoke(
227                             toolchainManager, session, "jdk", Collections.singletonMap("version", "[9,)"));
228 
229                     if (tcs != null && tcs.size() > 0) {
230                         // pick up latest, jdeps of JDK9 has more options compared to JDK8
231                         tc = tcs.get(tcs.size() - 1);
232                     }
233                 } catch (ReflectiveOperationException | SecurityException | IllegalArgumentException e) {
234                     // ignore
235                 }
236             }
237         }
238 
239         return tc;
240     }
241 }