/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.twitter.distributedlog.tools; import org.apache.bookkeeper.util.ReflectionUtils; import org.apache.commons.cli.BasicParser; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import java.util.Map; import java.util.TreeMap; /** * A Tool Framework */ public abstract class Tool { /** * Interface of a command to run in a tool. */ protected interface Command { String getName(); String getDescription(); int runCmd(String[] args) throws Exception; void printUsage(); } /** * {@link org.apache.commons.cli.Options} based command. */ protected abstract static class OptsCommand implements Command { /** * @return options used by this command. */ protected abstract Options getOptions(); /** * @return usage of this command. */ protected String getUsage() { return cmdName + " [options]"; } /** * Run given command line <i>commandLine</i>. * * @param commandLine * command line to run. * @return return code of this command. * @throws Exception */ protected abstract int runCmd(CommandLine commandLine) throws Exception; protected String cmdName; protected String description; protected OptsCommand(String name, String description) { this.cmdName = name; this.description = description; } @Override public String getName() { return cmdName; } @Override public String getDescription() { return description; } @Override public int runCmd(String[] args) throws Exception { try { BasicParser parser = new BasicParser(); CommandLine cmdline = parser.parse(getOptions(), args); return runCmd(cmdline); } catch (ParseException e) { printUsage(); return -1; } } @Override public void printUsage() { HelpFormatter helpFormatter = new HelpFormatter(); println(cmdName + ": " + getDescription()); helpFormatter.printHelp(getUsage(), getOptions()); } } public class HelpCommand implements Command { @Override public String getName() { return "help"; } @Override public String getDescription() { return "describe the usage of this tool or its sub-commands."; } @Override public int runCmd(String[] args) throws Exception { if (args.length == 0) { printToolUsage(); return -1; } String cmdName = args[0]; Command command = commands.get(cmdName); if (null == command) { System.err.println("Unknown command " + cmdName); printToolUsage(); return -1; } command.printUsage(); println(""); return 0; } @Override public void printUsage() { println(getName() + ": " + getDescription()); println(""); println("usage: " + getName() + " <command>"); } } // Commands managed by a tool protected final Map<String, Command> commands = new TreeMap<String, Command>(); protected Tool() { addCommand(new HelpCommand()); } /** * @return tool name. */ protected abstract String getName(); /** * Add a command in this tool. * * @param command * command to run in this tool. */ protected void addCommand(Command command) { commands.put(command.getName(), command); } /** * Print a message in this tool. * * @param msg * message to print */ protected static void println(String msg) { System.out.println(msg); } /** * print tool usage. */ protected void printToolUsage() { println("Usage: " + getName() + " <command>"); println(""); int maxKeyLength = 0; for (String key : commands.keySet()) { if (key.length() > maxKeyLength) { maxKeyLength = key.length(); } } maxKeyLength += 2; for (Map.Entry<String, Command> entry : commands.entrySet()) { StringBuilder spacesBuilder = new StringBuilder(); int numSpaces = maxKeyLength - entry.getKey().length(); for (int i = 0; i < numSpaces; i++) { spacesBuilder.append(" "); } println("\t" + entry.getKey() + spacesBuilder.toString() + ": " + entry.getValue().getDescription()); } println(""); } public int run(String[] args) throws Exception { if (args.length <= 0) { printToolUsage(); return -1; } String cmdName = args[0]; Command cmd = commands.get(cmdName); if (null == cmd) { System.err.println("ERROR: Unknown command " + cmdName); printToolUsage(); return -1; } // prepare new args String[] newArgs = new String[args.length - 1]; System.arraycopy(args, 1, newArgs, 0, newArgs.length); return cmd.runCmd(newArgs); } public static void main(String args[]) { int rc = -1; if (args.length <= 0) { System.err.println("No tool to run."); System.err.println(""); System.err.println("Usage : Tool <tool_class_name> <options>"); System.exit(-1); } String toolClass = args[0]; try { Tool tool = ReflectionUtils.newInstance(toolClass, Tool.class); String[] newArgs = new String[args.length - 1]; System.arraycopy(args, 1, newArgs, 0, newArgs.length); rc = tool.run(newArgs); } catch (Throwable t) { System.err.println("Fail to run tool " + toolClass + " : "); t.printStackTrace(); } System.exit(rc); } }