基于 Apache Commons CLI 的命令行开发 Apache Commons CLI 简介
Apache Commons CLI 是 Apache 下面的一个解析命令行输入的工具包,该工具包还提供了自动生成输出帮助文档的功能。
Apache Commons CLI 支持多种输入参数格式,主要支持的格式有以下几种:
POSIX(Portable Operating System Interface of Unix)中的参数形式,例如 tar -zxvf foo.tar.gz
GNU 中的长参数形式,例如 du --human-readable --max-depth=1
Java 命令中的参数形式,例如 java -Djava.net.useSystemProxies=true Foo
短杠参数带参数值的参数形式,例如 gcc -O2 foo.c
长杠参数不带参数值的形式,例如 ant – projecthelp
CLI 命令代码实现命令行程序处理流程相对比较简单,主要流程为设定命令行参数 -> 解析输入参数 -> 使用输入的数据进行逻辑处理。下图是以 rmdatasource 为例的运行流程图,图中加入了实际实现过程中的部分逻辑。
图 1. 命令行运行流程图清单 5 是 rmdatasource 的实现代码片段,主要逻辑在 simpleTest 函数里面。在里面我们首先载入了 ResourceBundle 用于程序的多语言支持,将运行中的输出信息预先定义在配置文件中(如 xml 或 property 文件),然后用 ResourceBundle 读取,这样在运行时可以根据运行环境的 locale 来决定输出信息语言,也可以让用户指定输出信息的语言。
然后程序使用 Options 定义命令行的参数,由于参数形式比较简单,所以使用了 Options 的 addOption 来创建一个参数设定(即 option),如果有复杂参数形式,可以使用 OptionBuilder 来生成 Option,示例如下:
清单 4. 使用 OptionBuilder 生成 Options 代码片段Option help = new Option("h", "the command help"); Option user = OptionBuilder.withArgName("type").hasArg().withDescription( "target the search type").create("t"); // 此处定义参数类似于 java 命令中的 -D<name>=<value> Option property = OptionBuilder.withArgName("property=value") .hasArgs(2).withValueSeparator().withDescription( "search the objects which have the target property and value").create("D"); Options opts = new Options(); opts.addOption(help); opts.addOption(user); opts.addOption(property);
在参数设定好后,程序使用 BasicParser 类来解析用户输入的参数,当参数中包含 –h 时程序打印命令行的帮助信息(利用 Apache Commons CLI 的 HelpFormatter 自动生成),如果不包含 –h 时,程序将读取需要的 ip、port 等参数并进行校验,校验通过后则调用内部接口进行 rmdatasource 的操作。
清单 5. rmdatasource 代码片段public class RMDataSource { /** * @param args 输入参数 */ public static void main(String[] args) { simpleTest(args); } public static void simpleTest(String[] args) { ResourceBundle resourceBundle = ResourceBundle.getBundle("message", Locale.getDefault()); Options opts = new Options(); opts.addOption("h", false, resourceBundle.getString("HELP_DESCRIPTION")); opts.addOption("i", true, resourceBundle.getString("HELP_IPADDRESS")); opts.addOption("p", true, resourceBundle.getString("HELP_PORT")); opts.addOption("t", true, resourceBundle.getString("HELP_PROTOCOL")); BasicParser parser = new BasicParser(); CommandLine cl; try { cl = parser.parse(opts, args); if (cl.getOptions().length > 0) { if (cl.hasOption('h')) { HelpFormatter hf = new HelpFormatter(); hf.printHelp("Options", opts); } else { String ip = cl.getOptionValue("i"); String port = cl.getOptionValue("p"); String protocol = cl.getOptionValue("t"); if(!CIMServiceFactory.getinstance().isIPValid(ip)) { System.err.println(resourceBundle.getString("INVALID_IP")); System.exit(1); } try { int rc = CIMServiceFactory.getinstance().rmdatasource( ip, port, protocol); if (rc == 0) { System.out.println(resourceBundle .getString("RMDATASOURCE_SUCCEEDED")); } else { System.err.println(resourceBundle .getString("RMDATASOURCE_FAILED")); } } catch (Exception e) { System.err.println(resourceBundle .getString("RMDATASOURCE_FAILED")); e.printStackTrace(); } } } else { System.err.println(resourceBundle.getString("ERROR_NOARGS")); } } catch (ParseException e) { e.printStackTrace(); } } }