View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *  http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.any23.cli;
19  
20  import com.beust.jcommander.JCommander;
21  import com.beust.jcommander.Parameter;
22  import com.beust.jcommander.converters.FileConverter;
23  import org.apache.any23.Any23;
24  import org.apache.any23.plugin.Any23PluginManager;
25  
26  import java.io.File;
27  import java.io.IOException;
28  import java.io.InputStream;
29  import java.io.PrintStream;
30  import java.util.Date;
31  import java.util.Iterator;
32  import java.util.Locale;
33  import java.util.Map;
34  import java.util.Properties;
35  
36  import static java.lang.System.currentTimeMillis;
37  import static java.lang.System.exit;
38  
39  /**
40   * This class is the main class responsible to provide a uniform command-line access points to all the others tools like
41   * {@link Rover}.
42   *
43   * @see ExtractorDocumentation
44   * @see Rover
45   */
46  public final class ToolRunner {
47  
48      public static final File DEFAULT_PLUGIN_DIR = new File(new File(System.getProperty("user.home")), ".any23/plugins");
49  
50      private static final PrintStream infoStream = System.err;
51  
52      @Parameter(names = { "-h", "--help" }, description = "Display help information.")
53      private boolean printHelp;
54  
55      @Parameter(names = { "-v", "--version" }, description = "Display version information.")
56      private boolean showVersion;
57  
58      @Parameter(names = { "-X", "--verbose" }, description = "Produce execution verbose output.")
59      private boolean verbose;
60  
61      @Parameter(names = {
62              "--plugins-dir" }, description = "The Any23 plugins directory.", converter = FileConverter.class)
63      private File pluginsDir = DEFAULT_PLUGIN_DIR;
64  
65      public static void main(String[] args) throws Exception {
66          exit(new ToolRunner().execute(args));
67      }
68  
69      public int execute(String... args) throws Exception {
70          return execute(false, args);
71      }
72  
73      int execute(boolean concise, String... args) throws Exception {
74          JCommander commander = new JCommander(this);
75          commander.setProgramName(System.getProperty("app.name"));
76  
77          // TODO (low) : this dirty solution has been introduced because it is not possible to
78          // parse arguments ( commander.parse() ) twice.
79          final File pluginsDirOption;
80          try {
81              pluginsDirOption = parsePluginDirOption(args);
82          } catch (Exception e) {
83              System.err.println(e.getMessage());
84              return 1;
85          }
86          if (pluginsDirOption != null) {
87              pluginsDir = pluginsDirOption;
88          }
89  
90          // add all plugins first
91          final Iterator<Tool> tools = getToolsInClasspath();
92          while (tools.hasNext()) {
93              Tool tool = tools.next();
94              commander.addCommand(tool);
95          }
96  
97          commander.parse(args);
98  
99          Map<String, JCommander> commands = commander.getCommands();
100         String parsedCommand = commander.getParsedCommand();
101 
102         if (printHelp) {
103             commander.usage();
104             return 0;
105         }
106 
107         if (showVersion) {
108             printVersionInfo();
109             return 0;
110         }
111 
112         if (parsedCommand == null) {
113             infoStream.println("A command must be specified.");
114             commander.usage();
115             return 1;
116         }
117 
118         long start = currentTimeMillis();
119         int exit = 0;
120 
121         Throwable error = null;
122 
123         // execute the parsed command
124         infoStream.println();
125         infoStream.println("------------------------------------------------------------------------");
126         infoStream.printf(Locale.ROOT, "Apache Any23 :: %s%n", parsedCommand);
127         infoStream.println("------------------------------------------------------------------------");
128         infoStream.println();
129 
130         try {
131             Tool tool = Tool.class.cast(commands.get(parsedCommand).getObjects().get(0));
132             if (tool instanceof BaseTool) {
133                 ((BaseTool) tool).run(concise);
134             } else {
135                 tool.run();
136             }
137         } catch (Throwable t) {
138             exit = 1;
139             error = t;
140         } finally {
141             infoStream.println();
142             infoStream.println("------------------------------------------------------------------------");
143             infoStream.printf(Locale.ROOT, "Apache Any23 %s%n", (exit != 0) ? "FAILURE" : "SUCCESS");
144 
145             if (exit != 0) {
146                 infoStream.println();
147 
148                 if (verbose) {
149                     System.err.println("Execution terminated with errors:");
150                     error.printStackTrace(infoStream);
151                 } else {
152                     infoStream.printf(Locale.ROOT, "Execution terminated with errors: %s%n", error.getMessage());
153                 }
154 
155                 infoStream.println();
156             }
157 
158             infoStream.printf(Locale.ROOT, "Total time: %ss%n", ((currentTimeMillis() - start) / 1000));
159             infoStream.printf(Locale.ROOT, "Finished at: %s%n", new Date());
160 
161             final Runtime runtime = Runtime.getRuntime();
162             final int megaUnit = 1024 * 1024;
163             infoStream.printf(Locale.ROOT, "Final Memory: %sM/%sM%n",
164                     (runtime.totalMemory() - runtime.freeMemory()) / megaUnit, runtime.totalMemory() / megaUnit);
165 
166             infoStream.println("------------------------------------------------------------------------");
167         }
168 
169         return exit;
170     }
171 
172     Iterator<Tool> getToolsInClasspath() throws IOException {
173         final Any23PluginManager pluginManager = Any23PluginManager.getInstance();
174         if (pluginsDir.exists() && pluginsDir.isDirectory()) {
175             pluginManager.loadJARDir(pluginsDir);
176         }
177         return pluginManager.getTools();
178     }
179 
180     private static void printVersionInfo() {
181         Properties properties = new Properties();
182         InputStream input = ToolRunner.class.getClassLoader()
183                 .getResourceAsStream("META-INF/maven/org.apache.any23/any23-core/pom.properties");
184 
185         if (input != null) {
186             try {
187                 properties.load(input);
188             } catch (IOException e) {
189                 // ignore, just don't load the properties
190             } finally {
191                 try {
192                     input.close();
193                 } catch (IOException e) {
194                     // close quietly
195                 }
196             }
197         }
198 
199         infoStream.printf(Locale.ROOT, "Apache Any23 %s%n", Any23.VERSION);
200         infoStream.printf(Locale.ROOT, "Java version: %s, vendor: %s%n", System.getProperty("java.version"),
201                 System.getProperty("java.vendor"));
202         infoStream.printf(Locale.ROOT, "Java home: %s%n", System.getProperty("java.home"));
203         infoStream.printf(Locale.ROOT, "Default locale: %s_%s, platform encoding: %s%n",
204                 System.getProperty("user.language"), System.getProperty("user.country"),
205                 System.getProperty("sun.jnu.encoding"));
206         infoStream.printf(Locale.ROOT, "OS name: \"%s\", version: \"%s\", arch: \"%s\", family: \"%s\"%n",
207                 System.getProperty("os.name"), System.getProperty("os.version"), System.getProperty("os.arch"),
208                 getOsFamily());
209     }
210 
211     private static final String getOsFamily() {
212         String osName = System.getProperty("os.name").toLowerCase(Locale.ROOT);
213         String pathSep = System.getProperty("path.separator");
214 
215         if (osName.contains("windows")) {
216             return "windows";
217         } else if (osName.contains("os/2")) {
218             return "os/2";
219         } else if (osName.contains("z/os") || osName.contains("os/390")) {
220             return "z/os";
221         } else if (osName.contains("os/400")) {
222             return "os/400";
223         } else if (";".equals(pathSep)) {
224             return "dos";
225         } else if (osName.contains("mac")) {
226             if (osName.endsWith("x")) {
227                 return "mac"; // MACOSX
228             }
229             return "unix";
230         } else if (osName.contains("nonstop_kernel")) {
231             return "tandem";
232         } else if (osName.contains("openvms")) {
233             return "openvms";
234         } else if (":".equals(pathSep)) {
235             return "unix";
236         }
237 
238         return "undefined";
239     }
240 
241     private static File parsePluginDirOption(String[] args) {
242         int optionIndex = -1;
243         for (int i = 0; i < args.length; i++) {
244             if ("--plugins-dir".equals(args[i])) {
245                 optionIndex = i;
246             }
247         }
248         if (optionIndex == -1)
249             return null;
250 
251         if (optionIndex == args.length - 1) {
252             throw new IllegalArgumentException("Missing argument for --plugins-dir option.");
253         }
254         final File pluginsDir = new File(args[optionIndex + 1]);
255         if (!pluginsDir.isDirectory()) {
256             throw new IllegalArgumentException("Expected a directory for --plugins-dir option value.");
257         }
258         return pluginsDir;
259     }
260 
261 }