View Javadoc

1   /*--------------------------------------------------------------------------
2    *  Copyright 2008 utgenome.org
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   *--------------------------------------------------------------------------*/
16  //--------------------------------------
17  // utgb-shell Project
18  //
19  // UTGBShell.java 
20  // Since: Jan 8, 2008
21  //
22  // $URL$ 
23  // $Author$
24  //--------------------------------------
25  package org.utgenome.shell;
26  
27  import java.io.BufferedReader;
28  import java.io.IOException;
29  import java.io.InputStream;
30  import java.lang.reflect.Modifier;
31  import java.util.List;
32  import java.util.Properties;
33  import java.util.Set;
34  import java.util.TreeMap;
35  
36  import org.utgenome.shell.Create.OverwriteMode;
37  import org.xerial.util.FileResource;
38  import org.xerial.util.ResourceFilter;
39  import org.xerial.util.StringUtil;
40  import org.xerial.util.io.VirtualFile;
41  import org.xerial.util.log.LogLevel;
42  import org.xerial.util.log.Logger;
43  import org.xerial.util.log.SimpleLogWriter;
44  import org.xerial.util.opt.Argument;
45  import org.xerial.util.opt.Option;
46  import org.xerial.util.opt.OptionParser;
47  import org.xerial.util.opt.OptionParserException;
48  
49  /**
50   * A command line client entry point
51   * 
52   * @author leo
53   * 
54   */
55  public class UTGBShell {
56  
57  	static {
58  	}
59  
60  	private static Logger _logger = Logger.getLogger(UTGBShell.class);
61  
62  	private static TreeMap<String, UTGBShellCommand> subCommandTable = new TreeMap<String, UTGBShellCommand>();
63  
64  	/**
65  	 * search sub commands from the this package (org.utgenome.shell)
66  	 */
67  	static void findSubCommands() {
68  		String shellPackage = UTGBShell.class.getPackage().getName();
69  		List<VirtualFile> classFileList = FileResource.listResources(shellPackage, new ResourceFilter() {
70  			public boolean accept(String resourcePath) {
71  				return resourcePath.endsWith(".class");
72  			}
73  		});
74  		for (VirtualFile vf : classFileList) {
75  			String logicalPath = vf.getLogicalPath();
76  			int dot = logicalPath.lastIndexOf(".");
77  			if (dot <= 0)
78  				continue;
79  			String className = shellPackage + "." + logicalPath.substring(0, dot).replaceAll("/", ".");
80  			try {
81  				Class<?> c = Class.forName(className, false, UTGBShell.class.getClassLoader());
82  				if (!Modifier.isAbstract(c.getModifiers()) && UTGBShellCommand.class.isAssignableFrom(c)) {
83  					// found a sub command class
84  					UTGBShellCommand subCommand = (UTGBShellCommand) c.newInstance();
85  					if (subCommand == null)
86  						continue;
87  					subCommandTable.put(subCommand.name(), subCommand);
88  				}
89  			}
90  			catch (ClassNotFoundException e) {
91  				continue;
92  			}
93  			catch (InstantiationException e) {
94  				_logger.error(e);
95  			}
96  			catch (IllegalAccessException e) {
97  				_logger.error(e);
98  			}
99  		}
100 	}
101 
102 	static {
103 		// search for the all available sub commands
104 		findSubCommands();
105 
106 		// System.setProperty("com.apple.eawt.CocoaComponent.CompatibilityMode", "false");
107 	}
108 
109 	public static class UTGBShellOption {
110 
111 		@Option(symbol = "h", longName = "help", description = "display help message")
112 		private boolean displayHelp = false;
113 
114 		@Option(symbol = "v", longName = "version", description = "display version")
115 		private boolean displayVersion = false;
116 
117 		@Argument(index = 0, required = false)
118 		private String subCommand = null;
119 
120 		@Option(symbol = "l", longName = "loglevel", description = "set log level: TRACE, DEBUG, INFO(default), WARN, ERROR, FATAL")
121 		private LogLevel logLevel = null;
122 
123 		@Option(symbol = "d", longName = "projectDir", description = "specify the project directory (default = current directory)")
124 		public String projectDir = ".";
125 
126 		@Option(symbol = "e", longName = "env", varName = "test|development|production", description = "switch the configuration file (default: development)")
127 		public String environment = "development";
128 
129 		@Option(symbol = "y", description = "(non-interactive mode) answer yes to all questions")
130 		public boolean answerYes = false;
131 
132 	}
133 
134 	public static Set<String> getSubCommandNameSet() {
135 		return subCommandTable.keySet();
136 	}
137 
138 	/**
139 	 * Run UTGB Shell commands
140 	 * 
141 	 * @param args
142 	 * @throws Exception
143 	 */
144 	public static void runCommand(String argLine) throws Exception {
145 		runCommand(argLine.split("[\\s]+"));
146 	}
147 
148 	public static void runCommand(UTGBShellOption opt, String argLine) throws Exception {
149 		runCommand(opt, argLine.split("[\\s]+"));
150 	}
151 
152 	public static void runCommand(UTGBShellOption opt, String[] args) throws Exception {
153 
154 		OptionParser optionParser = new OptionParser(opt);
155 		optionParser.setIgnoreUnknownOption(true);
156 
157 		optionParser.parse(args);
158 		String[] subCommandArgumetns = optionParser.getUnusedArguments();
159 
160 		if (opt.logLevel != null)
161 			Logger.getRootLogger().setLogLevel(opt.logLevel);
162 
163 		Logger.getRootLogger().setLogWriter(new SimpleLogWriter(System.err));
164 
165 		if (opt.answerYes) {
166 			ScaffoldGenerator.overwriteMode = OverwriteMode.YES_TO_ALL;
167 		}
168 
169 		if (opt.subCommand != null) {
170 			// go to sub command processing
171 			UTGBShellCommand subCommand = subCommandTable.get(opt.subCommand);
172 
173 			if (subCommand != null) {
174 				// Use the specified option holder for binding command-line parameters. If no option holder is
175 				// given, use the sub command instance itself.
176 				Object optionHolder = subCommand.getOptionHolder();
177 				if (optionHolder == null)
178 					optionHolder = subCommand;
179 
180 				OptionParser subCommandParser = new OptionParser(optionHolder);
181 				subCommandParser.setIgnoreUnknownOption(true);
182 				try {
183 					subCommandParser.parse(subCommandArgumetns);
184 					if (opt.displayHelp) {
185 						String helpFile = String.format("help-%s.txt", subCommand.name());
186 						System.out.println(loadUsage(helpFile));
187 						subCommandParser.printUsage();
188 						return;
189 					}
190 					else {
191 						// copy the rest of the command line arguments
192 						subCommand.execute(opt, subCommandArgumetns);
193 						return;
194 					}
195 				}
196 				catch (OptionParserException e) {
197 					System.err.println(e.getMessage());
198 					return;
199 				}
200 
201 			}
202 			else {
203 				System.err.println("unknown subcommand: " + opt.subCommand);
204 			}
205 		}
206 		else {
207 			if (opt.displayHelp) {
208 				// display help message
209 				System.out.println(getProgramInfo());
210 				BufferedReader helpReader = FileResource.open(UTGBShell.class, "help-message.txt");
211 				String line;
212 				while ((line = helpReader.readLine()) != null)
213 					System.out.println(line);
214 				// list command line options
215 				optionParser.printUsage();
216 				// list all sub commands
217 				System.out.println("[sub commands]");
218 				for (String subCommandName : subCommandTable.keySet()) {
219 					UTGBShellCommand sc = subCommandTable.get(subCommandName);
220 					System.out.format("  %-15s\t%s", subCommandName, sc.getOneLinerDescription());
221 					System.out.println();
222 				}
223 				return;
224 			}
225 			if (opt.displayVersion) {
226 				System.out.println(getProgramInfo());
227 				return;
228 			}
229 		}
230 
231 		// display a short help message
232 		System.out.println(getProgramInfo());
233 		System.out.println("type --help for a list of the available sub commands.");
234 
235 	}
236 
237 	/**
238 	 * Run UTGB Shell commands
239 	 * 
240 	 * @param args
241 	 * @throws Exception
242 	 */
243 	public static void runCommand(String[] args) throws Exception {
244 		runCommand(new UTGBShellOption(), args);
245 	}
246 
247 	/**
248 	 * Run UTGB Shell command. This method will terminates JVM with return code -1 when some error is observed. Thus, to
249 	 * invoke UTGB Shell command inside the Java program, use {@link #runCommand(String[])} method, which does not
250 	 * terminate the JVM.
251 	 * 
252 	 * 
253 	 * @param args
254 	 */
255 	public static void main(String[] args) {
256 		try {
257 			runCommand(args);
258 		}
259 		catch (UTGBShellException e) {
260 			System.err.println(e.getMessage());
261 			System.exit(1); // return error code
262 		}
263 		catch (OptionParserException e) {
264 			System.err.println(e.getMessage());
265 			System.exit(1); // return error code
266 		}
267 		catch (Exception e) {
268 			e.printStackTrace(System.err);
269 			System.exit(1); // return error code
270 		}
271 		catch (Error e) {
272 			e.printStackTrace(System.err);
273 			System.exit(1); // return error code
274 		}
275 	}
276 
277 	public static String loadUsage(String helpFileName) {
278 		// display help messages
279 		StringBuilder out = new StringBuilder();
280 		try {
281 			BufferedReader reader = FileResource.open(Create.class, helpFileName);
282 			String line;
283 			if (reader == null)
284 				return "";
285 			while ((line = reader.readLine()) != null) {
286 				out.append(line);
287 				out.append(StringUtil.NEW_LINE);
288 			}
289 			return out.toString();
290 		}
291 		catch (IOException e) {
292 			_logger.warn(String.format("%s is not found in the org.utgenome.shell package", helpFileName));
293 			return "";
294 		}
295 	}
296 
297 	public static String getProgramInfo() {
298 		return "UTGB Shell: version " + getVersion();
299 	}
300 
301 	public static String getVersion() {
302 		String version = "(unknown)";
303 		try {
304 			// load the pom.xml file copied as a resource
305 			InputStream pomIn = UTGBShell.class.getResourceAsStream("/META-INF/maven/org.utgenome/utgb-core/pom.properties");
306 			if (pomIn != null) {
307 				Properties prop = new Properties();
308 				prop.load(pomIn);
309 				version = prop.getProperty("version", version);
310 			}
311 		}
312 		catch (IOException e) {
313 			_logger.debug(e);
314 		}
315 		return version;
316 	}
317 }