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