├── .git.gitignore ├── .gitignore ├── README.md ├── assembly.xml ├── bin ├── shutdown.sh ├── startup.bat ├── startup.bat.bak └── startup.sh ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── github │ │ └── jobop │ │ └── performance │ │ ├── bootstrap │ │ ├── Bootstrap.java │ │ └── Main.java │ │ ├── cli │ │ ├── AlreadySelectedException.java │ │ ├── BasicParser.java │ │ ├── CommandLine.java │ │ ├── CommandLineParser.java │ │ ├── GnuParser.java │ │ ├── HelpFormatter.java │ │ ├── MissingArgumentException.java │ │ ├── MissingOptionException.java │ │ ├── Option.java │ │ ├── OptionBuilder.java │ │ ├── OptionGroup.java │ │ ├── OptionValidator.java │ │ ├── Options.java │ │ ├── ParseException.java │ │ ├── Parser.java │ │ ├── PatternOptionBuilder.java │ │ ├── PosixParser.java │ │ ├── TypeHandler.java │ │ ├── UnrecognizedOptionException.java │ │ └── Util.java │ │ ├── loader │ │ ├── AppJarFileClassLoader.java │ │ ├── JarFileClassLoader.java │ │ └── PrerformanceBizSpiLoaderUtil.java │ │ ├── parser │ │ ├── ArgusParser.java │ │ └── PerformanceContext.java │ │ ├── spi │ │ ├── PerformanceBizSpi.java │ │ ├── TestPerformanceBizSpi.java │ │ └── TestPerformanceBizSpi2.java │ │ ├── statistics │ │ ├── Counter.java │ │ ├── Recoder.java │ │ └── Timer.java │ │ └── task │ │ └── PerformanceTask.java └── resources │ └── config.properties └── test └── java.gitignore /.git.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jobop/performance/5f14829146eb5bc48a0c55e606ad715ed69a2fd1/.git.gitignore -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # performance 2 | 3 | 4 | 5 | ## 关于performance 6 | performance为开发人员提供一个易于使用的性能测试工具,开发人员只需要编写少量的代码,即可很方便地测试出某个业务或者技术的各种性能指标。 7 | 8 | 9 | 10 | ## 嵌入式启动 11 | 12 | 所谓嵌入式启动,即在通过api启动,如果你使用maven,可以在pom中加入如下依赖获取performance 13 | ```Xml 14 | 15 | com.github.jobop 16 | performance 17 | 1.0.0 18 | 19 | ``` 20 | 然后通过如下代码即可测试你的业务 21 | ```Java 22 | public class PerformanceTest implements PerformanceBizSpi { 23 | public static void main(String[] args) { 24 | new PerformanceTask().t(1).c(1l).l("test.log").addTest(new PerformanceTest()).start(); 25 | } 26 | @Override 27 | public boolean execute() { 28 | System.out.println("模拟50%成功率"); 29 | return (new Random().nextInt(10) % 2) == 0; 30 | 31 | } 32 | } 33 | ``` 34 | 其中 35 | 36 | t:持续时间,分为单位 37 | c:启动进程数 38 | l:报告输出路径 39 | n:被测试的类全路径,performance会根据这个全路径过滤后面addTest的用例,不指定则addTest的所用用例均会被测试 40 | addTest:需要增加到测试列表的用例,需要实现PerformanceBizSpi接口。 41 | start:开始测试 42 | 43 | 在测试完毕后,会在l指定的文件中输出报告如下: 44 | 45 | 接口 com.cmf.ec.trade.webapp.test.cases.ErrorCodeSpi 第1次输出,距离上次时间间隔为:60000ms 46 | 现在时间为:1422617565261 47 | 本间隔执行次数为:755.00 48 | 总执行次数为:755.00 49 | 最近一分钟平均耗时为:79.00ms 50 | 最近一分钟平均tps为:12.58 51 | 最近一分钟成功率为:100.00% 52 | 总平均耗时为:79.00ms 53 | 总平均tps为:12.58 54 | 总成功率为:100.00% 55 | ******************************************************************************* 56 | 57 | 58 | 59 | 60 | ## 容器式启动 61 | 62 | 有时为了可以在性能比较高的机器中测试,我们需要使用容器方式启动。 63 | 64 | 1、下载以下zip包,并解压。[performance-1.0.0.zip](https://github.com/jobop/release/blob/master/performance/performance-1.0.0.zip?raw=true) 65 | 2、你要设置一个app目录,修改conf/config.properties中的LIB_BASE_PATH即可 66 | 3、你需要在app目录中新建子文件夹,然后把你的用例所依赖的jar包全部放到里面(用例同样需要实现PerformanceBizSpi接口)。 67 | 4、在你的子文件夹中创建spi.lst文件,文件内容即此子文件夹中所包含全部用例的全路径,每个一行,如下所示: 68 | com.cmf.ec.testsub.TestTradeErrorCodeSpi 69 | com.cmf.ec.testsub.TestSample 70 | 5、执行bin目录中的脚本,脚本参数与api命名相同。 71 | -------------------------------------------------------------------------------- /assembly.xml: -------------------------------------------------------------------------------- 1 | 3 | package 4 | 5 | dir 6 | 7 | false 8 | 9 | 10 | target/classes 11 | 12 | *.properties 13 | 14 | /conf 15 | 16 | 17 | 18 | target/classes 19 | 20 | **/*.sh 21 | **/*.bat 22 | 23 | /bin 24 | 25 | 26 | 27 | 28 | 29 | runtime 30 | /lib 31 | true 32 | 33 | 34 | -------------------------------------------------------------------------------- /bin/shutdown.sh: -------------------------------------------------------------------------------- 1 | ss=`more pid` 2 | echo killed $ss .... 3 | kill -9 $ss 4 | -------------------------------------------------------------------------------- /bin/startup.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | java -DappHome="..\conf" -jar ..\lib\performance-${project.version}.jar -t 1 -c 1 -l D:\\recorde.log 3 | pause -------------------------------------------------------------------------------- /bin/startup.bat.bak: -------------------------------------------------------------------------------- 1 | @echo off 2 | set PARAMETER= 3 | :loop 4 | if "%1"=="" (goto :END) else (SET PARAMETER=%PARAMETER% %1 &shift /1&goto :loop) 5 | :END 6 | java -DappHome="..\conf" -jar ..\lib\performance-${project.version}.jar %PARAMETER% -------------------------------------------------------------------------------- /bin/startup.sh: -------------------------------------------------------------------------------- 1 | nohup java -DappHome="../conf" -jar ../lib/performance-${project.version}.jar -l recode.log $@ >>performance.log & 2 | echo $!>pid 3 | 4 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | com.github.jobop 5 | performance 6 | 1.0.0 7 | jar 8 | 9 | performance 10 | https://github.com/jobop/performance 11 | a simple performance framework 12 | 13 | org.sonatype.oss 14 | oss-parent 15 | 7 16 | 17 | 18 | 19 | The Apache Software License, Version 2.0 20 | http://www.apache.org/licenses/LICENSE-2.0.txt 21 | repo 22 | 23 | 24 | 25 | scm:git:git://github.com/jobop/performance.git 26 | scm:git:git@github.com:jobop/performance.git 27 | https://github.com/jobop/performance 28 | HEAD 29 | 30 | 31 | 32 | jobop 33 | jobop 34 | zw19860913@163.com 35 | 36 | 37 | 38 | 39 | 40 | install 41 | 42 | 43 | ${project.basedir}/bin 44 | true 45 | 46 | 47 | src/main/resources 48 | 49 | **/*.properties 50 | 51 | true 52 | 53 | 54 | 55 | 56 | org.apache.maven.plugins 57 | maven-compiler-plugin 58 | 3.0 59 | 60 | 1.6 61 | 1.6 62 | GBK 63 | true 64 | 65 | 66 | 67 | org.apache.maven.plugins 68 | maven-jar-plugin 69 | 2.4 70 | 71 | 72 | **/*.class 73 | 74 | 75 | 76 | 77 | true 78 | com.github.jobop.performance.bootstrap.Main 79 | 80 | 81 | 82 | 83 | 84 | org.apache.maven.plugins 85 | maven-assembly-plugin 86 | 2.4 87 | 88 | performance 89 | false 90 | target 91 | 92 | assembly.xml 93 | 94 | UTF-8 95 | true 96 | 97 | 98 | 99 | make-assembly 100 | package 101 | 102 | single 103 | 104 | 105 | 106 | 107 | 108 | org.apache.maven.plugins 109 | maven-source-plugin 110 | 2.2.1 111 | 112 | 113 | attach-sources 114 | 115 | jar 116 | 117 | 118 | 119 | 120 | 121 | org.apache.maven.plugins 122 | maven-javadoc-plugin 123 | 2.9 124 | 125 | 126 | attach-javadocs 127 | 128 | jar 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/bootstrap/Bootstrap.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jobop/performance/5f14829146eb5bc48a0c55e606ad715ed69a2fd1/src/main/java/com/github/jobop/performance/bootstrap/Bootstrap.java -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/bootstrap/Main.java: -------------------------------------------------------------------------------- 1 | package com.github.jobop.performance.bootstrap; 2 | 3 | public class Main { 4 | public static void main(String[] args) { 5 | 6 | new Bootstrap().run(args); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/cli/AlreadySelectedException.java: -------------------------------------------------------------------------------- 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 com.github.jobop.performance.cli; 19 | 20 | 21 | /** 22 | * Thrown when more than one option in an option group 23 | * has been provided. 24 | * 25 | * @author John Keyes ( john at integralsource.com ) 26 | * @version $Revision: 680644 $, $Date: 2008-07-29 01:13:48 -0700 (Tue, 29 Jul 2008) $ 27 | */ 28 | public class AlreadySelectedException extends ParseException 29 | { 30 | /** The option group selected. */ 31 | private OptionGroup group; 32 | 33 | /** The option that triggered the exception. */ 34 | private Option option; 35 | 36 | /** 37 | * Construct a new AlreadySelectedException 38 | * with the specified detail message. 39 | * 40 | * @param message the detail message 41 | */ 42 | public AlreadySelectedException(String message) 43 | { 44 | super(message); 45 | } 46 | 47 | /** 48 | * Construct a new AlreadySelectedException 49 | * for the specified option group. 50 | * 51 | * @param group the option group already selected 52 | * @param option the option that triggered the exception 53 | * @since 1.2 54 | */ 55 | public AlreadySelectedException(OptionGroup group, Option option) 56 | { 57 | this("The option '" + option.getKey() + "' was specified but an option from this group " 58 | + "has already been selected: '" + group.getSelected() + "'"); 59 | this.group = group; 60 | this.option = option; 61 | } 62 | 63 | /** 64 | * Returns the option group where another option has been selected. 65 | * 66 | * @return the related option group 67 | * @since 1.2 68 | */ 69 | public OptionGroup getOptionGroup() 70 | { 71 | return group; 72 | } 73 | 74 | /** 75 | * Returns the option that was added to the group and triggered the exception. 76 | * 77 | * @return the related option 78 | * @since 1.2 79 | */ 80 | public Option getOption() 81 | { 82 | return option; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/cli/BasicParser.java: -------------------------------------------------------------------------------- 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 com.github.jobop.performance.cli; 19 | 20 | /** 21 | * The class BasicParser provides a very simple implementation of 22 | * the {@link Parser#flatten(Options,String[],boolean) flatten} method. 23 | * 24 | * @author John Keyes (john at integralsource.com) 25 | * @version $Revision: 680644 $, $Date: 2008-07-29 01:13:48 -0700 (Tue, 29 Jul 2008) $ 26 | */ 27 | public class BasicParser extends Parser 28 | { 29 | /** 30 | *

A simple implementation of {@link Parser}'s abstract 31 | * {@link Parser#flatten(Options, String[], boolean) flatten} method.

32 | * 33 | *

Note: options and stopAtNonOption 34 | * are not used in this flatten method.

35 | * 36 | * @param options The command line {@link Options} 37 | * @param arguments The command line arguments to be parsed 38 | * @param stopAtNonOption Specifies whether to stop flattening 39 | * when an non option is found. 40 | * @return The arguments String array. 41 | */ 42 | protected String[] flatten(Options options, String[] arguments, boolean stopAtNonOption) 43 | { 44 | // just echo the arguments 45 | return arguments; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/cli/CommandLine.java: -------------------------------------------------------------------------------- 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 com.github.jobop.performance.cli; 19 | 20 | import java.io.Serializable; 21 | import java.util.ArrayList; 22 | import java.util.Collection; 23 | import java.util.Iterator; 24 | import java.util.LinkedList; 25 | import java.util.List; 26 | import java.util.Properties; 27 | 28 | /** 29 | * Represents list of arguments parsed against a {@link Options} descriptor. 30 | * 31 | *

It allows querying of a boolean {@link #hasOption(String opt)}, 32 | * in addition to retrieving the {@link #getOptionValue(String opt)} 33 | * for options requiring arguments.

34 | * 35 | *

Additionally, any left-over or unrecognized arguments, 36 | * are available for further processing.

37 | * 38 | * @author bob mcwhirter (bob @ werken.com) 39 | * @author James Strachan 40 | * @author John Keyes (john at integralsource.com) 41 | * @version $Revision: 735247 $, $Date: 2009-01-17 00:23:35 -0800 (Sat, 17 Jan 2009) $ 42 | */ 43 | public class CommandLine implements Serializable 44 | { 45 | private static final long serialVersionUID = 1L; 46 | 47 | /** the unrecognised options/arguments */ 48 | private List args = new LinkedList(); 49 | 50 | /** the processed options */ 51 | private List options = new ArrayList(); 52 | 53 | /** 54 | * Creates a command line. 55 | */ 56 | CommandLine() 57 | { 58 | // nothing to do 59 | } 60 | 61 | /** 62 | * Query to see if an option has been set. 63 | * 64 | * @param opt Short name of the option 65 | * @return true if set, false if not 66 | */ 67 | public boolean hasOption(String opt) 68 | { 69 | return options.contains(resolveOption(opt)); 70 | } 71 | 72 | /** 73 | * Query to see if an option has been set. 74 | * 75 | * @param opt character name of the option 76 | * @return true if set, false if not 77 | */ 78 | public boolean hasOption(char opt) 79 | { 80 | return hasOption(String.valueOf(opt)); 81 | } 82 | 83 | /** 84 | * Return the Object type of this Option. 85 | * 86 | * @param opt the name of the option 87 | * @return the type of this Option 88 | * @deprecated due to System.err message. Instead use getParsedOptionValue(String) 89 | */ 90 | public Object getOptionObject(String opt) 91 | { 92 | try { 93 | return getParsedOptionValue(opt); 94 | } catch(ParseException pe) { 95 | System.err.println("Exception found converting " + opt + " to desired type: " + 96 | pe.getMessage() ); 97 | return null; 98 | } 99 | } 100 | 101 | /** 102 | * Return a version of this Option converted to a particular type. 103 | * 104 | * @param opt the name of the option 105 | * @return the value parsed into a particluar object 106 | * @throws ParseException if there are problems turning the option value into the desired type 107 | * @see PatternOptionBuilder 108 | */ 109 | public Object getParsedOptionValue(String opt) 110 | throws ParseException 111 | { 112 | String res = getOptionValue(opt); 113 | 114 | Option option = resolveOption(opt); 115 | if (option == null) 116 | { 117 | return null; 118 | } 119 | 120 | Object type = option.getType(); 121 | 122 | return (res == null) ? null : TypeHandler.createValue(res, type); 123 | } 124 | 125 | /** 126 | * Return the Object type of this Option. 127 | * 128 | * @param opt the name of the option 129 | * @return the type of opt 130 | */ 131 | public Object getOptionObject(char opt) 132 | { 133 | return getOptionObject(String.valueOf(opt)); 134 | } 135 | 136 | /** 137 | * Retrieve the argument, if any, of this option. 138 | * 139 | * @param opt the name of the option 140 | * @return Value of the argument if option is set, and has an argument, 141 | * otherwise null. 142 | */ 143 | public String getOptionValue(String opt) 144 | { 145 | String[] values = getOptionValues(opt); 146 | 147 | return (values == null) ? null : values[0]; 148 | } 149 | 150 | /** 151 | * Retrieve the argument, if any, of this option. 152 | * 153 | * @param opt the character name of the option 154 | * @return Value of the argument if option is set, and has an argument, 155 | * otherwise null. 156 | */ 157 | public String getOptionValue(char opt) 158 | { 159 | return getOptionValue(String.valueOf(opt)); 160 | } 161 | 162 | /** 163 | * Retrieves the array of values, if any, of an option. 164 | * 165 | * @param opt string name of the option 166 | * @return Values of the argument if option is set, and has an argument, 167 | * otherwise null. 168 | */ 169 | public String[] getOptionValues(String opt) 170 | { 171 | List values = new ArrayList(); 172 | 173 | for (Iterator it = options.iterator(); it.hasNext();) 174 | { 175 | Option option = (Option) it.next(); 176 | if (opt.equals(option.getOpt()) || opt.equals(option.getLongOpt())) 177 | { 178 | values.addAll(option.getValuesList()); 179 | } 180 | } 181 | 182 | return values.isEmpty() ? null : (String[]) values.toArray(new String[values.size()]); 183 | } 184 | 185 | /** 186 | * Retrieves the option object given the long or short option as a String 187 | * 188 | * @param opt short or long name of the option 189 | * @return Canonicalized option 190 | */ 191 | private Option resolveOption(String opt) 192 | { 193 | opt = Util.stripLeadingHyphens(opt); 194 | for (Iterator it = options.iterator(); it.hasNext();) 195 | { 196 | Option option = (Option) it.next(); 197 | if (opt.equals(option.getOpt())) 198 | { 199 | return option; 200 | } 201 | 202 | if (opt.equals(option.getLongOpt())) 203 | { 204 | return option; 205 | } 206 | 207 | } 208 | return null; 209 | } 210 | 211 | /** 212 | * Retrieves the array of values, if any, of an option. 213 | * 214 | * @param opt character name of the option 215 | * @return Values of the argument if option is set, and has an argument, 216 | * otherwise null. 217 | */ 218 | public String[] getOptionValues(char opt) 219 | { 220 | return getOptionValues(String.valueOf(opt)); 221 | } 222 | 223 | /** 224 | * Retrieve the argument, if any, of an option. 225 | * 226 | * @param opt name of the option 227 | * @param defaultValue is the default value to be returned if the option 228 | * is not specified 229 | * @return Value of the argument if option is set, and has an argument, 230 | * otherwise defaultValue. 231 | */ 232 | public String getOptionValue(String opt, String defaultValue) 233 | { 234 | String answer = getOptionValue(opt); 235 | 236 | return (answer != null) ? answer : defaultValue; 237 | } 238 | 239 | /** 240 | * Retrieve the argument, if any, of an option. 241 | * 242 | * @param opt character name of the option 243 | * @param defaultValue is the default value to be returned if the option 244 | * is not specified 245 | * @return Value of the argument if option is set, and has an argument, 246 | * otherwise defaultValue. 247 | */ 248 | public String getOptionValue(char opt, String defaultValue) 249 | { 250 | return getOptionValue(String.valueOf(opt), defaultValue); 251 | } 252 | 253 | /** 254 | * Retrieve the map of values associated to the option. This is convenient 255 | * for options specifying Java properties like -Dparam1=value1 256 | * -Dparam2=value2. The first argument of the option is the key, and 257 | * the 2nd argument is the value. If the option has only one argument 258 | * (-Dfoo) it is considered as a boolean flag and the value is 259 | * "true". 260 | * 261 | * @param opt name of the option 262 | * @return The Properties mapped by the option, never null 263 | * even if the option doesn't exists 264 | * @since 1.2 265 | */ 266 | public Properties getOptionProperties(String opt) 267 | { 268 | Properties props = new Properties(); 269 | 270 | for (Iterator it = options.iterator(); it.hasNext();) 271 | { 272 | Option option = (Option) it.next(); 273 | 274 | if (opt.equals(option.getOpt()) || opt.equals(option.getLongOpt())) 275 | { 276 | List values = option.getValuesList(); 277 | if (values.size() >= 2) 278 | { 279 | // use the first 2 arguments as the key/value pair 280 | props.put(values.get(0), values.get(1)); 281 | } 282 | else if (values.size() == 1) 283 | { 284 | // no explicit value, handle it as a boolean 285 | props.put(values.get(0), "true"); 286 | } 287 | } 288 | } 289 | 290 | return props; 291 | } 292 | 293 | /** 294 | * Retrieve any left-over non-recognized options and arguments 295 | * 296 | * @return remaining items passed in but not parsed as an array 297 | */ 298 | public String[] getArgs() 299 | { 300 | String[] answer = new String[args.size()]; 301 | 302 | args.toArray(answer); 303 | 304 | return answer; 305 | } 306 | 307 | /** 308 | * Retrieve any left-over non-recognized options and arguments 309 | * 310 | * @return remaining items passed in but not parsed as a List. 311 | */ 312 | public List getArgList() 313 | { 314 | return args; 315 | } 316 | 317 | /** 318 | * jkeyes 319 | * - commented out until it is implemented properly 320 | *

Dump state, suitable for debugging.

321 | * 322 | * @return Stringified form of this object 323 | */ 324 | 325 | /* 326 | public String toString() { 327 | StringBuffer buf = new StringBuffer(); 328 | 329 | buf.append("[ CommandLine: [ options: "); 330 | buf.append(options.toString()); 331 | buf.append(" ] [ args: "); 332 | buf.append(args.toString()); 333 | buf.append(" ] ]"); 334 | 335 | return buf.toString(); 336 | } 337 | */ 338 | 339 | /** 340 | * Add left-over unrecognized option/argument. 341 | * 342 | * @param arg the unrecognised option/argument. 343 | */ 344 | void addArg(String arg) 345 | { 346 | args.add(arg); 347 | } 348 | 349 | /** 350 | * Add an option to the command line. The values of the option are stored. 351 | * 352 | * @param opt the processed option 353 | */ 354 | void addOption(Option opt) 355 | { 356 | options.add(opt); 357 | } 358 | 359 | /** 360 | * Returns an iterator over the Option members of CommandLine. 361 | * 362 | * @return an Iterator over the processed {@link Option} 363 | * members of this {@link CommandLine} 364 | */ 365 | public Iterator iterator() 366 | { 367 | return options.iterator(); 368 | } 369 | 370 | /** 371 | * Returns an array of the processed {@link Option}s. 372 | * 373 | * @return an array of the processed {@link Option}s. 374 | */ 375 | public Option[] getOptions() 376 | { 377 | Collection processed = options; 378 | 379 | // reinitialise array 380 | Option[] optionsArray = new Option[processed.size()]; 381 | 382 | // return the array 383 | return (Option[]) processed.toArray(optionsArray); 384 | } 385 | } 386 | -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/cli/CommandLineParser.java: -------------------------------------------------------------------------------- 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 com.github.jobop.performance.cli; 19 | 20 | 21 | /** 22 | * A class that implements the CommandLineParser interface 23 | * can parse a String array according to the {@link Options} specified 24 | * and return a {@link CommandLine}. 25 | * 26 | * @author John Keyes (john at integralsource.com) 27 | * @version $Revision: 680644 $, $Date: 2008-07-29 01:13:48 -0700 (Tue, 29 Jul 2008) $ 28 | */ 29 | public interface CommandLineParser 30 | { 31 | /** 32 | * Parse the arguments according to the specified options. 33 | * 34 | * @param options the specified Options 35 | * @param arguments the command line arguments 36 | * @return the list of atomic option and value tokens 37 | * 38 | * @throws ParseException if there are any problems encountered 39 | * while parsing the command line tokens. 40 | */ 41 | CommandLine parse(Options options, String[] arguments) throws ParseException; 42 | 43 | /** 44 | * Parse the arguments according to the specified options and 45 | * properties. 46 | * 47 | * @param options the specified Options 48 | * @param arguments the command line arguments 49 | * @param properties command line option name-value pairs 50 | * @return the list of atomic option and value tokens 51 | * 52 | * @throws ParseException if there are any problems encountered 53 | * while parsing the command line tokens. 54 | */ 55 | /* To maintain binary compatibility, this is commented out. 56 | It is still in the abstract Parser class, so most users will 57 | still reap the benefit. 58 | CommandLine parse(Options options, String[] arguments, Properties properties) 59 | throws ParseException; 60 | */ 61 | 62 | /** 63 | * Parse the arguments according to the specified options. 64 | * 65 | * @param options the specified Options 66 | * @param arguments the command line arguments 67 | * @param stopAtNonOption specifies whether to continue parsing the 68 | * arguments if a non option is encountered. 69 | * 70 | * @return the list of atomic option and value tokens 71 | * @throws ParseException if there are any problems encountered 72 | * while parsing the command line tokens. 73 | */ 74 | CommandLine parse(Options options, String[] arguments, boolean stopAtNonOption) throws ParseException; 75 | 76 | /** 77 | * Parse the arguments according to the specified options and 78 | * properties. 79 | * 80 | * @param options the specified Options 81 | * @param arguments the command line arguments 82 | * @param properties command line option name-value pairs 83 | * @param stopAtNonOption specifies whether to continue parsing the 84 | * 85 | * @return the list of atomic option and value tokens 86 | * @throws ParseException if there are any problems encountered 87 | * while parsing the command line tokens. 88 | */ 89 | /* To maintain binary compatibility, this is commented out. 90 | It is still in the abstract Parser class, so most users will 91 | still reap the benefit. 92 | CommandLine parse(Options options, String[] arguments, Properties properties, boolean stopAtNonOption) 93 | throws ParseException; 94 | */ 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/cli/GnuParser.java: -------------------------------------------------------------------------------- 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 com.github.jobop.performance.cli; 19 | 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | 23 | /** 24 | * The class GnuParser provides an implementation of the 25 | * {@link Parser#flatten(Options, String[], boolean) flatten} method. 26 | * 27 | * @author John Keyes (john at integralsource.com) 28 | * @version $Revision: 680644 $, $Date: 2008-07-29 01:13:48 -0700 (Tue, 29 Jul 2008) $ 29 | */ 30 | public class GnuParser extends Parser 31 | { 32 | /** 33 | * This flatten method does so using the following rules: 34 | *
    35 | *
  1. If an {@link Option} exists for the first character of 36 | * the arguments entry AND an {@link Option} 37 | * does not exist for the whole argument then 38 | * add the first character as an option to the processed tokens 39 | * list e.g. "-D" and add the rest of the entry to the also.
  2. 40 | *
  3. Otherwise just add the token to the processed tokens list.
  4. 41 | *
42 | * 43 | * @param options The Options to parse the arguments by. 44 | * @param arguments The arguments that have to be flattened. 45 | * @param stopAtNonOption specifies whether to stop flattening when 46 | * a non option has been encountered 47 | * @return a String array of the flattened arguments 48 | */ 49 | protected String[] flatten(Options options, String[] arguments, boolean stopAtNonOption) 50 | { 51 | List tokens = new ArrayList(); 52 | 53 | boolean eatTheRest = false; 54 | 55 | for (int i = 0; i < arguments.length; i++) 56 | { 57 | String arg = arguments[i]; 58 | 59 | if ("--".equals(arg)) 60 | { 61 | eatTheRest = true; 62 | tokens.add("--"); 63 | } 64 | else if ("-".equals(arg)) 65 | { 66 | tokens.add("-"); 67 | } 68 | else if (arg.startsWith("-")) 69 | { 70 | String opt = Util.stripLeadingHyphens(arg); 71 | 72 | if (options.hasOption(opt)) 73 | { 74 | tokens.add(arg); 75 | } 76 | else 77 | { 78 | if (opt.indexOf('=') != -1 && options.hasOption(opt.substring(0, opt.indexOf('=')))) 79 | { 80 | // the format is --foo=value or -foo=value 81 | tokens.add(arg.substring(0, arg.indexOf('='))); // --foo 82 | tokens.add(arg.substring(arg.indexOf('=') + 1)); // value 83 | } 84 | else if (options.hasOption(arg.substring(0, 2))) 85 | { 86 | // the format is a special properties option (-Dproperty=value) 87 | tokens.add(arg.substring(0, 2)); // -D 88 | tokens.add(arg.substring(2)); // property=value 89 | } 90 | else 91 | { 92 | eatTheRest = stopAtNonOption; 93 | tokens.add(arg); 94 | } 95 | } 96 | } 97 | else 98 | { 99 | tokens.add(arg); 100 | } 101 | 102 | if (eatTheRest) 103 | { 104 | for (i++; i < arguments.length; i++) 105 | { 106 | tokens.add(arguments[i]); 107 | } 108 | } 109 | } 110 | 111 | return (String[]) tokens.toArray(new String[tokens.size()]); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/cli/HelpFormatter.java: -------------------------------------------------------------------------------- 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 com.github.jobop.performance.cli; 19 | 20 | import java.io.PrintWriter; 21 | import java.util.ArrayList; 22 | import java.util.Collection; 23 | import java.util.Collections; 24 | import java.util.Comparator; 25 | import java.util.Iterator; 26 | import java.util.List; 27 | 28 | /** 29 | * A formatter of help messages for the current command line options 30 | * 31 | * @author Slawek Zachcial 32 | * @author John Keyes (john at integralsource.com) 33 | * @version $Revision: 751120 $, $Date: 2009-03-06 14:45:57 -0800 (Fri, 06 Mar 2009) $ 34 | */ 35 | public class HelpFormatter 36 | { 37 | // --------------------------------------------------------------- Constants 38 | 39 | /** default number of characters per line */ 40 | public static final int DEFAULT_WIDTH = 74; 41 | 42 | /** default padding to the left of each line */ 43 | public static final int DEFAULT_LEFT_PAD = 1; 44 | 45 | /** 46 | * the number of characters of padding to be prefixed 47 | * to each description line 48 | */ 49 | public static final int DEFAULT_DESC_PAD = 3; 50 | 51 | /** the string to display at the beginning of the usage statement */ 52 | public static final String DEFAULT_SYNTAX_PREFIX = "usage: "; 53 | 54 | /** default prefix for shortOpts */ 55 | public static final String DEFAULT_OPT_PREFIX = "-"; 56 | 57 | /** default prefix for long Option */ 58 | public static final String DEFAULT_LONG_OPT_PREFIX = "--"; 59 | 60 | /** default name for an argument */ 61 | public static final String DEFAULT_ARG_NAME = "arg"; 62 | 63 | // -------------------------------------------------------------- Attributes 64 | 65 | /** 66 | * number of characters per line 67 | * 68 | * @deprecated Scope will be made private for next major version 69 | * - use get/setWidth methods instead. 70 | */ 71 | public int defaultWidth = DEFAULT_WIDTH; 72 | 73 | /** 74 | * amount of padding to the left of each line 75 | * 76 | * @deprecated Scope will be made private for next major version 77 | * - use get/setLeftPadding methods instead. 78 | */ 79 | public int defaultLeftPad = DEFAULT_LEFT_PAD; 80 | 81 | /** 82 | * the number of characters of padding to be prefixed 83 | * to each description line 84 | * 85 | * @deprecated Scope will be made private for next major version 86 | * - use get/setDescPadding methods instead. 87 | */ 88 | public int defaultDescPad = DEFAULT_DESC_PAD; 89 | 90 | /** 91 | * the string to display at the begining of the usage statement 92 | * 93 | * @deprecated Scope will be made private for next major version 94 | * - use get/setSyntaxPrefix methods instead. 95 | */ 96 | public String defaultSyntaxPrefix = DEFAULT_SYNTAX_PREFIX; 97 | 98 | /** 99 | * the new line string 100 | * 101 | * @deprecated Scope will be made private for next major version 102 | * - use get/setNewLine methods instead. 103 | */ 104 | public String defaultNewLine = System.getProperty("line.separator"); 105 | 106 | /** 107 | * the shortOpt prefix 108 | * 109 | * @deprecated Scope will be made private for next major version 110 | * - use get/setOptPrefix methods instead. 111 | */ 112 | public String defaultOptPrefix = DEFAULT_OPT_PREFIX; 113 | 114 | /** 115 | * the long Opt prefix 116 | * 117 | * @deprecated Scope will be made private for next major version 118 | * - use get/setLongOptPrefix methods instead. 119 | */ 120 | public String defaultLongOptPrefix = DEFAULT_LONG_OPT_PREFIX; 121 | 122 | /** 123 | * the name of the argument 124 | * 125 | * @deprecated Scope will be made private for next major version 126 | * - use get/setArgName methods instead. 127 | */ 128 | public String defaultArgName = DEFAULT_ARG_NAME; 129 | 130 | /** 131 | * Comparator used to sort the options when they output in help text 132 | * 133 | * Defaults to case-insensitive alphabetical sorting by option key 134 | */ 135 | protected Comparator optionComparator = new OptionComparator(); 136 | 137 | /** 138 | * Sets the 'width'. 139 | * 140 | * @param width the new value of 'width' 141 | */ 142 | public void setWidth(int width) 143 | { 144 | this.defaultWidth = width; 145 | } 146 | 147 | /** 148 | * Returns the 'width'. 149 | * 150 | * @return the 'width' 151 | */ 152 | public int getWidth() 153 | { 154 | return defaultWidth; 155 | } 156 | 157 | /** 158 | * Sets the 'leftPadding'. 159 | * 160 | * @param padding the new value of 'leftPadding' 161 | */ 162 | public void setLeftPadding(int padding) 163 | { 164 | this.defaultLeftPad = padding; 165 | } 166 | 167 | /** 168 | * Returns the 'leftPadding'. 169 | * 170 | * @return the 'leftPadding' 171 | */ 172 | public int getLeftPadding() 173 | { 174 | return defaultLeftPad; 175 | } 176 | 177 | /** 178 | * Sets the 'descPadding'. 179 | * 180 | * @param padding the new value of 'descPadding' 181 | */ 182 | public void setDescPadding(int padding) 183 | { 184 | this.defaultDescPad = padding; 185 | } 186 | 187 | /** 188 | * Returns the 'descPadding'. 189 | * 190 | * @return the 'descPadding' 191 | */ 192 | public int getDescPadding() 193 | { 194 | return defaultDescPad; 195 | } 196 | 197 | /** 198 | * Sets the 'syntaxPrefix'. 199 | * 200 | * @param prefix the new value of 'syntaxPrefix' 201 | */ 202 | public void setSyntaxPrefix(String prefix) 203 | { 204 | this.defaultSyntaxPrefix = prefix; 205 | } 206 | 207 | /** 208 | * Returns the 'syntaxPrefix'. 209 | * 210 | * @return the 'syntaxPrefix' 211 | */ 212 | public String getSyntaxPrefix() 213 | { 214 | return defaultSyntaxPrefix; 215 | } 216 | 217 | /** 218 | * Sets the 'newLine'. 219 | * 220 | * @param newline the new value of 'newLine' 221 | */ 222 | public void setNewLine(String newline) 223 | { 224 | this.defaultNewLine = newline; 225 | } 226 | 227 | /** 228 | * Returns the 'newLine'. 229 | * 230 | * @return the 'newLine' 231 | */ 232 | public String getNewLine() 233 | { 234 | return defaultNewLine; 235 | } 236 | 237 | /** 238 | * Sets the 'optPrefix'. 239 | * 240 | * @param prefix the new value of 'optPrefix' 241 | */ 242 | public void setOptPrefix(String prefix) 243 | { 244 | this.defaultOptPrefix = prefix; 245 | } 246 | 247 | /** 248 | * Returns the 'optPrefix'. 249 | * 250 | * @return the 'optPrefix' 251 | */ 252 | public String getOptPrefix() 253 | { 254 | return defaultOptPrefix; 255 | } 256 | 257 | /** 258 | * Sets the 'longOptPrefix'. 259 | * 260 | * @param prefix the new value of 'longOptPrefix' 261 | */ 262 | public void setLongOptPrefix(String prefix) 263 | { 264 | this.defaultLongOptPrefix = prefix; 265 | } 266 | 267 | /** 268 | * Returns the 'longOptPrefix'. 269 | * 270 | * @return the 'longOptPrefix' 271 | */ 272 | public String getLongOptPrefix() 273 | { 274 | return defaultLongOptPrefix; 275 | } 276 | 277 | /** 278 | * Sets the 'argName'. 279 | * 280 | * @param name the new value of 'argName' 281 | */ 282 | public void setArgName(String name) 283 | { 284 | this.defaultArgName = name; 285 | } 286 | 287 | /** 288 | * Returns the 'argName'. 289 | * 290 | * @return the 'argName' 291 | */ 292 | public String getArgName() 293 | { 294 | return defaultArgName; 295 | } 296 | 297 | /** 298 | * Comparator used to sort the options when they output in help text 299 | * 300 | * Defaults to case-insensitive alphabetical sorting by option key 301 | */ 302 | public Comparator getOptionComparator() 303 | { 304 | return optionComparator; 305 | } 306 | 307 | /** 308 | * Set the comparator used to sort the options when they output in help text 309 | * 310 | * Passing in a null parameter will set the ordering to the default mode 311 | */ 312 | public void setOptionComparator(Comparator comparator) 313 | { 314 | if (comparator == null) 315 | { 316 | this.optionComparator = new OptionComparator(); 317 | } 318 | else 319 | { 320 | this.optionComparator = comparator; 321 | } 322 | } 323 | 324 | /** 325 | * Print the help for options with the specified 326 | * command line syntax. This method prints help information to 327 | * System.out. 328 | * 329 | * @param cmdLineSyntax the syntax for this application 330 | * @param options the Options instance 331 | */ 332 | public void printHelp(String cmdLineSyntax, Options options) 333 | { 334 | printHelp(defaultWidth, cmdLineSyntax, null, options, null, false); 335 | } 336 | 337 | /** 338 | * Print the help for options with the specified 339 | * command line syntax. This method prints help information to 340 | * System.out. 341 | * 342 | * @param cmdLineSyntax the syntax for this application 343 | * @param options the Options instance 344 | * @param autoUsage whether to print an automatically generated 345 | * usage statement 346 | */ 347 | public void printHelp(String cmdLineSyntax, Options options, boolean autoUsage) 348 | { 349 | printHelp(defaultWidth, cmdLineSyntax, null, options, null, autoUsage); 350 | } 351 | 352 | /** 353 | * Print the help for options with the specified 354 | * command line syntax. This method prints help information to 355 | * System.out. 356 | * 357 | * @param cmdLineSyntax the syntax for this application 358 | * @param header the banner to display at the begining of the help 359 | * @param options the Options instance 360 | * @param footer the banner to display at the end of the help 361 | */ 362 | public void printHelp(String cmdLineSyntax, String header, Options options, String footer) 363 | { 364 | printHelp(cmdLineSyntax, header, options, footer, false); 365 | } 366 | 367 | /** 368 | * Print the help for options with the specified 369 | * command line syntax. This method prints help information to 370 | * System.out. 371 | * 372 | * @param cmdLineSyntax the syntax for this application 373 | * @param header the banner to display at the begining of the help 374 | * @param options the Options instance 375 | * @param footer the banner to display at the end of the help 376 | * @param autoUsage whether to print an automatically generated 377 | * usage statement 378 | */ 379 | public void printHelp(String cmdLineSyntax, String header, Options options, String footer, boolean autoUsage) 380 | { 381 | printHelp(defaultWidth, cmdLineSyntax, header, options, footer, autoUsage); 382 | } 383 | 384 | /** 385 | * Print the help for options with the specified 386 | * command line syntax. This method prints help information to 387 | * System.out. 388 | * 389 | * @param width the number of characters to be displayed on each line 390 | * @param cmdLineSyntax the syntax for this application 391 | * @param header the banner to display at the beginning of the help 392 | * @param options the Options instance 393 | * @param footer the banner to display at the end of the help 394 | */ 395 | public void printHelp(int width, String cmdLineSyntax, String header, Options options, String footer) 396 | { 397 | printHelp(width, cmdLineSyntax, header, options, footer, false); 398 | } 399 | 400 | /** 401 | * Print the help for options with the specified 402 | * command line syntax. This method prints help information to 403 | * System.out. 404 | * 405 | * @param width the number of characters to be displayed on each line 406 | * @param cmdLineSyntax the syntax for this application 407 | * @param header the banner to display at the begining of the help 408 | * @param options the Options instance 409 | * @param footer the banner to display at the end of the help 410 | * @param autoUsage whether to print an automatically generated 411 | * usage statement 412 | */ 413 | public void printHelp(int width, String cmdLineSyntax, String header, 414 | Options options, String footer, boolean autoUsage) 415 | { 416 | PrintWriter pw = new PrintWriter(System.out); 417 | 418 | printHelp(pw, width, cmdLineSyntax, header, options, defaultLeftPad, defaultDescPad, footer, autoUsage); 419 | pw.flush(); 420 | } 421 | 422 | /** 423 | * Print the help for options with the specified 424 | * command line syntax. 425 | * 426 | * @param pw the writer to which the help will be written 427 | * @param width the number of characters to be displayed on each line 428 | * @param cmdLineSyntax the syntax for this application 429 | * @param header the banner to display at the begining of the help 430 | * @param options the Options instance 431 | * @param leftPad the number of characters of padding to be prefixed 432 | * to each line 433 | * @param descPad the number of characters of padding to be prefixed 434 | * to each description line 435 | * @param footer the banner to display at the end of the help 436 | * 437 | * @throws IllegalStateException if there is no room to print a line 438 | */ 439 | public void printHelp(PrintWriter pw, int width, String cmdLineSyntax, 440 | String header, Options options, int leftPad, 441 | int descPad, String footer) 442 | { 443 | printHelp(pw, width, cmdLineSyntax, header, options, leftPad, descPad, footer, false); 444 | } 445 | 446 | 447 | /** 448 | * Print the help for options with the specified 449 | * command line syntax. 450 | * 451 | * @param pw the writer to which the help will be written 452 | * @param width the number of characters to be displayed on each line 453 | * @param cmdLineSyntax the syntax for this application 454 | * @param header the banner to display at the begining of the help 455 | * @param options the Options instance 456 | * @param leftPad the number of characters of padding to be prefixed 457 | * to each line 458 | * @param descPad the number of characters of padding to be prefixed 459 | * to each description line 460 | * @param footer the banner to display at the end of the help 461 | * @param autoUsage whether to print an automatically generated 462 | * usage statement 463 | * 464 | * @throws IllegalStateException if there is no room to print a line 465 | */ 466 | public void printHelp(PrintWriter pw, int width, String cmdLineSyntax, 467 | String header, Options options, int leftPad, 468 | int descPad, String footer, boolean autoUsage) 469 | { 470 | if ((cmdLineSyntax == null) || (cmdLineSyntax.length() == 0)) 471 | { 472 | throw new IllegalArgumentException("cmdLineSyntax not provided"); 473 | } 474 | 475 | if (autoUsage) 476 | { 477 | printUsage(pw, width, cmdLineSyntax, options); 478 | } 479 | else 480 | { 481 | printUsage(pw, width, cmdLineSyntax); 482 | } 483 | 484 | if ((header != null) && (header.trim().length() > 0)) 485 | { 486 | printWrapped(pw, width, header); 487 | } 488 | 489 | printOptions(pw, width, options, leftPad, descPad); 490 | 491 | if ((footer != null) && (footer.trim().length() > 0)) 492 | { 493 | printWrapped(pw, width, footer); 494 | } 495 | } 496 | 497 | /** 498 | *

Prints the usage statement for the specified application.

499 | * 500 | * @param pw The PrintWriter to print the usage statement 501 | * @param width The number of characters to display per line 502 | * @param app The application name 503 | * @param options The command line Options 504 | * 505 | */ 506 | public void printUsage(PrintWriter pw, int width, String app, Options options) 507 | { 508 | // initialise the string buffer 509 | StringBuffer buff = new StringBuffer(defaultSyntaxPrefix).append(app).append(" "); 510 | 511 | // create a list for processed option groups 512 | final Collection processedGroups = new ArrayList(); 513 | 514 | // temp variable 515 | Option option; 516 | 517 | List optList = new ArrayList(options.getOptions()); 518 | Collections.sort(optList, getOptionComparator()); 519 | // iterate over the options 520 | for (Iterator i = optList.iterator(); i.hasNext();) 521 | { 522 | // get the next Option 523 | option = (Option) i.next(); 524 | 525 | // check if the option is part of an OptionGroup 526 | OptionGroup group = options.getOptionGroup(option); 527 | 528 | // if the option is part of a group 529 | if (group != null) 530 | { 531 | // and if the group has not already been processed 532 | if (!processedGroups.contains(group)) 533 | { 534 | // add the group to the processed list 535 | processedGroups.add(group); 536 | 537 | 538 | // add the usage clause 539 | appendOptionGroup(buff, group); 540 | } 541 | 542 | // otherwise the option was displayed in the group 543 | // previously so ignore it. 544 | } 545 | 546 | // if the Option is not part of an OptionGroup 547 | else 548 | { 549 | appendOption(buff, option, option.isRequired()); 550 | } 551 | 552 | if (i.hasNext()) 553 | { 554 | buff.append(" "); 555 | } 556 | } 557 | 558 | 559 | // call printWrapped 560 | printWrapped(pw, width, buff.toString().indexOf(' ') + 1, buff.toString()); 561 | } 562 | 563 | /** 564 | * Appends the usage clause for an OptionGroup to a StringBuffer. 565 | * The clause is wrapped in square brackets if the group is required. 566 | * The display of the options is handled by appendOption 567 | * @param buff the StringBuffer to append to 568 | * @param group the group to append 569 | * @see #appendOption(StringBuffer,Option,boolean) 570 | */ 571 | private void appendOptionGroup(final StringBuffer buff, final OptionGroup group) 572 | { 573 | if (!group.isRequired()) 574 | { 575 | buff.append("["); 576 | } 577 | 578 | List optList = new ArrayList(group.getOptions()); 579 | Collections.sort(optList, getOptionComparator()); 580 | // for each option in the OptionGroup 581 | for (Iterator i = optList.iterator(); i.hasNext();) 582 | { 583 | // whether the option is required or not is handled at group level 584 | appendOption(buff, (Option) i.next(), true); 585 | 586 | if (i.hasNext()) 587 | { 588 | buff.append(" | "); 589 | } 590 | } 591 | 592 | if (!group.isRequired()) 593 | { 594 | buff.append("]"); 595 | } 596 | } 597 | 598 | /** 599 | * Appends the usage clause for an Option to a StringBuffer. 600 | * 601 | * @param buff the StringBuffer to append to 602 | * @param option the Option to append 603 | * @param required whether the Option is required or not 604 | */ 605 | private static void appendOption(final StringBuffer buff, final Option option, final boolean required) 606 | { 607 | if (!required) 608 | { 609 | buff.append("["); 610 | } 611 | 612 | if (option.getOpt() != null) 613 | { 614 | buff.append("-").append(option.getOpt()); 615 | } 616 | else 617 | { 618 | buff.append("--").append(option.getLongOpt()); 619 | } 620 | 621 | // if the Option has a value 622 | if (option.hasArg() && option.hasArgName()) 623 | { 624 | buff.append(" <").append(option.getArgName()).append(">"); 625 | } 626 | 627 | // if the Option is not a required option 628 | if (!required) 629 | { 630 | buff.append("]"); 631 | } 632 | } 633 | 634 | /** 635 | * Print the cmdLineSyntax to the specified writer, using the 636 | * specified width. 637 | * 638 | * @param pw The printWriter to write the help to 639 | * @param width The number of characters per line for the usage statement. 640 | * @param cmdLineSyntax The usage statement. 641 | */ 642 | public void printUsage(PrintWriter pw, int width, String cmdLineSyntax) 643 | { 644 | int argPos = cmdLineSyntax.indexOf(' ') + 1; 645 | 646 | printWrapped(pw, width, defaultSyntaxPrefix.length() + argPos, defaultSyntaxPrefix + cmdLineSyntax); 647 | } 648 | 649 | /** 650 | *

Print the help for the specified Options to the specified writer, 651 | * using the specified width, left padding and description padding.

652 | * 653 | * @param pw The printWriter to write the help to 654 | * @param width The number of characters to display per line 655 | * @param options The command line Options 656 | * @param leftPad the number of characters of padding to be prefixed 657 | * to each line 658 | * @param descPad the number of characters of padding to be prefixed 659 | * to each description line 660 | */ 661 | public void printOptions(PrintWriter pw, int width, Options options, 662 | int leftPad, int descPad) 663 | { 664 | StringBuffer sb = new StringBuffer(); 665 | 666 | renderOptions(sb, width, options, leftPad, descPad); 667 | pw.println(sb.toString()); 668 | } 669 | 670 | /** 671 | * Print the specified text to the specified PrintWriter. 672 | * 673 | * @param pw The printWriter to write the help to 674 | * @param width The number of characters to display per line 675 | * @param text The text to be written to the PrintWriter 676 | */ 677 | public void printWrapped(PrintWriter pw, int width, String text) 678 | { 679 | printWrapped(pw, width, 0, text); 680 | } 681 | 682 | /** 683 | * Print the specified text to the specified PrintWriter. 684 | * 685 | * @param pw The printWriter to write the help to 686 | * @param width The number of characters to display per line 687 | * @param nextLineTabStop The position on the next line for the first tab. 688 | * @param text The text to be written to the PrintWriter 689 | */ 690 | public void printWrapped(PrintWriter pw, int width, int nextLineTabStop, String text) 691 | { 692 | StringBuffer sb = new StringBuffer(text.length()); 693 | 694 | renderWrappedText(sb, width, nextLineTabStop, text); 695 | pw.println(sb.toString()); 696 | } 697 | 698 | // --------------------------------------------------------------- Protected 699 | 700 | /** 701 | * Render the specified Options and return the rendered Options 702 | * in a StringBuffer. 703 | * 704 | * @param sb The StringBuffer to place the rendered Options into. 705 | * @param width The number of characters to display per line 706 | * @param options The command line Options 707 | * @param leftPad the number of characters of padding to be prefixed 708 | * to each line 709 | * @param descPad the number of characters of padding to be prefixed 710 | * to each description line 711 | * 712 | * @return the StringBuffer with the rendered Options contents. 713 | */ 714 | protected StringBuffer renderOptions(StringBuffer sb, int width, Options options, int leftPad, int descPad) 715 | { 716 | final String lpad = createPadding(leftPad); 717 | final String dpad = createPadding(descPad); 718 | 719 | // first create list containing only -a,--aaa where 720 | // -a is opt and --aaa is long opt; in parallel look for 721 | // the longest opt string this list will be then used to 722 | // sort options ascending 723 | int max = 0; 724 | StringBuffer optBuf; 725 | List prefixList = new ArrayList(); 726 | 727 | List optList = options.helpOptions(); 728 | 729 | Collections.sort(optList, getOptionComparator()); 730 | 731 | for (Iterator i = optList.iterator(); i.hasNext();) 732 | { 733 | Option option = (Option) i.next(); 734 | optBuf = new StringBuffer(8); 735 | 736 | if (option.getOpt() == null) 737 | { 738 | optBuf.append(lpad).append(" " + defaultLongOptPrefix).append(option.getLongOpt()); 739 | } 740 | else 741 | { 742 | optBuf.append(lpad).append(defaultOptPrefix).append(option.getOpt()); 743 | 744 | if (option.hasLongOpt()) 745 | { 746 | optBuf.append(',').append(defaultLongOptPrefix).append(option.getLongOpt()); 747 | } 748 | } 749 | 750 | if (option.hasArg()) 751 | { 752 | if (option.hasArgName()) 753 | { 754 | optBuf.append(" <").append(option.getArgName()).append(">"); 755 | } 756 | else 757 | { 758 | optBuf.append(' '); 759 | } 760 | } 761 | 762 | prefixList.add(optBuf); 763 | max = (optBuf.length() > max) ? optBuf.length() : max; 764 | } 765 | 766 | int x = 0; 767 | 768 | for (Iterator i = optList.iterator(); i.hasNext();) 769 | { 770 | Option option = (Option) i.next(); 771 | optBuf = new StringBuffer(prefixList.get(x++).toString()); 772 | 773 | if (optBuf.length() < max) 774 | { 775 | optBuf.append(createPadding(max - optBuf.length())); 776 | } 777 | 778 | optBuf.append(dpad); 779 | 780 | int nextLineTabStop = max + descPad; 781 | 782 | if (option.getDescription() != null) 783 | { 784 | optBuf.append(option.getDescription()); 785 | } 786 | 787 | renderWrappedText(sb, width, nextLineTabStop, optBuf.toString()); 788 | 789 | if (i.hasNext()) 790 | { 791 | sb.append(defaultNewLine); 792 | } 793 | } 794 | 795 | return sb; 796 | } 797 | 798 | /** 799 | * Render the specified text and return the rendered Options 800 | * in a StringBuffer. 801 | * 802 | * @param sb The StringBuffer to place the rendered text into. 803 | * @param width The number of characters to display per line 804 | * @param nextLineTabStop The position on the next line for the first tab. 805 | * @param text The text to be rendered. 806 | * 807 | * @return the StringBuffer with the rendered Options contents. 808 | */ 809 | protected StringBuffer renderWrappedText(StringBuffer sb, int width, 810 | int nextLineTabStop, String text) 811 | { 812 | int pos = findWrapPos(text, width, 0); 813 | 814 | if (pos == -1) 815 | { 816 | sb.append(rtrim(text)); 817 | 818 | return sb; 819 | } 820 | sb.append(rtrim(text.substring(0, pos))).append(defaultNewLine); 821 | 822 | if (nextLineTabStop >= width) 823 | { 824 | // stops infinite loop happening 825 | nextLineTabStop = 1; 826 | } 827 | 828 | // all following lines must be padded with nextLineTabStop space 829 | // characters 830 | final String padding = createPadding(nextLineTabStop); 831 | 832 | while (true) 833 | { 834 | text = padding + text.substring(pos).trim(); 835 | pos = findWrapPos(text, width, 0); 836 | 837 | if (pos == -1) 838 | { 839 | sb.append(text); 840 | 841 | return sb; 842 | } 843 | 844 | if ( (text.length() > width) && (pos == nextLineTabStop - 1) ) 845 | { 846 | pos = width; 847 | } 848 | 849 | sb.append(rtrim(text.substring(0, pos))).append(defaultNewLine); 850 | } 851 | } 852 | 853 | /** 854 | * Finds the next text wrap position after startPos for the 855 | * text in text with the column width width. 856 | * The wrap point is the last postion before startPos+width having a 857 | * whitespace character (space, \n, \r). 858 | * 859 | * @param text The text being searched for the wrap position 860 | * @param width width of the wrapped text 861 | * @param startPos position from which to start the lookup whitespace 862 | * character 863 | * @return postion on which the text must be wrapped or -1 if the wrap 864 | * position is at the end of the text 865 | */ 866 | protected int findWrapPos(String text, int width, int startPos) 867 | { 868 | int pos = -1; 869 | 870 | // the line ends before the max wrap pos or a new line char found 871 | if (((pos = text.indexOf('\n', startPos)) != -1 && pos <= width) 872 | || ((pos = text.indexOf('\t', startPos)) != -1 && pos <= width)) 873 | { 874 | return pos + 1; 875 | } 876 | else if (startPos + width >= text.length()) 877 | { 878 | return -1; 879 | } 880 | 881 | 882 | // look for the last whitespace character before startPos+width 883 | pos = startPos + width; 884 | 885 | char c; 886 | 887 | while ((pos >= startPos) && ((c = text.charAt(pos)) != ' ') 888 | && (c != '\n') && (c != '\r')) 889 | { 890 | --pos; 891 | } 892 | 893 | // if we found it - just return 894 | if (pos > startPos) 895 | { 896 | return pos; 897 | } 898 | 899 | // must look for the first whitespace chearacter after startPos 900 | // + width 901 | pos = startPos + width; 902 | 903 | while ((pos <= text.length()) && ((c = text.charAt(pos)) != ' ') 904 | && (c != '\n') && (c != '\r')) 905 | { 906 | ++pos; 907 | } 908 | 909 | return (pos == text.length()) ? (-1) : pos; 910 | } 911 | 912 | /** 913 | * Return a String of padding of length len. 914 | * 915 | * @param len The length of the String of padding to create. 916 | * 917 | * @return The String of padding 918 | */ 919 | protected String createPadding(int len) 920 | { 921 | StringBuffer sb = new StringBuffer(len); 922 | 923 | for (int i = 0; i < len; ++i) 924 | { 925 | sb.append(' '); 926 | } 927 | 928 | return sb.toString(); 929 | } 930 | 931 | /** 932 | * Remove the trailing whitespace from the specified String. 933 | * 934 | * @param s The String to remove the trailing padding from. 935 | * 936 | * @return The String of without the trailing padding 937 | */ 938 | protected String rtrim(String s) 939 | { 940 | if ((s == null) || (s.length() == 0)) 941 | { 942 | return s; 943 | } 944 | 945 | int pos = s.length(); 946 | 947 | while ((pos > 0) && Character.isWhitespace(s.charAt(pos - 1))) 948 | { 949 | --pos; 950 | } 951 | 952 | return s.substring(0, pos); 953 | } 954 | 955 | // ------------------------------------------------------ Package protected 956 | // ---------------------------------------------------------------- Private 957 | // ---------------------------------------------------------- Inner classes 958 | /** 959 | * This class implements the Comparator interface 960 | * for comparing Options. 961 | */ 962 | private static class OptionComparator implements Comparator 963 | { 964 | 965 | /** 966 | * Compares its two arguments for order. Returns a negative 967 | * integer, zero, or a positive integer as the first argument 968 | * is less than, equal to, or greater than the second. 969 | * 970 | * @param o1 The first Option to be compared. 971 | * @param o2 The second Option to be compared. 972 | * @return a negative integer, zero, or a positive integer as 973 | * the first argument is less than, equal to, or greater than the 974 | * second. 975 | */ 976 | public int compare(Object o1, Object o2) 977 | { 978 | Option opt1 = (Option) o1; 979 | Option opt2 = (Option) o2; 980 | 981 | return opt1.getKey().compareToIgnoreCase(opt2.getKey()); 982 | } 983 | } 984 | } 985 | -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/cli/MissingArgumentException.java: -------------------------------------------------------------------------------- 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 com.github.jobop.performance.cli; 19 | 20 | 21 | /** 22 | * Thrown when an option requiring an argument 23 | * is not provided with an argument. 24 | * 25 | * @author John Keyes (john at integralsource.com) 26 | * @version $Revision: 680644 $, $Date: 2008-07-29 01:13:48 -0700 (Tue, 29 Jul 2008) $ 27 | */ 28 | public class MissingArgumentException extends ParseException 29 | { 30 | /** The option requiring additional arguments */ 31 | private Option option; 32 | 33 | /** 34 | * Construct a new MissingArgumentException 35 | * with the specified detail message. 36 | * 37 | * @param message the detail message 38 | */ 39 | public MissingArgumentException(String message) 40 | { 41 | super(message); 42 | } 43 | 44 | /** 45 | * Construct a new MissingArgumentException 46 | * with the specified detail message. 47 | * 48 | * @param option the option requiring an argument 49 | * @since 1.2 50 | */ 51 | public MissingArgumentException(Option option) 52 | { 53 | this("Missing argument for option: " + option.getKey()); 54 | this.option = option; 55 | } 56 | 57 | /** 58 | * Return the option requiring an argument that wasn't provided 59 | * on the command line. 60 | * 61 | * @return the related option 62 | * @since 1.2 63 | */ 64 | public Option getOption() 65 | { 66 | return option; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/cli/MissingOptionException.java: -------------------------------------------------------------------------------- 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 com.github.jobop.performance.cli; 19 | 20 | import java.util.List; 21 | import java.util.Iterator; 22 | 23 | /** 24 | * Thrown when a required option has not been provided. 25 | * 26 | * @author John Keyes ( john at integralsource.com ) 27 | * @version $Revision: 680644 $, $Date: 2008-07-29 01:13:48 -0700 (Tue, 29 Jul 2008) $ 28 | */ 29 | public class MissingOptionException extends ParseException 30 | { 31 | /** The list of missing options */ 32 | private List missingOptions; 33 | 34 | /** 35 | * Construct a new MissingSelectedException 36 | * with the specified detail message. 37 | * 38 | * @param message the detail message 39 | */ 40 | public MissingOptionException(String message) 41 | { 42 | super(message); 43 | } 44 | 45 | /** 46 | * Constructs a new MissingSelectedException with the 47 | * specified list of missing options. 48 | * 49 | * @param missingOptions the list of missing options 50 | * @since 1.2 51 | */ 52 | public MissingOptionException(List missingOptions) 53 | { 54 | this(createMessage(missingOptions)); 55 | this.missingOptions = missingOptions; 56 | } 57 | 58 | /** 59 | * Return the list of options (as strings) missing in the command line parsed. 60 | * 61 | * @return the missing options 62 | * @since 1.2 63 | */ 64 | public List getMissingOptions() 65 | { 66 | return missingOptions; 67 | } 68 | 69 | /** 70 | * Build the exception message from the specified list of options. 71 | * 72 | * @param missingOptions 73 | * @since 1.2 74 | */ 75 | private static String createMessage(List missingOptions) 76 | { 77 | StringBuffer buff = new StringBuffer("Missing required option"); 78 | buff.append(missingOptions.size() == 1 ? "" : "s"); 79 | buff.append(": "); 80 | 81 | Iterator it = missingOptions.iterator(); 82 | while (it.hasNext()) 83 | { 84 | buff.append(it.next()); 85 | if (it.hasNext()) 86 | { 87 | buff.append(", "); 88 | } 89 | } 90 | 91 | return buff.toString(); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/cli/Option.java: -------------------------------------------------------------------------------- 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 com.github.jobop.performance.cli; 19 | 20 | import java.io.Serializable; 21 | import java.util.ArrayList; 22 | import java.util.List; 23 | 24 | /**

Describes a single command-line option. It maintains 25 | * information regarding the short-name of the option, the long-name, 26 | * if any exists, a flag indicating if an argument is required for 27 | * this option, and a self-documenting description of the option.

28 | * 29 | *

An Option is not created independantly, but is create through 30 | * an instance of {@link Options}.

31 | * 32 | * @see org.apache.commons.cli.Options 33 | * @see org.apache.commons.cli.CommandLine 34 | * 35 | * @author bob mcwhirter (bob @ werken.com) 36 | * @author James Strachan 37 | * @version $Revision: 680644 $, $Date: 2008-07-29 01:13:48 -0700 (Tue, 29 Jul 2008) $ 38 | */ 39 | public class Option implements Cloneable, Serializable 40 | { 41 | private static final long serialVersionUID = 1L; 42 | 43 | /** constant that specifies the number of argument values has not been specified */ 44 | public static final int UNINITIALIZED = -1; 45 | 46 | /** constant that specifies the number of argument values is infinite */ 47 | public static final int UNLIMITED_VALUES = -2; 48 | 49 | /** the name of the option */ 50 | private String opt; 51 | 52 | /** the long representation of the option */ 53 | private String longOpt; 54 | 55 | /** the name of the argument for this option */ 56 | private String argName = "arg"; 57 | 58 | /** description of the option */ 59 | private String description; 60 | 61 | /** specifies whether this option is required to be present */ 62 | private boolean required; 63 | 64 | /** specifies whether the argument value of this Option is optional */ 65 | private boolean optionalArg; 66 | 67 | /** the number of argument values this option can have */ 68 | private int numberOfArgs = UNINITIALIZED; 69 | 70 | /** the type of this Option */ 71 | private Object type; 72 | 73 | /** the list of argument values **/ 74 | private List values = new ArrayList(); 75 | 76 | /** the character that is the value separator */ 77 | private char valuesep; 78 | 79 | /** 80 | * Creates an Option using the specified parameters. 81 | * 82 | * @param opt short representation of the option 83 | * @param description describes the function of the option 84 | * 85 | * @throws IllegalArgumentException if there are any non valid 86 | * Option characters in opt. 87 | */ 88 | public Option(String opt, String description) throws IllegalArgumentException 89 | { 90 | this(opt, null, false, description); 91 | } 92 | 93 | /** 94 | * Creates an Option using the specified parameters. 95 | * 96 | * @param opt short representation of the option 97 | * @param hasArg specifies whether the Option takes an argument or not 98 | * @param description describes the function of the option 99 | * 100 | * @throws IllegalArgumentException if there are any non valid 101 | * Option characters in opt. 102 | */ 103 | public Option(String opt, boolean hasArg, String description) throws IllegalArgumentException 104 | { 105 | this(opt, null, hasArg, description); 106 | } 107 | 108 | /** 109 | * Creates an Option using the specified parameters. 110 | * 111 | * @param opt short representation of the option 112 | * @param longOpt the long representation of the option 113 | * @param hasArg specifies whether the Option takes an argument or not 114 | * @param description describes the function of the option 115 | * 116 | * @throws IllegalArgumentException if there are any non valid 117 | * Option characters in opt. 118 | */ 119 | public Option(String opt, String longOpt, boolean hasArg, String description) 120 | throws IllegalArgumentException 121 | { 122 | // ensure that the option is valid 123 | OptionValidator.validateOption(opt); 124 | 125 | this.opt = opt; 126 | this.longOpt = longOpt; 127 | 128 | // if hasArg is set then the number of arguments is 1 129 | if (hasArg) 130 | { 131 | this.numberOfArgs = 1; 132 | } 133 | 134 | this.description = description; 135 | } 136 | 137 | /** 138 | * Returns the id of this Option. This is only set when the 139 | * Option shortOpt is a single character. This is used for switch 140 | * statements. 141 | * 142 | * @return the id of this Option 143 | */ 144 | public int getId() 145 | { 146 | return getKey().charAt(0); 147 | } 148 | 149 | /** 150 | * Returns the 'unique' Option identifier. 151 | * 152 | * @return the 'unique' Option identifier 153 | */ 154 | String getKey() 155 | { 156 | // if 'opt' is null, then it is a 'long' option 157 | if (opt == null) 158 | { 159 | return longOpt; 160 | } 161 | 162 | return opt; 163 | } 164 | 165 | /** 166 | * Retrieve the name of this Option. 167 | * 168 | * It is this String which can be used with 169 | * {@link CommandLine#hasOption(String opt)} and 170 | * {@link CommandLine#getOptionValue(String opt)} to check 171 | * for existence and argument. 172 | * 173 | * @return The name of this option 174 | */ 175 | public String getOpt() 176 | { 177 | return opt; 178 | } 179 | 180 | /** 181 | * Retrieve the type of this Option. 182 | * 183 | * @return The type of this option 184 | */ 185 | public Object getType() 186 | { 187 | return type; 188 | } 189 | 190 | /** 191 | * Sets the type of this Option. 192 | * 193 | * @param type the type of this Option 194 | */ 195 | public void setType(Object type) 196 | { 197 | this.type = type; 198 | } 199 | 200 | /** 201 | * Retrieve the long name of this Option. 202 | * 203 | * @return Long name of this option, or null, if there is no long name 204 | */ 205 | public String getLongOpt() 206 | { 207 | return longOpt; 208 | } 209 | 210 | /** 211 | * Sets the long name of this Option. 212 | * 213 | * @param longOpt the long name of this Option 214 | */ 215 | public void setLongOpt(String longOpt) 216 | { 217 | this.longOpt = longOpt; 218 | } 219 | 220 | /** 221 | * Sets whether this Option can have an optional argument. 222 | * 223 | * @param optionalArg specifies whether the Option can have 224 | * an optional argument. 225 | */ 226 | public void setOptionalArg(boolean optionalArg) 227 | { 228 | this.optionalArg = optionalArg; 229 | } 230 | 231 | /** 232 | * @return whether this Option can have an optional argument 233 | */ 234 | public boolean hasOptionalArg() 235 | { 236 | return optionalArg; 237 | } 238 | 239 | /** 240 | * Query to see if this Option has a long name 241 | * 242 | * @return boolean flag indicating existence of a long name 243 | */ 244 | public boolean hasLongOpt() 245 | { 246 | return longOpt != null; 247 | } 248 | 249 | /** 250 | * Query to see if this Option requires an argument 251 | * 252 | * @return boolean flag indicating if an argument is required 253 | */ 254 | public boolean hasArg() 255 | { 256 | return numberOfArgs > 0 || numberOfArgs == UNLIMITED_VALUES; 257 | } 258 | 259 | /** 260 | * Retrieve the self-documenting description of this Option 261 | * 262 | * @return The string description of this option 263 | */ 264 | public String getDescription() 265 | { 266 | return description; 267 | } 268 | 269 | /** 270 | * Sets the self-documenting description of this Option 271 | * 272 | * @param description The description of this option 273 | * @since 1.1 274 | */ 275 | public void setDescription(String description) 276 | { 277 | this.description = description; 278 | } 279 | 280 | /** 281 | * Query to see if this Option requires an argument 282 | * 283 | * @return boolean flag indicating if an argument is required 284 | */ 285 | public boolean isRequired() 286 | { 287 | return required; 288 | } 289 | 290 | /** 291 | * Sets whether this Option is mandatory. 292 | * 293 | * @param required specifies whether this Option is mandatory 294 | */ 295 | public void setRequired(boolean required) 296 | { 297 | this.required = required; 298 | } 299 | 300 | /** 301 | * Sets the display name for the argument value. 302 | * 303 | * @param argName the display name for the argument value. 304 | */ 305 | public void setArgName(String argName) 306 | { 307 | this.argName = argName; 308 | } 309 | 310 | /** 311 | * Gets the display name for the argument value. 312 | * 313 | * @return the display name for the argument value. 314 | */ 315 | public String getArgName() 316 | { 317 | return argName; 318 | } 319 | 320 | /** 321 | * Returns whether the display name for the argument value 322 | * has been set. 323 | * 324 | * @return if the display name for the argument value has been 325 | * set. 326 | */ 327 | public boolean hasArgName() 328 | { 329 | return argName != null && argName.length() > 0; 330 | } 331 | 332 | /** 333 | * Query to see if this Option can take many values. 334 | * 335 | * @return boolean flag indicating if multiple values are allowed 336 | */ 337 | public boolean hasArgs() 338 | { 339 | return numberOfArgs > 1 || numberOfArgs == UNLIMITED_VALUES; 340 | } 341 | 342 | /** 343 | * Sets the number of argument values this Option can take. 344 | * 345 | * @param num the number of argument values 346 | */ 347 | public void setArgs(int num) 348 | { 349 | this.numberOfArgs = num; 350 | } 351 | 352 | /** 353 | * Sets the value separator. For example if the argument value 354 | * was a Java property, the value separator would be '='. 355 | * 356 | * @param sep The value separator. 357 | */ 358 | public void setValueSeparator(char sep) 359 | { 360 | this.valuesep = sep; 361 | } 362 | 363 | /** 364 | * Returns the value separator character. 365 | * 366 | * @return the value separator character. 367 | */ 368 | public char getValueSeparator() 369 | { 370 | return valuesep; 371 | } 372 | 373 | /** 374 | * Return whether this Option has specified a value separator. 375 | * 376 | * @return whether this Option has specified a value separator. 377 | * @since 1.1 378 | */ 379 | public boolean hasValueSeparator() 380 | { 381 | return valuesep > 0; 382 | } 383 | 384 | /** 385 | * Returns the number of argument values this Option can take. 386 | * 387 | * @return num the number of argument values 388 | */ 389 | public int getArgs() 390 | { 391 | return numberOfArgs; 392 | } 393 | 394 | /** 395 | * Adds the specified value to this Option. 396 | * 397 | * @param value is a/the value of this Option 398 | */ 399 | void addValueForProcessing(String value) 400 | { 401 | switch (numberOfArgs) 402 | { 403 | case UNINITIALIZED: 404 | throw new RuntimeException("NO_ARGS_ALLOWED"); 405 | 406 | default: 407 | processValue(value); 408 | } 409 | } 410 | 411 | /** 412 | * Processes the value. If this Option has a value separator 413 | * the value will have to be parsed into individual tokens. When 414 | * n-1 tokens have been processed and there are more value separators 415 | * in the value, parsing is ceased and the remaining characters are 416 | * added as a single token. 417 | * 418 | * @param value The String to be processed. 419 | * 420 | * @since 1.0.1 421 | */ 422 | private void processValue(String value) 423 | { 424 | // this Option has a separator character 425 | if (hasValueSeparator()) 426 | { 427 | // get the separator character 428 | char sep = getValueSeparator(); 429 | 430 | // store the index for the value separator 431 | int index = value.indexOf(sep); 432 | 433 | // while there are more value separators 434 | while (index != -1) 435 | { 436 | // next value to be added 437 | if (values.size() == (numberOfArgs - 1)) 438 | { 439 | break; 440 | } 441 | 442 | // store 443 | add(value.substring(0, index)); 444 | 445 | // parse 446 | value = value.substring(index + 1); 447 | 448 | // get new index 449 | index = value.indexOf(sep); 450 | } 451 | } 452 | 453 | // store the actual value or the last value that has been parsed 454 | add(value); 455 | } 456 | 457 | /** 458 | * Add the value to this Option. If the number of arguments 459 | * is greater than zero and there is enough space in the list then 460 | * add the value. Otherwise, throw a runtime exception. 461 | * 462 | * @param value The value to be added to this Option 463 | * 464 | * @since 1.0.1 465 | */ 466 | private void add(String value) 467 | { 468 | if ((numberOfArgs > 0) && (values.size() > (numberOfArgs - 1))) 469 | { 470 | throw new RuntimeException("Cannot add value, list full."); 471 | } 472 | 473 | // store value 474 | values.add(value); 475 | } 476 | 477 | /** 478 | * Returns the specified value of this Option or 479 | * null if there is no value. 480 | * 481 | * @return the value/first value of this Option or 482 | * null if there is no value. 483 | */ 484 | public String getValue() 485 | { 486 | return hasNoValues() ? null : (String) values.get(0); 487 | } 488 | 489 | /** 490 | * Returns the specified value of this Option or 491 | * null if there is no value. 492 | * 493 | * @param index The index of the value to be returned. 494 | * 495 | * @return the specified value of this Option or 496 | * null if there is no value. 497 | * 498 | * @throws IndexOutOfBoundsException if index is less than 1 499 | * or greater than the number of the values for this Option. 500 | */ 501 | public String getValue(int index) throws IndexOutOfBoundsException 502 | { 503 | return hasNoValues() ? null : (String) values.get(index); 504 | } 505 | 506 | /** 507 | * Returns the value/first value of this Option or the 508 | * defaultValue if there is no value. 509 | * 510 | * @param defaultValue The value to be returned if ther 511 | * is no value. 512 | * 513 | * @return the value/first value of this Option or the 514 | * defaultValue if there are no values. 515 | */ 516 | public String getValue(String defaultValue) 517 | { 518 | String value = getValue(); 519 | 520 | return (value != null) ? value : defaultValue; 521 | } 522 | 523 | /** 524 | * Return the values of this Option as a String array 525 | * or null if there are no values 526 | * 527 | * @return the values of this Option as a String array 528 | * or null if there are no values 529 | */ 530 | public String[] getValues() 531 | { 532 | return hasNoValues() ? null : (String[]) values.toArray(new String[values.size()]); 533 | } 534 | 535 | /** 536 | * @return the values of this Option as a List 537 | * or null if there are no values 538 | */ 539 | public List getValuesList() 540 | { 541 | return values; 542 | } 543 | 544 | /** 545 | * Dump state, suitable for debugging. 546 | * 547 | * @return Stringified form of this object 548 | */ 549 | public String toString() 550 | { 551 | StringBuffer buf = new StringBuffer().append("[ option: "); 552 | 553 | buf.append(opt); 554 | 555 | if (longOpt != null) 556 | { 557 | buf.append(" ").append(longOpt); 558 | } 559 | 560 | buf.append(" "); 561 | 562 | if (hasArgs()) 563 | { 564 | buf.append("[ARG...]"); 565 | } 566 | else if (hasArg()) 567 | { 568 | buf.append(" [ARG]"); 569 | } 570 | 571 | buf.append(" :: ").append(description); 572 | 573 | if (type != null) 574 | { 575 | buf.append(" :: ").append(type); 576 | } 577 | 578 | buf.append(" ]"); 579 | 580 | return buf.toString(); 581 | } 582 | 583 | /** 584 | * Returns whether this Option has any values. 585 | * 586 | * @return whether this Option has any values. 587 | */ 588 | private boolean hasNoValues() 589 | { 590 | return values.isEmpty(); 591 | } 592 | 593 | public boolean equals(Object o) 594 | { 595 | if (this == o) 596 | { 597 | return true; 598 | } 599 | if (o == null || getClass() != o.getClass()) 600 | { 601 | return false; 602 | } 603 | 604 | Option option = (Option) o; 605 | 606 | 607 | if (opt != null ? !opt.equals(option.opt) : option.opt != null) 608 | { 609 | return false; 610 | } 611 | if (longOpt != null ? !longOpt.equals(option.longOpt) : option.longOpt != null) 612 | { 613 | return false; 614 | } 615 | 616 | return true; 617 | } 618 | 619 | public int hashCode() 620 | { 621 | int result; 622 | result = (opt != null ? opt.hashCode() : 0); 623 | result = 31 * result + (longOpt != null ? longOpt.hashCode() : 0); 624 | return result; 625 | } 626 | 627 | /** 628 | * A rather odd clone method - due to incorrect code in 1.0 it is public 629 | * and in 1.1 rather than throwing a CloneNotSupportedException it throws 630 | * a RuntimeException so as to maintain backwards compat at the API level. 631 | * 632 | * After calling this method, it is very likely you will want to call 633 | * clearValues(). 634 | * 635 | * @throws RuntimeException 636 | */ 637 | public Object clone() 638 | { 639 | try 640 | { 641 | Option option = (Option) super.clone(); 642 | option.values = new ArrayList(values); 643 | return option; 644 | } 645 | catch (CloneNotSupportedException cnse) 646 | { 647 | throw new RuntimeException("A CloneNotSupportedException was thrown: " + cnse.getMessage()); 648 | } 649 | } 650 | 651 | /** 652 | * Clear the Option values. After a parse is complete, these are left with 653 | * data in them and they need clearing if another parse is done. 654 | * 655 | * See: CLI-71 656 | */ 657 | void clearValues() 658 | { 659 | values.clear(); 660 | } 661 | 662 | /** 663 | * This method is not intended to be used. It was a piece of internal 664 | * API that was made public in 1.0. It currently throws an UnsupportedOperationException. 665 | * @deprecated 666 | * @throws UnsupportedOperationException 667 | */ 668 | public boolean addValue(String value) 669 | { 670 | throw new UnsupportedOperationException("The addValue method is not intended for client use. " 671 | + "Subclasses should use the addValueForProcessing method instead. "); 672 | } 673 | 674 | } 675 | -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/cli/OptionBuilder.java: -------------------------------------------------------------------------------- 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 com.github.jobop.performance.cli; 19 | 20 | 21 | /** 22 | * OptionBuilder allows the user to create Options using descriptive methods. 23 | * 24 | *

Details on the Builder pattern can be found at 25 | * 26 | * http://c2.com/cgi-bin/wiki?BuilderPattern.

27 | * 28 | * @author John Keyes (john at integralsource.com) 29 | * @version $Revision: 754830 $, $Date: 2009-03-16 00:26:44 -0700 (Mon, 16 Mar 2009) $ 30 | * @since 1.0 31 | */ 32 | public final class OptionBuilder 33 | { 34 | /** long option */ 35 | private static String longopt; 36 | 37 | /** option description */ 38 | private static String description; 39 | 40 | /** argument name */ 41 | private static String argName; 42 | 43 | /** is required? */ 44 | private static boolean required; 45 | 46 | /** the number of arguments */ 47 | private static int numberOfArgs = Option.UNINITIALIZED; 48 | 49 | /** option type */ 50 | private static Object type; 51 | 52 | /** option can have an optional argument value */ 53 | private static boolean optionalArg; 54 | 55 | /** value separator for argument value */ 56 | private static char valuesep; 57 | 58 | /** option builder instance */ 59 | private static OptionBuilder instance = new OptionBuilder(); 60 | 61 | /** 62 | * private constructor to prevent instances being created 63 | */ 64 | private OptionBuilder() 65 | { 66 | // hide the constructor 67 | } 68 | 69 | /** 70 | * Resets the member variables to their default values. 71 | */ 72 | private static void reset() 73 | { 74 | description = null; 75 | argName = "arg"; 76 | longopt = null; 77 | type = null; 78 | required = false; 79 | numberOfArgs = Option.UNINITIALIZED; 80 | 81 | 82 | // PMM 9/6/02 - these were missing 83 | optionalArg = false; 84 | valuesep = (char) 0; 85 | } 86 | 87 | /** 88 | * The next Option created will have the following long option value. 89 | * 90 | * @param newLongopt the long option value 91 | * @return the OptionBuilder instance 92 | */ 93 | public static OptionBuilder withLongOpt(String newLongopt) 94 | { 95 | OptionBuilder.longopt = newLongopt; 96 | 97 | return instance; 98 | } 99 | 100 | /** 101 | * The next Option created will require an argument value. 102 | * 103 | * @return the OptionBuilder instance 104 | */ 105 | public static OptionBuilder hasArg() 106 | { 107 | OptionBuilder.numberOfArgs = 1; 108 | 109 | return instance; 110 | } 111 | 112 | /** 113 | * The next Option created will require an argument value if 114 | * hasArg is true. 115 | * 116 | * @param hasArg if true then the Option has an argument value 117 | * @return the OptionBuilder instance 118 | */ 119 | public static OptionBuilder hasArg(boolean hasArg) 120 | { 121 | OptionBuilder.numberOfArgs = hasArg ? 1 : Option.UNINITIALIZED; 122 | 123 | return instance; 124 | } 125 | 126 | /** 127 | * The next Option created will have the specified argument value name. 128 | * 129 | * @param name the name for the argument value 130 | * @return the OptionBuilder instance 131 | */ 132 | public static OptionBuilder withArgName(String name) 133 | { 134 | OptionBuilder.argName = name; 135 | 136 | return instance; 137 | } 138 | 139 | /** 140 | * The next Option created will be required. 141 | * 142 | * @return the OptionBuilder instance 143 | */ 144 | public static OptionBuilder isRequired() 145 | { 146 | OptionBuilder.required = true; 147 | 148 | return instance; 149 | } 150 | 151 | /** 152 | * The next Option created uses sep as a means to 153 | * separate argument values. 154 | * 155 | * Example: 156 | *
157 |      * Option opt = OptionBuilder.withValueSeparator(':')
158 |      *                           .create('D');
159 |      *
160 |      * CommandLine line = parser.parse(args);
161 |      * String propertyName = opt.getValue(0);
162 |      * String propertyValue = opt.getValue(1);
163 |      * 
164 | * 165 | * @param sep The value separator to be used for the argument values. 166 | * 167 | * @return the OptionBuilder instance 168 | */ 169 | public static OptionBuilder withValueSeparator(char sep) 170 | { 171 | OptionBuilder.valuesep = sep; 172 | 173 | return instance; 174 | } 175 | 176 | /** 177 | * The next Option created uses '=' as a means to 178 | * separate argument values. 179 | * 180 | * Example: 181 | *
182 |      * Option opt = OptionBuilder.withValueSeparator()
183 |      *                           .create('D');
184 |      *
185 |      * CommandLine line = parser.parse(args);
186 |      * String propertyName = opt.getValue(0);
187 |      * String propertyValue = opt.getValue(1);
188 |      * 
189 | * 190 | * @return the OptionBuilder instance 191 | */ 192 | public static OptionBuilder withValueSeparator() 193 | { 194 | OptionBuilder.valuesep = '='; 195 | 196 | return instance; 197 | } 198 | 199 | /** 200 | * The next Option created will be required if required 201 | * is true. 202 | * 203 | * @param newRequired if true then the Option is required 204 | * @return the OptionBuilder instance 205 | */ 206 | public static OptionBuilder isRequired(boolean newRequired) 207 | { 208 | OptionBuilder.required = newRequired; 209 | 210 | return instance; 211 | } 212 | 213 | /** 214 | * The next Option created can have unlimited argument values. 215 | * 216 | * @return the OptionBuilder instance 217 | */ 218 | public static OptionBuilder hasArgs() 219 | { 220 | OptionBuilder.numberOfArgs = Option.UNLIMITED_VALUES; 221 | 222 | return instance; 223 | } 224 | 225 | /** 226 | * The next Option created can have num argument values. 227 | * 228 | * @param num the number of args that the option can have 229 | * @return the OptionBuilder instance 230 | */ 231 | public static OptionBuilder hasArgs(int num) 232 | { 233 | OptionBuilder.numberOfArgs = num; 234 | 235 | return instance; 236 | } 237 | 238 | /** 239 | * The next Option can have an optional argument. 240 | * 241 | * @return the OptionBuilder instance 242 | */ 243 | public static OptionBuilder hasOptionalArg() 244 | { 245 | OptionBuilder.numberOfArgs = 1; 246 | OptionBuilder.optionalArg = true; 247 | 248 | return instance; 249 | } 250 | 251 | /** 252 | * The next Option can have an unlimited number of optional arguments. 253 | * 254 | * @return the OptionBuilder instance 255 | */ 256 | public static OptionBuilder hasOptionalArgs() 257 | { 258 | OptionBuilder.numberOfArgs = Option.UNLIMITED_VALUES; 259 | OptionBuilder.optionalArg = true; 260 | 261 | return instance; 262 | } 263 | 264 | /** 265 | * The next Option can have the specified number of optional arguments. 266 | * 267 | * @param numArgs - the maximum number of optional arguments 268 | * the next Option created can have. 269 | * @return the OptionBuilder instance 270 | */ 271 | public static OptionBuilder hasOptionalArgs(int numArgs) 272 | { 273 | OptionBuilder.numberOfArgs = numArgs; 274 | OptionBuilder.optionalArg = true; 275 | 276 | return instance; 277 | } 278 | 279 | /** 280 | * The next Option created will have a value that will be an instance 281 | * of type. 282 | * 283 | * @param newType the type of the Options argument value 284 | * @return the OptionBuilder instance 285 | */ 286 | public static OptionBuilder withType(Object newType) 287 | { 288 | OptionBuilder.type = newType; 289 | 290 | return instance; 291 | } 292 | 293 | /** 294 | * The next Option created will have the specified description 295 | * 296 | * @param newDescription a description of the Option's purpose 297 | * @return the OptionBuilder instance 298 | */ 299 | public static OptionBuilder withDescription(String newDescription) 300 | { 301 | OptionBuilder.description = newDescription; 302 | 303 | return instance; 304 | } 305 | 306 | /** 307 | * Create an Option using the current settings and with 308 | * the specified Option char. 309 | * 310 | * @param opt the character representation of the Option 311 | * @return the Option instance 312 | * @throws IllegalArgumentException if opt is not 313 | * a valid character. See Option. 314 | */ 315 | public static Option create(char opt) throws IllegalArgumentException 316 | { 317 | return create(String.valueOf(opt)); 318 | } 319 | 320 | /** 321 | * Create an Option using the current settings 322 | * 323 | * @return the Option instance 324 | * @throws IllegalArgumentException if longOpt has not been set. 325 | */ 326 | public static Option create() throws IllegalArgumentException 327 | { 328 | if (longopt == null) 329 | { 330 | OptionBuilder.reset(); 331 | throw new IllegalArgumentException("must specify longopt"); 332 | } 333 | 334 | return create(null); 335 | } 336 | 337 | /** 338 | * Create an Option using the current settings and with 339 | * the specified Option char. 340 | * 341 | * @param opt the java.lang.String representation 342 | * of the Option 343 | * @return the Option instance 344 | * @throws IllegalArgumentException if opt is not 345 | * a valid character. See Option. 346 | */ 347 | public static Option create(String opt) throws IllegalArgumentException 348 | { 349 | Option option = null; 350 | try { 351 | // create the option 352 | option = new Option(opt, description); 353 | 354 | // set the option properties 355 | option.setLongOpt(longopt); 356 | option.setRequired(required); 357 | option.setOptionalArg(optionalArg); 358 | option.setArgs(numberOfArgs); 359 | option.setType(type); 360 | option.setValueSeparator(valuesep); 361 | option.setArgName(argName); 362 | } finally { 363 | // reset the OptionBuilder properties 364 | OptionBuilder.reset(); 365 | } 366 | 367 | // return the Option instance 368 | return option; 369 | } 370 | } 371 | -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/cli/OptionGroup.java: -------------------------------------------------------------------------------- 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 com.github.jobop.performance.cli; 19 | 20 | import java.io.Serializable; 21 | import java.util.Collection; 22 | import java.util.HashMap; 23 | import java.util.Iterator; 24 | import java.util.Map; 25 | 26 | /** 27 | * A group of mutually exclusive options. 28 | * 29 | * @author John Keyes ( john at integralsource.com ) 30 | * @version $Revision: 680644 $, $Date: 2008-07-29 01:13:48 -0700 (Tue, 29 Jul 2008) $ 31 | */ 32 | public class OptionGroup implements Serializable 33 | { 34 | private static final long serialVersionUID = 1L; 35 | 36 | /** hold the options */ 37 | private Map optionMap = new HashMap(); 38 | 39 | /** the name of the selected option */ 40 | private String selected; 41 | 42 | /** specified whether this group is required */ 43 | private boolean required; 44 | 45 | /** 46 | * Add the specified Option to this group. 47 | * 48 | * @param option the option to add to this group 49 | * @return this option group with the option added 50 | */ 51 | public OptionGroup addOption(Option option) 52 | { 53 | // key - option name 54 | // value - the option 55 | optionMap.put(option.getKey(), option); 56 | 57 | return this; 58 | } 59 | 60 | /** 61 | * @return the names of the options in this group as a 62 | * Collection 63 | */ 64 | public Collection getNames() 65 | { 66 | // the key set is the collection of names 67 | return optionMap.keySet(); 68 | } 69 | 70 | /** 71 | * @return the options in this group as a Collection 72 | */ 73 | public Collection getOptions() 74 | { 75 | // the values are the collection of options 76 | return optionMap.values(); 77 | } 78 | 79 | /** 80 | * Set the selected option of this group to name. 81 | * 82 | * @param option the option that is selected 83 | * @throws AlreadySelectedException if an option from this group has 84 | * already been selected. 85 | */ 86 | public void setSelected(Option option) throws AlreadySelectedException 87 | { 88 | // if no option has already been selected or the 89 | // same option is being reselected then set the 90 | // selected member variable 91 | if (selected == null || selected.equals(option.getOpt())) 92 | { 93 | selected = option.getOpt(); 94 | } 95 | else 96 | { 97 | throw new AlreadySelectedException(this, option); 98 | } 99 | } 100 | 101 | /** 102 | * @return the selected option name 103 | */ 104 | public String getSelected() 105 | { 106 | return selected; 107 | } 108 | 109 | /** 110 | * @param required specifies if this group is required 111 | */ 112 | public void setRequired(boolean required) 113 | { 114 | this.required = required; 115 | } 116 | 117 | /** 118 | * Returns whether this option group is required. 119 | * 120 | * @return whether this option group is required 121 | */ 122 | public boolean isRequired() 123 | { 124 | return required; 125 | } 126 | 127 | /** 128 | * Returns the stringified version of this OptionGroup. 129 | * 130 | * @return the stringified representation of this group 131 | */ 132 | public String toString() 133 | { 134 | StringBuffer buff = new StringBuffer(); 135 | 136 | Iterator iter = getOptions().iterator(); 137 | 138 | buff.append("["); 139 | 140 | while (iter.hasNext()) 141 | { 142 | Option option = (Option) iter.next(); 143 | 144 | if (option.getOpt() != null) 145 | { 146 | buff.append("-"); 147 | buff.append(option.getOpt()); 148 | } 149 | else 150 | { 151 | buff.append("--"); 152 | buff.append(option.getLongOpt()); 153 | } 154 | 155 | buff.append(" "); 156 | buff.append(option.getDescription()); 157 | 158 | if (iter.hasNext()) 159 | { 160 | buff.append(", "); 161 | } 162 | } 163 | 164 | buff.append("]"); 165 | 166 | return buff.toString(); 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/cli/OptionValidator.java: -------------------------------------------------------------------------------- 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 com.github.jobop.performance.cli; 19 | 20 | /** 21 | * Validates an Option string. 22 | * 23 | * @author John Keyes ( john at integralsource.com ) 24 | * @version $Revision: 680644 $, $Date: 2008-07-29 01:13:48 -0700 (Tue, 29 Jul 2008) $ 25 | * @since 1.1 26 | */ 27 | class OptionValidator 28 | { 29 | /** 30 | * Validates whether opt is a permissable Option 31 | * shortOpt. The rules that specify if the opt 32 | * is valid are: 33 | * 34 | * 41 | * 42 | * @param opt The option string to validate 43 | * @throws IllegalArgumentException if the Option is not valid. 44 | */ 45 | static void validateOption(String opt) throws IllegalArgumentException 46 | { 47 | // check that opt is not NULL 48 | if (opt == null) 49 | { 50 | return; 51 | } 52 | 53 | // handle the single character opt 54 | else if (opt.length() == 1) 55 | { 56 | char ch = opt.charAt(0); 57 | 58 | if (!isValidOpt(ch)) 59 | { 60 | throw new IllegalArgumentException("illegal option value '" + ch + "'"); 61 | } 62 | } 63 | 64 | // handle the multi character opt 65 | else 66 | { 67 | char[] chars = opt.toCharArray(); 68 | 69 | for (int i = 0; i < chars.length; i++) 70 | { 71 | if (!isValidChar(chars[i])) 72 | { 73 | throw new IllegalArgumentException("opt contains illegal character value '" + chars[i] + "'"); 74 | } 75 | } 76 | } 77 | } 78 | 79 | /** 80 | * Returns whether the specified character is a valid Option. 81 | * 82 | * @param c the option to validate 83 | * @return true if c is a letter, ' ', '?' or '@', 84 | * otherwise false. 85 | */ 86 | private static boolean isValidOpt(char c) 87 | { 88 | return isValidChar(c) || c == ' ' || c == '?' || c == '@'; 89 | } 90 | 91 | /** 92 | * Returns whether the specified character is a valid character. 93 | * 94 | * @param c the character to validate 95 | * @return true if c is a letter. 96 | */ 97 | private static boolean isValidChar(char c) 98 | { 99 | return Character.isJavaIdentifierPart(c); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/cli/Options.java: -------------------------------------------------------------------------------- 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 com.github.jobop.performance.cli; 19 | 20 | import java.io.Serializable; 21 | import java.util.ArrayList; 22 | import java.util.Collection; 23 | import java.util.Collections; 24 | import java.util.HashMap; 25 | import java.util.HashSet; 26 | import java.util.Iterator; 27 | import java.util.List; 28 | import java.util.Map; 29 | 30 | /** 31 | *

Main entry-point into the library.

32 | * 33 | *

Options represents a collection of {@link Option} objects, which 34 | * describe the possible options for a command-line.

35 | * 36 | *

It may flexibly parse long and short options, with or without 37 | * values. Additionally, it may parse only a portion of a commandline, 38 | * allowing for flexible multi-stage parsing.

39 | * 40 | * @see org.apache.commons.cli.CommandLine 41 | * 42 | * @author bob mcwhirter (bob @ werken.com) 43 | * @author James Strachan 44 | * @version $Revision: 680644 $, $Date: 2008-07-29 01:13:48 -0700 (Tue, 29 Jul 2008) $ 45 | */ 46 | public class Options implements Serializable 47 | { 48 | private static final long serialVersionUID = 1L; 49 | 50 | /** a map of the options with the character key */ 51 | private Map shortOpts = new HashMap(); 52 | 53 | /** a map of the options with the long key */ 54 | private Map longOpts = new HashMap(); 55 | 56 | /** a map of the required options */ 57 | private List requiredOpts = new ArrayList(); 58 | 59 | /** a map of the option groups */ 60 | private Map optionGroups = new HashMap(); 61 | 62 | /** 63 | * Add the specified option group. 64 | * 65 | * @param group the OptionGroup that is to be added 66 | * @return the resulting Options instance 67 | */ 68 | public Options addOptionGroup(OptionGroup group) 69 | { 70 | Iterator options = group.getOptions().iterator(); 71 | 72 | if (group.isRequired()) 73 | { 74 | requiredOpts.add(group); 75 | } 76 | 77 | while (options.hasNext()) 78 | { 79 | Option option = (Option) options.next(); 80 | 81 | // an Option cannot be required if it is in an 82 | // OptionGroup, either the group is required or 83 | // nothing is required 84 | option.setRequired(false); 85 | addOption(option); 86 | 87 | optionGroups.put(option.getKey(), group); 88 | } 89 | 90 | return this; 91 | } 92 | 93 | /** 94 | * Lists the OptionGroups that are members of this Options instance. 95 | * 96 | * @return a Collection of OptionGroup instances. 97 | */ 98 | Collection getOptionGroups() 99 | { 100 | return new HashSet(optionGroups.values()); 101 | } 102 | 103 | /** 104 | * Add an option that only contains a short-name. 105 | * It may be specified as requiring an argument. 106 | * 107 | * @param opt Short single-character name of the option. 108 | * @param hasArg flag signally if an argument is required after this option 109 | * @param description Self-documenting description 110 | * @return the resulting Options instance 111 | */ 112 | public Options addOption(String opt, boolean hasArg, String description) 113 | { 114 | addOption(opt, null, hasArg, description); 115 | 116 | return this; 117 | } 118 | 119 | /** 120 | * Add an option that contains a short-name and a long-name. 121 | * It may be specified as requiring an argument. 122 | * 123 | * @param opt Short single-character name of the option. 124 | * @param longOpt Long multi-character name of the option. 125 | * @param hasArg flag signally if an argument is required after this option 126 | * @param description Self-documenting description 127 | * @return the resulting Options instance 128 | */ 129 | public Options addOption(String opt, String longOpt, boolean hasArg, String description) 130 | { 131 | addOption(new Option(opt, longOpt, hasArg, description)); 132 | 133 | return this; 134 | } 135 | 136 | /** 137 | * Adds an option instance 138 | * 139 | * @param opt the option that is to be added 140 | * @return the resulting Options instance 141 | */ 142 | public Options addOption(Option opt) 143 | { 144 | String key = opt.getKey(); 145 | 146 | // add it to the long option list 147 | if (opt.hasLongOpt()) 148 | { 149 | longOpts.put(opt.getLongOpt(), opt); 150 | } 151 | 152 | // if the option is required add it to the required list 153 | if (opt.isRequired()) 154 | { 155 | if (requiredOpts.contains(key)) 156 | { 157 | requiredOpts.remove(requiredOpts.indexOf(key)); 158 | } 159 | requiredOpts.add(key); 160 | } 161 | 162 | shortOpts.put(key, opt); 163 | 164 | return this; 165 | } 166 | 167 | /** 168 | * Retrieve a read-only list of options in this set 169 | * 170 | * @return read-only Collection of {@link Option} objects in this descriptor 171 | */ 172 | public Collection getOptions() 173 | { 174 | return Collections.unmodifiableCollection(helpOptions()); 175 | } 176 | 177 | /** 178 | * Returns the Options for use by the HelpFormatter. 179 | * 180 | * @return the List of Options 181 | */ 182 | List helpOptions() 183 | { 184 | return new ArrayList(shortOpts.values()); 185 | } 186 | 187 | /** 188 | * Returns the required options. 189 | * 190 | * @return List of required options 191 | */ 192 | public List getRequiredOptions() 193 | { 194 | return requiredOpts; 195 | } 196 | 197 | /** 198 | * Retrieve the {@link Option} matching the long or short name specified. 199 | * The leading hyphens in the name are ignored (up to 2). 200 | * 201 | * @param opt short or long name of the {@link Option} 202 | * @return the option represented by opt 203 | */ 204 | public Option getOption(String opt) 205 | { 206 | opt = Util.stripLeadingHyphens(opt); 207 | 208 | if (shortOpts.containsKey(opt)) 209 | { 210 | return (Option) shortOpts.get(opt); 211 | } 212 | 213 | return (Option) longOpts.get(opt); 214 | } 215 | 216 | /** 217 | * Returns whether the named {@link Option} is a member of this {@link Options}. 218 | * 219 | * @param opt short or long name of the {@link Option} 220 | * @return true if the named {@link Option} is a member 221 | * of this {@link Options} 222 | */ 223 | public boolean hasOption(String opt) 224 | { 225 | opt = Util.stripLeadingHyphens(opt); 226 | 227 | return shortOpts.containsKey(opt) || longOpts.containsKey(opt); 228 | } 229 | 230 | /** 231 | * Returns the OptionGroup the opt belongs to. 232 | * @param opt the option whose OptionGroup is being queried. 233 | * 234 | * @return the OptionGroup if opt is part 235 | * of an OptionGroup, otherwise return null 236 | */ 237 | public OptionGroup getOptionGroup(Option opt) 238 | { 239 | return (OptionGroup) optionGroups.get(opt.getKey()); 240 | } 241 | 242 | /** 243 | * Dump state, suitable for debugging. 244 | * 245 | * @return Stringified form of this object 246 | */ 247 | public String toString() 248 | { 249 | StringBuffer buf = new StringBuffer(); 250 | 251 | buf.append("[ Options: [ short "); 252 | buf.append(shortOpts.toString()); 253 | buf.append(" ] [ long "); 254 | buf.append(longOpts); 255 | buf.append(" ]"); 256 | 257 | return buf.toString(); 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/cli/ParseException.java: -------------------------------------------------------------------------------- 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 com.github.jobop.performance.cli; 19 | 20 | /** 21 | * Base for Exceptions thrown during parsing of a command-line. 22 | * 23 | * @author bob mcwhirter (bob @ werken.com) 24 | * @version $Revision: 680644 $, $Date: 2008-07-29 01:13:48 -0700 (Tue, 29 Jul 2008) $ 25 | */ 26 | public class ParseException extends Exception 27 | { 28 | /** 29 | * Construct a new ParseException 30 | * with the specified detail message. 31 | * 32 | * @param message the detail message 33 | */ 34 | public ParseException(String message) 35 | { 36 | super(message); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/cli/Parser.java: -------------------------------------------------------------------------------- 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 com.github.jobop.performance.cli; 19 | 20 | import java.util.ArrayList; 21 | import java.util.Arrays; 22 | import java.util.Enumeration; 23 | import java.util.Iterator; 24 | import java.util.List; 25 | import java.util.ListIterator; 26 | import java.util.Properties; 27 | 28 | /** 29 | * Parser creates {@link CommandLine}s. 30 | * 31 | * @author John Keyes (john at integralsource.com) 32 | * @version $Revision: 680644 $, $Date: 2008-07-29 01:13:48 -0700 (Tue, 29 Jul 2008) $ 33 | */ 34 | public abstract class Parser implements CommandLineParser 35 | { 36 | /** commandline instance */ 37 | protected CommandLine cmd; 38 | 39 | /** current Options */ 40 | private Options options; 41 | 42 | /** list of required options strings */ 43 | private List requiredOptions; 44 | 45 | protected void setOptions(final Options options) 46 | { 47 | this.options = options; 48 | this.requiredOptions = new ArrayList(options.getRequiredOptions()); 49 | } 50 | 51 | protected Options getOptions() 52 | { 53 | return options; 54 | } 55 | 56 | protected List getRequiredOptions() 57 | { 58 | return requiredOptions; 59 | } 60 | 61 | /** 62 | * Subclasses must implement this method to reduce 63 | * the arguments that have been passed to the parse method. 64 | * 65 | * @param opts The Options to parse the arguments by. 66 | * @param arguments The arguments that have to be flattened. 67 | * @param stopAtNonOption specifies whether to stop 68 | * flattening when a non option has been encountered 69 | * @return a String array of the flattened arguments 70 | */ 71 | protected abstract String[] flatten(Options opts, String[] arguments, boolean stopAtNonOption); 72 | 73 | /** 74 | * Parses the specified arguments based 75 | * on the specifed {@link Options}. 76 | * 77 | * @param options the Options 78 | * @param arguments the arguments 79 | * @return the CommandLine 80 | * @throws ParseException if an error occurs when parsing the 81 | * arguments. 82 | */ 83 | public CommandLine parse(Options options, String[] arguments) throws ParseException 84 | { 85 | return parse(options, arguments, null, false); 86 | } 87 | 88 | /** 89 | * Parse the arguments according to the specified options and properties. 90 | * 91 | * @param options the specified Options 92 | * @param arguments the command line arguments 93 | * @param properties command line option name-value pairs 94 | * @return the list of atomic option and value tokens 95 | * @throws ParseException if there are any problems encountered 96 | * while parsing the command line tokens. 97 | * 98 | * @since 1.1 99 | */ 100 | public CommandLine parse(Options options, String[] arguments, Properties properties) throws ParseException 101 | { 102 | return parse(options, arguments, properties, false); 103 | } 104 | 105 | /** 106 | * Parses the specified arguments 107 | * based on the specifed {@link Options}. 108 | * 109 | * @param options the Options 110 | * @param arguments the arguments 111 | * @param stopAtNonOption specifies whether to stop interpreting the 112 | * arguments when a non option has been encountered 113 | * and to add them to the CommandLines args list. 114 | * @return the CommandLine 115 | * @throws ParseException if an error occurs when parsing the arguments. 116 | */ 117 | public CommandLine parse(Options options, String[] arguments, boolean stopAtNonOption) throws ParseException 118 | { 119 | return parse(options, arguments, null, stopAtNonOption); 120 | } 121 | 122 | /** 123 | * Parse the arguments according to the specified options and 124 | * properties. 125 | * 126 | * @param options the specified Options 127 | * @param arguments the command line arguments 128 | * @param properties command line option name-value pairs 129 | * @param stopAtNonOption stop parsing the arguments when the first 130 | * non option is encountered. 131 | * 132 | * @return the list of atomic option and value tokens 133 | * 134 | * @throws ParseException if there are any problems encountered 135 | * while parsing the command line tokens. 136 | * 137 | * @since 1.1 138 | */ 139 | public CommandLine parse(Options options, String[] arguments, Properties properties, boolean stopAtNonOption) 140 | throws ParseException 141 | { 142 | // clear out the data in options in case it's been used before (CLI-71) 143 | for (Iterator it = options.helpOptions().iterator(); it.hasNext();) 144 | { 145 | Option opt = (Option) it.next(); 146 | opt.clearValues(); 147 | } 148 | 149 | // initialise members 150 | setOptions(options); 151 | 152 | cmd = new CommandLine(); 153 | 154 | boolean eatTheRest = false; 155 | 156 | if (arguments == null) 157 | { 158 | arguments = new String[0]; 159 | } 160 | 161 | List tokenList = Arrays.asList(flatten(getOptions(), arguments, stopAtNonOption)); 162 | 163 | ListIterator iterator = tokenList.listIterator(); 164 | 165 | // process each flattened token 166 | while (iterator.hasNext()) 167 | { 168 | String t = (String) iterator.next(); 169 | 170 | // the value is the double-dash 171 | if ("--".equals(t)) 172 | { 173 | eatTheRest = true; 174 | } 175 | 176 | // the value is a single dash 177 | else if ("-".equals(t)) 178 | { 179 | if (stopAtNonOption) 180 | { 181 | eatTheRest = true; 182 | } 183 | else 184 | { 185 | cmd.addArg(t); 186 | } 187 | } 188 | 189 | // the value is an option 190 | else if (t.startsWith("-")) 191 | { 192 | if (stopAtNonOption && !getOptions().hasOption(t)) 193 | { 194 | eatTheRest = true; 195 | cmd.addArg(t); 196 | } 197 | else 198 | { 199 | processOption(t, iterator); 200 | } 201 | } 202 | 203 | // the value is an argument 204 | else 205 | { 206 | cmd.addArg(t); 207 | 208 | if (stopAtNonOption) 209 | { 210 | eatTheRest = true; 211 | } 212 | } 213 | 214 | // eat the remaining tokens 215 | if (eatTheRest) 216 | { 217 | while (iterator.hasNext()) 218 | { 219 | String str = (String) iterator.next(); 220 | 221 | // ensure only one double-dash is added 222 | if (!"--".equals(str)) 223 | { 224 | cmd.addArg(str); 225 | } 226 | } 227 | } 228 | } 229 | 230 | processProperties(properties); 231 | checkRequiredOptions(); 232 | 233 | return cmd; 234 | } 235 | 236 | /** 237 | * Sets the values of Options using the values in properties. 238 | * 239 | * @param properties The value properties to be processed. 240 | */ 241 | protected void processProperties(Properties properties) 242 | { 243 | if (properties == null) 244 | { 245 | return; 246 | } 247 | 248 | for (Enumeration e = properties.propertyNames(); e.hasMoreElements();) 249 | { 250 | String option = e.nextElement().toString(); 251 | 252 | if (!cmd.hasOption(option)) 253 | { 254 | Option opt = getOptions().getOption(option); 255 | 256 | // get the value from the properties instance 257 | String value = properties.getProperty(option); 258 | 259 | if (opt.hasArg()) 260 | { 261 | if (opt.getValues() == null || opt.getValues().length == 0) 262 | { 263 | try 264 | { 265 | opt.addValueForProcessing(value); 266 | } 267 | catch (RuntimeException exp) 268 | { 269 | // if we cannot add the value don't worry about it 270 | } 271 | } 272 | } 273 | else if (!("yes".equalsIgnoreCase(value) 274 | || "true".equalsIgnoreCase(value) 275 | || "1".equalsIgnoreCase(value))) 276 | { 277 | // if the value is not yes, true or 1 then don't add the 278 | // option to the CommandLine 279 | break; 280 | } 281 | 282 | cmd.addOption(opt); 283 | } 284 | } 285 | } 286 | 287 | /** 288 | * Throws a {@link MissingOptionException} if all of the required options 289 | * are not present. 290 | * 291 | * @throws MissingOptionException if any of the required Options 292 | * are not present. 293 | */ 294 | protected void checkRequiredOptions() throws MissingOptionException 295 | { 296 | // if there are required options that have not been processsed 297 | if (!getRequiredOptions().isEmpty()) 298 | { 299 | throw new MissingOptionException(getRequiredOptions()); 300 | } 301 | } 302 | 303 | /** 304 | *

Process the argument values for the specified Option 305 | * opt using the values retrieved from the 306 | * specified iterator iter. 307 | * 308 | * @param opt The current Option 309 | * @param iter The iterator over the flattened command line 310 | * Options. 311 | * 312 | * @throws ParseException if an argument value is required 313 | * and it is has not been found. 314 | */ 315 | public void processArgs(Option opt, ListIterator iter) throws ParseException 316 | { 317 | // loop until an option is found 318 | while (iter.hasNext()) 319 | { 320 | String str = (String) iter.next(); 321 | 322 | // found an Option, not an argument 323 | if (getOptions().hasOption(str) && str.startsWith("-")) 324 | { 325 | iter.previous(); 326 | break; 327 | } 328 | 329 | // found a value 330 | try 331 | { 332 | opt.addValueForProcessing(Util.stripLeadingAndTrailingQuotes(str)); 333 | } 334 | catch (RuntimeException exp) 335 | { 336 | iter.previous(); 337 | break; 338 | } 339 | } 340 | 341 | if (opt.getValues() == null && !opt.hasOptionalArg()) 342 | { 343 | throw new MissingArgumentException(opt); 344 | } 345 | } 346 | 347 | /** 348 | * Process the Option specified by arg using the values 349 | * retrieved from the specfied iterator iter. 350 | * 351 | * @param arg The String value representing an Option 352 | * @param iter The iterator over the flattened command line arguments. 353 | * 354 | * @throws ParseException if arg does not represent an Option 355 | */ 356 | protected void processOption(String arg, ListIterator iter) throws ParseException 357 | { 358 | boolean hasOption = getOptions().hasOption(arg); 359 | 360 | // if there is no option throw an UnrecognisedOptionException 361 | if (!hasOption) 362 | { 363 | throw new UnrecognizedOptionException("Unrecognized option: " + arg, arg); 364 | } 365 | 366 | // get the option represented by arg 367 | Option opt = (Option) getOptions().getOption(arg).clone(); 368 | 369 | // if the option is a required option remove the option from 370 | // the requiredOptions list 371 | if (opt.isRequired()) 372 | { 373 | getRequiredOptions().remove(opt.getKey()); 374 | } 375 | 376 | // if the option is in an OptionGroup make that option the selected 377 | // option of the group 378 | if (getOptions().getOptionGroup(opt) != null) 379 | { 380 | OptionGroup group = getOptions().getOptionGroup(opt); 381 | 382 | if (group.isRequired()) 383 | { 384 | getRequiredOptions().remove(group); 385 | } 386 | 387 | group.setSelected(opt); 388 | } 389 | 390 | // if the option takes an argument value 391 | if (opt.hasArg()) 392 | { 393 | processArgs(opt, iter); 394 | } 395 | 396 | // set the option on the command line 397 | cmd.addOption(opt); 398 | } 399 | } 400 | -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/cli/PatternOptionBuilder.java: -------------------------------------------------------------------------------- 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 com.github.jobop.performance.cli; 19 | 20 | import java.io.File; 21 | import java.io.FileInputStream; 22 | import java.net.URL; 23 | import java.util.Date; 24 | 25 | /** 26 | *

27 | * Allows Options to be created from a single String. 28 | * The pattern contains various single character flags and via 29 | * an optional punctuation character, their expected type. 30 | *

31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | *
a-a flag
b@-b [classname]
c>-c [filename]
d+-d [classname] (creates object via empty contructor)
e%-e [number] (creates Double/Long instance depeding on existing of a '.')
f/-f [url]
g:-g [string]
41 | * 42 | *

43 | * For example, the following allows command line flags of '-v -p string-value -f /dir/file'. 44 | * The exclamation mark precede a mandatory option. 45 | *

46 | * Options options = PatternOptionBuilder.parsePattern("vp:!f/"); 47 | * 48 | *

49 | * TODO These need to break out to OptionType and also 50 | * to be pluggable. 51 | *

52 | * 53 | * @version $Revision: 734339 $, $Date: 2009-01-13 21:56:47 -0800 (Tue, 13 Jan 2009) $ 54 | */ 55 | public class PatternOptionBuilder 56 | { 57 | /** String class */ 58 | public static final Class STRING_VALUE = String.class; 59 | 60 | /** Object class */ 61 | public static final Class OBJECT_VALUE = Object.class; 62 | 63 | /** Number class */ 64 | public static final Class NUMBER_VALUE = Number.class; 65 | 66 | /** Date class */ 67 | public static final Class DATE_VALUE = Date.class; 68 | 69 | /** Class class */ 70 | public static final Class CLASS_VALUE = Class.class; 71 | 72 | /// can we do this one?? 73 | // is meant to check that the file exists, else it errors. 74 | // ie) it's for reading not writing. 75 | 76 | /** FileInputStream class */ 77 | public static final Class EXISTING_FILE_VALUE = FileInputStream.class; 78 | 79 | /** File class */ 80 | public static final Class FILE_VALUE = File.class; 81 | 82 | /** File array class */ 83 | public static final Class FILES_VALUE = File[].class; 84 | 85 | /** URL class */ 86 | public static final Class URL_VALUE = URL.class; 87 | 88 | /** 89 | * Retrieve the class that ch represents. 90 | * 91 | * @param ch the specified character 92 | * @return The class that ch represents 93 | */ 94 | public static Object getValueClass(char ch) 95 | { 96 | switch (ch) 97 | { 98 | case '@': 99 | return PatternOptionBuilder.OBJECT_VALUE; 100 | case ':': 101 | return PatternOptionBuilder.STRING_VALUE; 102 | case '%': 103 | return PatternOptionBuilder.NUMBER_VALUE; 104 | case '+': 105 | return PatternOptionBuilder.CLASS_VALUE; 106 | case '#': 107 | return PatternOptionBuilder.DATE_VALUE; 108 | case '<': 109 | return PatternOptionBuilder.EXISTING_FILE_VALUE; 110 | case '>': 111 | return PatternOptionBuilder.FILE_VALUE; 112 | case '*': 113 | return PatternOptionBuilder.FILES_VALUE; 114 | case '/': 115 | return PatternOptionBuilder.URL_VALUE; 116 | } 117 | 118 | return null; 119 | } 120 | 121 | /** 122 | * Returns whether ch is a value code, i.e. 123 | * whether it represents a class in a pattern. 124 | * 125 | * @param ch the specified character 126 | * @return true if ch is a value code, otherwise false. 127 | */ 128 | public static boolean isValueCode(char ch) 129 | { 130 | return ch == '@' 131 | || ch == ':' 132 | || ch == '%' 133 | || ch == '+' 134 | || ch == '#' 135 | || ch == '<' 136 | || ch == '>' 137 | || ch == '*' 138 | || ch == '/' 139 | || ch == '!'; 140 | } 141 | 142 | /** 143 | * Returns the {@link Options} instance represented by pattern. 144 | * 145 | * @param pattern the pattern string 146 | * @return The {@link Options} instance 147 | */ 148 | public static Options parsePattern(String pattern) 149 | { 150 | char opt = ' '; 151 | boolean required = false; 152 | Object type = null; 153 | 154 | Options options = new Options(); 155 | 156 | for (int i = 0; i < pattern.length(); i++) 157 | { 158 | char ch = pattern.charAt(i); 159 | 160 | // a value code comes after an option and specifies 161 | // details about it 162 | if (!isValueCode(ch)) 163 | { 164 | if (opt != ' ') 165 | { 166 | OptionBuilder.hasArg(type != null); 167 | OptionBuilder.isRequired(required); 168 | OptionBuilder.withType(type); 169 | 170 | // we have a previous one to deal with 171 | options.addOption(OptionBuilder.create(opt)); 172 | required = false; 173 | type = null; 174 | opt = ' '; 175 | } 176 | 177 | opt = ch; 178 | } 179 | else if (ch == '!') 180 | { 181 | required = true; 182 | } 183 | else 184 | { 185 | type = getValueClass(ch); 186 | } 187 | } 188 | 189 | if (opt != ' ') 190 | { 191 | OptionBuilder.hasArg(type != null); 192 | OptionBuilder.isRequired(required); 193 | OptionBuilder.withType(type); 194 | 195 | // we have a final one to deal with 196 | options.addOption(OptionBuilder.create(opt)); 197 | } 198 | 199 | return options; 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/cli/PosixParser.java: -------------------------------------------------------------------------------- 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 com.github.jobop.performance.cli; 19 | 20 | import java.util.ArrayList; 21 | import java.util.Arrays; 22 | import java.util.Iterator; 23 | import java.util.List; 24 | 25 | /** 26 | * The class PosixParser provides an implementation of the 27 | * {@link Parser#flatten(Options,String[],boolean) flatten} method. 28 | * 29 | * @author John Keyes (john at integralsource.com) 30 | * @version $Revision: 695760 $, $Date: 2008-09-16 01:05:03 -0700 (Tue, 16 Sep 31 | * 2008) $ 32 | */ 33 | public class PosixParser extends Parser { 34 | /** holder for flattened tokens */ 35 | private List tokens = new ArrayList(); 36 | 37 | /** specifies if bursting should continue */ 38 | private boolean eatTheRest; 39 | 40 | /** holder for the current option */ 41 | private Option currentOption; 42 | 43 | /** the command line Options */ 44 | private Options options; 45 | 46 | /** 47 | * Resets the members to their original state i.e. remove all of 48 | * tokens entries and set eatTheRest to false. 49 | */ 50 | private void init() { 51 | eatTheRest = false; 52 | tokens.clear(); 53 | } 54 | 55 | /** 56 | *

57 | * An implementation of {@link Parser}'s abstract 58 | * {@link Parser#flatten(Options,String[],boolean) flatten} method. 59 | *

60 | * 61 | *

62 | * The following are the rules used by this flatten method. 63 | *

    64 | *
  1. if stopAtNonOption is true then do not burst 65 | * anymore of arguments entries, just add each successive entry 66 | * without further processing. Otherwise, ignore 67 | * stopAtNonOption.
  2. 68 | *
  3. if the current arguments entry is "--" just add 69 | * the entry to the list of processed tokens
  4. 70 | *
  5. if the current arguments entry is "-" just add 71 | * the entry to the list of processed tokens
  6. 72 | *
  7. if the current arguments entry is two characters in 73 | * length and the first character is "-" then check if this is a 74 | * valid {@link Option} id. If it is a valid id, then add the entry to the 75 | * list of processed tokens and set the current {@link Option} member. If it 76 | * is not a valid id and stopAtNonOption is true, then the 77 | * remaining entries are copied to the list of processed tokens. Otherwise, 78 | * the current entry is ignored.
  8. 79 | *
  9. if the current arguments entry is more than two 80 | * characters in length and the first character is "-" then we need 81 | * to burst the entry to determine its constituents. For more information on 82 | * the bursting algorithm see 83 | * {@link PosixParser#burstToken(String, boolean) burstToken}.
  10. 84 | *
  11. if the current arguments entry is not handled by any of 85 | * the previous rules, then the entry is added to the list of processed 86 | * tokens.
  12. 87 | *
88 | *

89 | * 90 | * @param options 91 | * The command line {@link Options} 92 | * @param arguments 93 | * The command line arguments to be parsed 94 | * @param stopAtNonOption 95 | * Specifies whether to stop flattening when an non option is 96 | * found. 97 | * @return The flattened arguments String array. 98 | */ 99 | protected String[] flatten(Options options, String[] arguments, boolean stopAtNonOption) { 100 | init(); 101 | this.options = options; 102 | 103 | // an iterator for the command line tokens 104 | Iterator iter = Arrays.asList(arguments).iterator(); 105 | 106 | // process each command line token 107 | while (iter.hasNext()) { 108 | // get the next command line token 109 | String token = (String) iter.next(); 110 | 111 | // handle long option --foo or --foo=bar 112 | if (token.startsWith("--")) { 113 | int pos = token.indexOf('='); 114 | String opt = pos == -1 ? token : token.substring(0, pos); // --foo 115 | 116 | if (!options.hasOption(opt)) { 117 | processNonOptionToken(token, stopAtNonOption); 118 | } else { 119 | currentOption = options.getOption(opt); 120 | 121 | tokens.add(opt); 122 | if (pos != -1) { 123 | tokens.add(token.substring(pos + 1)); 124 | } 125 | } 126 | } 127 | 128 | // single hyphen 129 | else if ("-".equals(token)) { 130 | tokens.add(token); 131 | } else if (token.startsWith("-")) { 132 | if (token.length() == 2 || options.hasOption(token)) { 133 | processOptionToken(token, stopAtNonOption); 134 | } 135 | // requires bursting 136 | else { 137 | burstToken(token, stopAtNonOption); 138 | } 139 | } else { 140 | processNonOptionToken(token, stopAtNonOption); 141 | } 142 | 143 | gobble(iter); 144 | } 145 | 146 | return (String[]) tokens.toArray(new String[tokens.size()]); 147 | } 148 | 149 | /** 150 | * Adds the remaining tokens to the processed tokens list. 151 | * 152 | * @param iter 153 | * An iterator over the remaining tokens 154 | */ 155 | private void gobble(Iterator iter) { 156 | if (eatTheRest) { 157 | while (iter.hasNext()) { 158 | tokens.add(iter.next()); 159 | } 160 | } 161 | } 162 | 163 | /** 164 | * Add the special token "--" and the current value to 165 | * the processed tokens list. Then add all the remaining 166 | * argument values to the processed tokens list. 167 | * 168 | * @param value 169 | * The current token 170 | */ 171 | private void processNonOptionToken(String value, boolean stopAtNonOption) { 172 | if (stopAtNonOption && (currentOption == null || !currentOption.hasArg())) { 173 | eatTheRest = true; 174 | tokens.add("--"); 175 | } 176 | 177 | tokens.add(value); 178 | } 179 | 180 | /** 181 | *

182 | * If an {@link Option} exists for token then add the token to 183 | * the processed list. 184 | *

185 | * 186 | *

187 | * If an {@link Option} does not exist and stopAtNonOption is 188 | * set then add the remaining tokens to the processed tokens list directly. 189 | *

190 | * 191 | * @param token 192 | * The current option token 193 | * @param stopAtNonOption 194 | * Specifies whether flattening should halt at the first non 195 | * option. 196 | */ 197 | private void processOptionToken(String token, boolean stopAtNonOption) { 198 | if (stopAtNonOption && !options.hasOption(token)) { 199 | eatTheRest = true; 200 | } 201 | 202 | if (options.hasOption(token)) { 203 | currentOption = options.getOption(token); 204 | } 205 | 206 | tokens.add(token); 207 | } 208 | 209 | /** 210 | * Breaks token into its constituent parts using the following 211 | * algorithm. 212 | * 213 | * 230 | * 231 | * @param token 232 | * The current token to be burst 233 | * @param stopAtNonOption 234 | * Specifies whether to stop processing at the first non-Option 235 | * encountered. 236 | */ 237 | protected void burstToken(String token, boolean stopAtNonOption) { 238 | for (int i = 1; i < token.length(); i++) { 239 | String ch = String.valueOf(token.charAt(i)); 240 | 241 | if (options.hasOption(ch)) { 242 | tokens.add("-" + ch); 243 | currentOption = options.getOption(ch); 244 | 245 | if (currentOption.hasArg() && (token.length() != (i + 1))) { 246 | tokens.add(token.substring(i + 1)); 247 | 248 | break; 249 | } 250 | } else if (stopAtNonOption) { 251 | processNonOptionToken(token.substring(i), true); 252 | break; 253 | } else { 254 | tokens.add(token); 255 | break; 256 | } 257 | } 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/cli/TypeHandler.java: -------------------------------------------------------------------------------- 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 com.github.jobop.performance.cli; 19 | 20 | import java.io.File; 21 | import java.net.MalformedURLException; 22 | import java.net.URL; 23 | import java.util.Date; 24 | 25 | /** 26 | * This is a temporary implementation. TypeHandler will handle the 27 | * pluggableness of OptionTypes and it will direct all of these types 28 | * of conversion functionalities to ConvertUtils component in Commons 29 | * already. BeanUtils I think. 30 | * 31 | * @version $Revision: 741425 $, $Date: 2009-02-05 22:10:54 -0800 (Thu, 05 Feb 2009) $ 32 | */ 33 | public class TypeHandler 34 | { 35 | /** 36 | * Returns the Object of type obj 37 | * with the value of str. 38 | * 39 | * @param str the command line value 40 | * @param obj the type of argument 41 | * @return The instance of obj initialised with 42 | * the value of str. 43 | */ 44 | public static Object createValue(String str, Object obj) 45 | throws ParseException 46 | { 47 | return createValue(str, (Class) obj); 48 | } 49 | 50 | /** 51 | * Returns the Object of type clazz 52 | * with the value of str. 53 | * 54 | * @param str the command line value 55 | * @param clazz the type of argument 56 | * @return The instance of clazz initialised with 57 | * the value of str. 58 | */ 59 | public static Object createValue(String str, Class clazz) 60 | throws ParseException 61 | { 62 | if (PatternOptionBuilder.STRING_VALUE == clazz) 63 | { 64 | return str; 65 | } 66 | else if (PatternOptionBuilder.OBJECT_VALUE == clazz) 67 | { 68 | return createObject(str); 69 | } 70 | else if (PatternOptionBuilder.NUMBER_VALUE == clazz) 71 | { 72 | return createNumber(str); 73 | } 74 | else if (PatternOptionBuilder.DATE_VALUE == clazz) 75 | { 76 | return createDate(str); 77 | } 78 | else if (PatternOptionBuilder.CLASS_VALUE == clazz) 79 | { 80 | return createClass(str); 81 | } 82 | else if (PatternOptionBuilder.FILE_VALUE == clazz) 83 | { 84 | return createFile(str); 85 | } 86 | else if (PatternOptionBuilder.EXISTING_FILE_VALUE == clazz) 87 | { 88 | return createFile(str); 89 | } 90 | else if (PatternOptionBuilder.FILES_VALUE == clazz) 91 | { 92 | return createFiles(str); 93 | } 94 | else if (PatternOptionBuilder.URL_VALUE == clazz) 95 | { 96 | return createURL(str); 97 | } 98 | else 99 | { 100 | return null; 101 | } 102 | } 103 | 104 | /** 105 | * Create an Object from the classname and empty constructor. 106 | * 107 | * @param classname the argument value 108 | * @return the initialised object, or null if it couldn't create 109 | * the Object. 110 | */ 111 | public static Object createObject(String classname) 112 | throws ParseException 113 | { 114 | Class cl = null; 115 | 116 | try 117 | { 118 | cl = Class.forName(classname); 119 | } 120 | catch (ClassNotFoundException cnfe) 121 | { 122 | throw new ParseException("Unable to find the class: " + classname); 123 | } 124 | 125 | Object instance = null; 126 | 127 | try 128 | { 129 | instance = cl.newInstance(); 130 | } 131 | catch (Exception e) 132 | { 133 | throw new ParseException(e.getClass().getName() + "; Unable to create an instance of: " + classname); 134 | } 135 | 136 | return instance; 137 | } 138 | 139 | /** 140 | * Create a number from a String. If a . is present, it creates a 141 | * Double, otherwise a Long. 142 | * 143 | * @param str the value 144 | * @return the number represented by str, if str 145 | * is not a number, null is returned. 146 | */ 147 | public static Number createNumber(String str) 148 | throws ParseException 149 | { 150 | try 151 | { 152 | if (str.indexOf('.') != -1) 153 | { 154 | return Double.valueOf(str); 155 | } 156 | else 157 | { 158 | return Long.valueOf(str); 159 | } 160 | } 161 | catch (NumberFormatException e) 162 | { 163 | throw new ParseException(e.getMessage()); 164 | } 165 | } 166 | 167 | /** 168 | * Returns the class whose name is classname. 169 | * 170 | * @param classname the class name 171 | * @return The class if it is found, otherwise return null 172 | */ 173 | public static Class createClass(String classname) 174 | throws ParseException 175 | { 176 | try 177 | { 178 | return Class.forName(classname); 179 | } 180 | catch (ClassNotFoundException e) 181 | { 182 | throw new ParseException("Unable to find the class: " + classname); 183 | } 184 | } 185 | 186 | /** 187 | * Returns the date represented by str. 188 | * 189 | * @param str the date string 190 | * @return The date if str is a valid date string, 191 | * otherwise return null. 192 | */ 193 | public static Date createDate(String str) 194 | throws ParseException 195 | { 196 | throw new UnsupportedOperationException("Not yet implemented"); 197 | } 198 | 199 | /** 200 | * Returns the URL represented by str. 201 | * 202 | * @param str the URL string 203 | * @return The URL is str is well-formed, otherwise 204 | * return null. 205 | */ 206 | public static URL createURL(String str) 207 | throws ParseException 208 | { 209 | try 210 | { 211 | return new URL(str); 212 | } 213 | catch (MalformedURLException e) 214 | { 215 | throw new ParseException("Unable to parse the URL: " + str); 216 | } 217 | } 218 | 219 | /** 220 | * Returns the File represented by str. 221 | * 222 | * @param str the File location 223 | * @return The file represented by str. 224 | */ 225 | public static File createFile(String str) 226 | throws ParseException 227 | { 228 | return new File(str); 229 | } 230 | 231 | /** 232 | * Returns the File[] represented by str. 233 | * 234 | * @param str the paths to the files 235 | * @return The File[] represented by str. 236 | */ 237 | public static File[] createFiles(String str) 238 | throws ParseException 239 | { 240 | // to implement/port: 241 | // return FileW.findFiles(str); 242 | throw new UnsupportedOperationException("Not yet implemented"); 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/cli/UnrecognizedOptionException.java: -------------------------------------------------------------------------------- 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 com.github.jobop.performance.cli; 19 | 20 | 21 | /** 22 | * Exception thrown during parsing signalling an unrecognized 23 | * option was seen. 24 | * 25 | * @author bob mcwhiter (bob @ werken.com) 26 | * @version $Revision: 680644 $, $Date: 2008-07-29 01:13:48 -0700 (Tue, 29 Jul 2008) $ 27 | */ 28 | public class UnrecognizedOptionException extends ParseException 29 | { 30 | /** The unrecognized option */ 31 | private String option; 32 | 33 | /** 34 | * Construct a new UnrecognizedArgumentException 35 | * with the specified detail message. 36 | * 37 | * @param message the detail message 38 | */ 39 | public UnrecognizedOptionException(String message) 40 | { 41 | super(message); 42 | } 43 | 44 | /** 45 | * Construct a new UnrecognizedArgumentException 46 | * with the specified option and detail message. 47 | * 48 | * @param message the detail message 49 | * @param option the unrecognized option 50 | * @since 1.2 51 | */ 52 | public UnrecognizedOptionException(String message, String option) 53 | { 54 | this(message); 55 | this.option = option; 56 | } 57 | 58 | /** 59 | * Returns the unrecognized option. 60 | * 61 | * @return the related option 62 | * @since 1.2 63 | */ 64 | public String getOption() 65 | { 66 | return option; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/cli/Util.java: -------------------------------------------------------------------------------- 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 com.github.jobop.performance.cli; 19 | 20 | /** 21 | * Contains useful helper methods for classes within this package. 22 | * 23 | * @author John Keyes (john at integralsource.com) 24 | * @version $Revision: 680644 $, $Date: 2008-07-29 01:13:48 -0700 (Tue, 29 Jul 2008) $ 25 | */ 26 | class Util 27 | { 28 | /** 29 | * Remove the hyphens from the begining of str and 30 | * return the new String. 31 | * 32 | * @param str The string from which the hyphens should be removed. 33 | * 34 | * @return the new String. 35 | */ 36 | static String stripLeadingHyphens(String str) 37 | { 38 | if (str == null) 39 | { 40 | return null; 41 | } 42 | if (str.startsWith("--")) 43 | { 44 | return str.substring(2, str.length()); 45 | } 46 | else if (str.startsWith("-")) 47 | { 48 | return str.substring(1, str.length()); 49 | } 50 | 51 | return str; 52 | } 53 | 54 | /** 55 | * Remove the leading and trailing quotes from str. 56 | * E.g. if str is '"one two"', then 'one two' is returned. 57 | * 58 | * @param str The string from which the leading and trailing quotes 59 | * should be removed. 60 | * 61 | * @return The string without the leading and trailing quotes. 62 | */ 63 | static String stripLeadingAndTrailingQuotes(String str) 64 | { 65 | if (str.startsWith("\"")) 66 | { 67 | str = str.substring(1, str.length()); 68 | } 69 | if (str.endsWith("\"")) 70 | { 71 | str = str.substring(0, str.length() - 1); 72 | } 73 | return str; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/loader/AppJarFileClassLoader.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jobop/performance/5f14829146eb5bc48a0c55e606ad715ed69a2fd1/src/main/java/com/github/jobop/performance/loader/AppJarFileClassLoader.java -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/loader/JarFileClassLoader.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jobop/performance/5f14829146eb5bc48a0c55e606ad715ed69a2fd1/src/main/java/com/github/jobop/performance/loader/JarFileClassLoader.java -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/loader/PrerformanceBizSpiLoaderUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.jobop.performance.loader; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileFilter; 6 | import java.io.FileInputStream; 7 | import java.io.InputStreamReader; 8 | import java.lang.reflect.Method; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | import com.github.jobop.performance.spi.PerformanceBizSpi; 13 | 14 | public class PrerformanceBizSpiLoaderUtil { 15 | public static List loadSpiFromDir(File dir) { 16 | List spis = new ArrayList(); 17 | File[] jarFiles = dir.listFiles(new FileFilter() { 18 | @Override 19 | public boolean accept(File arg0) { 20 | return arg0.getName().endsWith(".jar"); 21 | } 22 | }); 23 | File[] spiFiles = dir.listFiles(new FileFilter() { 24 | @Override 25 | public boolean accept(File arg0) { 26 | return arg0.getName().endsWith("spi.lst"); 27 | } 28 | }); 29 | if (spiFiles == null || spiFiles.length == 0) { 30 | return spis; 31 | } 32 | 33 | JarFileClassLoader classLoader = new AppJarFileClassLoader(jarFiles); 34 | List spiListLine = null; 35 | try { 36 | spiListLine = readFileForLines(spiFiles[0]); 37 | } catch (Exception e1) { 38 | e1.printStackTrace(); 39 | } 40 | if (spiListLine == null || spiListLine.size() == 0) { 41 | return spis; 42 | } 43 | for (String spiName : spiListLine) { 44 | PerformanceBizSpi spi = null; 45 | try { 46 | Class clazz = classLoader.loadClass(spiName); 47 | Object obj = clazz.newInstance(); 48 | spi = (PerformanceBizSpi) obj; 49 | } catch (Exception e) { 50 | e.printStackTrace(); 51 | System.out.println("can not load spi:" + spiName + " from dir" + dir.getAbsolutePath()); 52 | } 53 | if (null != spi) { 54 | spis.add(spi); 55 | } 56 | } 57 | 58 | return spis; 59 | } 60 | 61 | private static List readFileForLines(File file) throws Exception { 62 | List lines = new ArrayList(); 63 | if (file == null || !file.exists()) { 64 | return lines; 65 | } 66 | FileInputStream fis = null; 67 | BufferedReader br = null; 68 | try { 69 | fis = new FileInputStream(file); 70 | br = new BufferedReader(new InputStreamReader(fis)); 71 | String line = null; 72 | while ((line = br.readLine()) != null) { 73 | lines.add(line); 74 | } 75 | } finally { 76 | try { 77 | br.close(); 78 | } catch (Exception e) { 79 | } 80 | try { 81 | fis.close(); 82 | } catch (Exception e) { 83 | } 84 | } 85 | return lines; 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/parser/ArgusParser.java: -------------------------------------------------------------------------------- 1 | package com.github.jobop.performance.parser; 2 | 3 | import com.github.jobop.performance.cli.CommandLine; 4 | import com.github.jobop.performance.cli.CommandLineParser; 5 | import com.github.jobop.performance.cli.Option; 6 | import com.github.jobop.performance.cli.Options; 7 | import com.github.jobop.performance.cli.ParseException; 8 | import com.github.jobop.performance.cli.PatternOptionBuilder; 9 | import com.github.jobop.performance.cli.PosixParser; 10 | 11 | public class ArgusParser { 12 | 13 | private final static String BIZ_NAME = "n"; 14 | private final static String ABIDANCE_TIME = "t"; 15 | private final static String THREAD_COUNT = "c"; 16 | private final static String LOG_PATH = "l"; 17 | 18 | public PerformanceContext parse(String[] args) { 19 | 20 | try { 21 | CommandLineParser parser = new PosixParser(); 22 | CommandLine cmd = parser.parse(createOptions(), args); 23 | return assembleBootstrapArgus(cmd); 24 | } catch (ParseException e) { 25 | help(); 26 | System.exit(0); 27 | return null; 28 | } 29 | 30 | } 31 | 32 | private PerformanceContext assembleBootstrapArgus(CommandLine cmd) throws ParseException { 33 | PerformanceContext argus = new PerformanceContext(); 34 | argus.setAbidanceTime(((Long) cmd.getParsedOptionValue(ABIDANCE_TIME)).intValue()); 35 | argus.setThreadCount((Long) cmd.getParsedOptionValue(THREAD_COUNT)); 36 | String bizName = cmd.getOptionValue(BIZ_NAME); 37 | if (null != bizName && !bizName.equals("")) { 38 | argus.setBizName(bizName); 39 | } 40 | String logPath = cmd.getOptionValue(LOG_PATH); 41 | if (logPath != null && !logPath.equals("")) { 42 | argus.setLogPath(logPath); 43 | } 44 | return argus; 45 | } 46 | 47 | private Options createOptions() { 48 | Options options = new Options(); 49 | options.addOption(bizNameOption()).addOption(abidanceTimeOption()).addOption(threadCountOption()).addOption(logPathOption()); 50 | return options; 51 | } 52 | 53 | private final Option bizNameOption() { 54 | Option opt = new Option(BIZ_NAME, true, "bizName"); 55 | opt.setType(String.class); 56 | opt.setRequired(false); 57 | return opt; 58 | } 59 | 60 | private final Option abidanceTimeOption() { 61 | Option opt = new Option(ABIDANCE_TIME, true, "abidanceTime"); 62 | opt.setType(PatternOptionBuilder.NUMBER_VALUE); 63 | opt.setRequired(true); 64 | return opt; 65 | } 66 | 67 | private final Option threadCountOption() { 68 | Option opt = new Option(THREAD_COUNT, true, "threadCount"); 69 | opt.setType(PatternOptionBuilder.NUMBER_VALUE); 70 | opt.setRequired(true); 71 | return opt; 72 | } 73 | 74 | private final Option logPathOption() { 75 | Option opt = new Option(LOG_PATH, true, "logPath"); 76 | opt.setType(String.class); 77 | opt.setRequired(false); 78 | return opt; 79 | } 80 | 81 | private void help() { 82 | System.out.println("usage: performance [-n bizName] [-l logPath] -t abidanceMinuteTime -c threadCount"); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/parser/PerformanceContext.java: -------------------------------------------------------------------------------- 1 | package com.github.jobop.performance.parser; 2 | 3 | public class PerformanceContext { 4 | private String bizName = ""; 5 | private int abidanceTime; 6 | private Long threadCount; 7 | private String logPath = ""; 8 | 9 | public String getBizName() { 10 | return bizName; 11 | } 12 | 13 | public void setBizName(String bizName) { 14 | this.bizName = bizName; 15 | } 16 | 17 | public int getAbidanceTime() { 18 | return abidanceTime; 19 | } 20 | 21 | public void setAbidanceTime(int abidanceTime) { 22 | this.abidanceTime = abidanceTime; 23 | } 24 | 25 | public Long getThreadCount() { 26 | return threadCount; 27 | } 28 | 29 | public void setThreadCount(Long threadCount) { 30 | this.threadCount = threadCount; 31 | } 32 | 33 | public String getLogPath() { 34 | return logPath; 35 | } 36 | 37 | public void setLogPath(String logPath) { 38 | this.logPath = logPath; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/spi/PerformanceBizSpi.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jobop/performance/5f14829146eb5bc48a0c55e606ad715ed69a2fd1/src/main/java/com/github/jobop/performance/spi/PerformanceBizSpi.java -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/spi/TestPerformanceBizSpi.java: -------------------------------------------------------------------------------- 1 | package com.github.jobop.performance.spi; 2 | 3 | import java.util.Random; 4 | 5 | public class TestPerformanceBizSpi implements PerformanceBizSpi { 6 | 7 | @Override 8 | public boolean excute(BizContext context) { 9 | try { 10 | Thread.sleep(500); 11 | } catch (InterruptedException e) { 12 | Thread.currentThread().interrupt(); 13 | } 14 | return ((new Random().nextInt(10) % 3) == 0) ? false : true; 15 | } 16 | 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/spi/TestPerformanceBizSpi2.java: -------------------------------------------------------------------------------- 1 | package com.github.jobop.performance.spi; 2 | 3 | import java.util.Random; 4 | 5 | public class TestPerformanceBizSpi2 implements PerformanceBizSpi { 6 | 7 | @Override 8 | public boolean excute(BizContext context) { 9 | try { 10 | Thread.sleep(200); 11 | } catch (InterruptedException e) { 12 | Thread.currentThread().interrupt(); 13 | } 14 | return ((new Random().nextInt(10) % 2) == 0) ? false : true; 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/statistics/Counter.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jobop/performance/5f14829146eb5bc48a0c55e606ad715ed69a2fd1/src/main/java/com/github/jobop/performance/statistics/Counter.java -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/statistics/Recoder.java: -------------------------------------------------------------------------------- 1 | package com.github.jobop.performance.statistics; 2 | 3 | import java.io.PrintStream; 4 | 5 | public class Recoder { 6 | 7 | public static PrintStream out = null; 8 | public static PrintStream err = null; 9 | static { 10 | Runtime.getRuntime().addShutdownHook(new Thread() { 11 | @Override 12 | public void run() { 13 | 14 | try { 15 | if (out != null) { 16 | out.close(); 17 | } 18 | } catch (Exception e) { 19 | } 20 | try { 21 | if (err != null) { 22 | err.close(); 23 | } 24 | } catch (Exception e) { 25 | } 26 | } 27 | }); 28 | } 29 | 30 | public static void setOut(PrintStream out) { 31 | Recoder.out = out; 32 | } 33 | 34 | public static void setErr(PrintStream err) { 35 | Recoder.err = err; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/statistics/Timer.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jobop/performance/5f14829146eb5bc48a0c55e606ad715ed69a2fd1/src/main/java/com/github/jobop/performance/statistics/Timer.java -------------------------------------------------------------------------------- /src/main/java/com/github/jobop/performance/task/PerformanceTask.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jobop/performance/5f14829146eb5bc48a0c55e606ad715ed69a2fd1/src/main/java/com/github/jobop/performance/task/PerformanceTask.java -------------------------------------------------------------------------------- /src/main/resources/config.properties: -------------------------------------------------------------------------------- 1 | LIB_BASE_PATH=D:\\hehehe -------------------------------------------------------------------------------- /src/test/java.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jobop/performance/5f14829146eb5bc48a0c55e606ad715ed69a2fd1/src/test/java.gitignore --------------------------------------------------------------------------------