1 /* 2 Licensed to the Apache Software Foundation (ASF) under one or more 3 contributor license agreements. See the NOTICE file distributed with 4 this work for additional information regarding copyright ownership. 5 The ASF licenses this file to You under the Apache License, Version 2.0 6 (the "License"); you may not use this file except in compliance with 7 the License. You may obtain a copy of the License at 8 9 http://www.apache.org/licenses/LICENSE-2.0 10 11 Unless required by applicable law or agreed to in writing, software 12 distributed under the License is distributed on an "AS IS" BASIS, 13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 See the License for the specific language governing permissions and 15 limitations under the License. 16 */ 17 18 package org.apache.commons.cli; 19 20 import static org.apache.commons.cli.Util.EMPTY_STRING_ARRAY; 21 22 import java.io.Serializable; 23 import java.util.ArrayList; 24 import java.util.Iterator; 25 import java.util.LinkedList; 26 import java.util.List; 27 import java.util.Objects; 28 import java.util.Properties; 29 import java.util.function.Consumer; 30 import java.util.function.Supplier; 31 32 /** 33 * Represents list of arguments parsed against a {@link Options} descriptor. 34 * <p> 35 * It allows querying of a boolean {@link #hasOption(String opt)}, in addition to retrieving the 36 * {@link #getOptionValue(String opt)} for options requiring arguments. 37 * </p> 38 * <p> 39 * Additionally, any left-over or unrecognized arguments, are available for further processing. 40 * </p> 41 */ 42 public class CommandLine implements Serializable { 43 44 /** 45 * A nested builder class to create {@code CommandLine} instance using descriptive methods. 46 * 47 * @since 1.4 48 */ 49 public static final class Builder { 50 51 /** 52 * Prints an Option to {@link System#out}. 53 */ 54 static final Consumer<Option> DEPRECATED_HANDLER = o -> System.out.println(o.toDeprecatedString()); 55 56 /** The unrecognized options/arguments */ 57 private final List<String> args = new LinkedList<>(); 58 59 /** The processed options */ 60 private final List<Option> options = new ArrayList<>(); 61 62 /** 63 * Deprecated Option handler. 64 */ 65 private Consumer<Option> deprecatedHandler = DEPRECATED_HANDLER; 66 67 /** 68 * Adds left-over unrecognized option/argument. 69 * 70 * @param arg the unrecognized option/argument. 71 * 72 * @return this Builder instance for method chaining. 73 */ 74 public Builder addArg(final String arg) { 75 if (arg != null) { 76 args.add(arg); 77 } 78 return this; 79 } 80 81 /** 82 * Adds an option to the command line. The values of the option are stored. 83 * 84 * @param opt the processed option. 85 * 86 * @return this Builder instance for method chaining. 87 */ 88 public Builder addOption(final Option opt) { 89 if (opt != null) { 90 options.add(opt); 91 } 92 return this; 93 } 94 95 /** 96 * Creates the new instance. 97 * 98 * @return the new instance. 99 */ 100 public CommandLine build() { 101 return new CommandLine(args, options, deprecatedHandler); 102 } 103 104 /** 105 * Sets the deprecated option handler. 106 * 107 * @param deprecatedHandler the deprecated option handler. 108 * @return this. 109 * @since 1.7.0 110 */ 111 public Builder setDeprecatedHandler(final Consumer<Option> deprecatedHandler) { 112 this.deprecatedHandler = deprecatedHandler; 113 return this; 114 } 115 } 116 117 /** The serial version UID. */ 118 private static final long serialVersionUID = 1L; 119 120 /** 121 * Creates a new builder. 122 * 123 * @return a new builder. 124 * @since 1.7.0 125 */ 126 public static Builder builder() { 127 return new Builder(); 128 } 129 130 /** The unrecognized options/arguments */ 131 private final List<String> args; 132 133 /** The processed options */ 134 private final List<Option> options; 135 136 /** 137 * The deprecated option handler. 138 * <p> 139 * If you want to serialize this field, use a serialization proxy. 140 * </p> 141 */ 142 private final transient Consumer<Option> deprecatedHandler; 143 144 /** 145 * Creates a command line. 146 */ 147 protected CommandLine() { 148 this(new LinkedList<>(), new ArrayList<>(), Builder.DEPRECATED_HANDLER); 149 } 150 151 /** 152 * Creates a command line. 153 */ 154 private CommandLine(final List<String> args, final List<Option> options, final Consumer<Option> deprecatedHandler) { 155 this.args = Objects.requireNonNull(args, "args"); 156 this.options = Objects.requireNonNull(options, "options"); 157 this.deprecatedHandler = deprecatedHandler; 158 } 159 160 /** 161 * Adds left-over unrecognized option/argument. 162 * 163 * @param arg the unrecognized option/argument. 164 */ 165 protected void addArg(final String arg) { 166 if (arg != null) { 167 args.add(arg); 168 } 169 } 170 171 /** 172 * Adds an option to the command line. The values of the option are stored. 173 * 174 * @param opt the processed option. 175 */ 176 protected void addOption(final Option opt) { 177 if (opt != null) { 178 options.add(opt); 179 } 180 } 181 182 private <T> T get(final Supplier<T> supplier) { 183 return supplier == null ? null : supplier.get(); 184 } 185 186 /** 187 * Gets any left-over non-recognized options and arguments 188 * 189 * @return remaining items passed in but not parsed as a {@code List}. 190 */ 191 public List<String> getArgList() { 192 return args; 193 } 194 195 /** 196 * Gets any left-over non-recognized options and arguments 197 * 198 * @return remaining items passed in but not parsed as an array. 199 */ 200 public String[] getArgs() { 201 return args.toArray(Util.EMPTY_STRING_ARRAY); 202 } 203 204 /** 205 * Gets the {@code Object} type of this {@code Option}. 206 * 207 * @deprecated due to System.err message. Instead use getParsedOptionValue(char) 208 * @param opt the name of the option. 209 * @return the type of opt. 210 */ 211 @Deprecated 212 public Object getOptionObject(final char opt) { 213 return getOptionObject(String.valueOf(opt)); 214 } 215 216 /** 217 * Gets the {@code Object} type of this {@code Option}. 218 * 219 * @param opt the name of the option. 220 * @return the type of this {@code Option}. 221 * @deprecated due to System.err message. Instead use getParsedOptionValue(String) 222 */ 223 @Deprecated 224 public Object getOptionObject(final String opt) { 225 try { 226 return getParsedOptionValue(opt); 227 } catch (final ParseException pe) { 228 System.err.println("Exception found converting " + opt + " to desired type: " + pe.getMessage()); 229 return null; 230 } 231 } 232 233 /** 234 * Gets the map of values associated to the option. This is convenient for options specifying Java properties like 235 * <code>-Dparam1=value1 236 * -Dparam2=value2</code>. All odd numbered values are property keys 237 * and even numbered values are property values. If there are an odd number of values 238 * the last value is assumed to be a boolean flag and the value is "true". 239 * 240 * @param option name of the option. 241 * @return The Properties mapped by the option, never {@code null} even if the option doesn't exists. 242 * @since 1.5.0 243 */ 244 public Properties getOptionProperties(final Option option) { 245 final Properties props = new Properties(); 246 for (final Option processedOption : options) { 247 if (processedOption.equals(option)) { 248 processPropertiesFromValues(props, processedOption.getValuesList()); 249 } 250 } 251 return props; 252 } 253 254 /** 255 * Gets the map of values associated to the option. This is convenient for options specifying Java properties like 256 * <code>-Dparam1=value1 257 * -Dparam2=value2</code>. The first argument of the option is the key, and the 2nd argument is the value. If the option 258 * has only one argument ({@code -Dfoo}) it is considered as a boolean flag and the value is {@code "true"}. 259 * 260 * @param opt name of the option. 261 * @return The Properties mapped by the option, never {@code null} even if the option doesn't exists. 262 * @since 1.2 263 */ 264 public Properties getOptionProperties(final String opt) { 265 final Properties props = new Properties(); 266 for (final Option option : options) { 267 if (opt.equals(option.getOpt()) || opt.equals(option.getLongOpt())) { 268 processPropertiesFromValues(props, option.getValuesList()); 269 } 270 } 271 return props; 272 } 273 274 /** 275 * Gets an array of the processed {@link Option}s. 276 * 277 * @return an array of the processed {@link Option}s. 278 */ 279 public Option[] getOptions() { 280 return options.toArray(Option.EMPTY_ARRAY); 281 } 282 283 /** 284 * Gets the first argument, if any, of this option. 285 * 286 * @param opt the character name of the option. 287 * @return Value of the argument if option is set, and has an argument, otherwise null. 288 */ 289 public String getOptionValue(final char opt) { 290 return getOptionValue(String.valueOf(opt)); 291 } 292 293 /** 294 * Gets the argument, if any, of an option. 295 * 296 * @param opt character name of the option 297 * @param defaultValue is the default value to be returned if the option is not specified. 298 * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}. 299 */ 300 public String getOptionValue(final char opt, final String defaultValue) { 301 return getOptionValue(String.valueOf(opt), () -> defaultValue); 302 } 303 304 /** 305 * Gets the argument, if any, of an option. 306 * 307 * @param opt character name of the option 308 * @param defaultValue is a supplier for the default value to be returned if the option is not specified. 309 * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}. 310 * @since 1.7.0 311 */ 312 public String getOptionValue(final char opt, final Supplier<String> defaultValue) { 313 return getOptionValue(String.valueOf(opt), defaultValue); 314 } 315 316 /** 317 * Gets the first argument, if any, of this option. 318 * 319 * @param option the name of the option. 320 * @return Value of the argument if option is set, and has an argument, otherwise null. 321 * @since 1.5.0 322 */ 323 public String getOptionValue(final Option option) { 324 final String[] values = getOptionValues(option); 325 return values == null ? null : values[0]; 326 } 327 328 /** 329 * Gets the first argument, if any, of an option. 330 * 331 * @param option name of the option. 332 * @param defaultValue is the default value to be returned if the option is not specified. 333 * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}. 334 * @since 1.5.0 335 */ 336 public String getOptionValue(final Option option, final String defaultValue) { 337 return getOptionValue(option, () -> defaultValue); 338 } 339 340 /** 341 * Gets the first argument, if any, of an option. 342 * 343 * @param option name of the option. 344 * @param defaultValue is a supplier for the default value to be returned if the option is not specified. 345 * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}. 346 * @since 1.7.0 347 */ 348 public String getOptionValue(final Option option, final Supplier<String> defaultValue) { 349 final String answer = getOptionValue(option); 350 return answer != null ? answer : get(defaultValue); 351 } 352 353 /** 354 * Gets the first argument, if any, of this option. 355 * 356 * @param opt the name of the option. 357 * @return Value of the argument if option is set, and has an argument, otherwise null. 358 */ 359 public String getOptionValue(final String opt) { 360 return getOptionValue(resolveOption(opt)); 361 } 362 363 /** 364 * Gets the first argument, if any, of an option. 365 * 366 * @param opt name of the option. 367 * @param defaultValue is the default value to be returned if the option is not specified. 368 * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}. 369 */ 370 public String getOptionValue(final String opt, final String defaultValue) { 371 return getOptionValue(resolveOption(opt), () -> defaultValue); 372 } 373 374 /** 375 * Gets the first argument, if any, of an option. 376 * 377 * @param opt name of the option. 378 * @param defaultValue is a supplier for the default value to be returned if the option is not specified. 379 * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}. 380 * @since 1.7.0 381 */ 382 public String getOptionValue(final String opt, final Supplier<String> defaultValue) { 383 return getOptionValue(resolveOption(opt), defaultValue); 384 } 385 386 387 /** 388 * Gets the array of values, if any, of an option. 389 * 390 * @param opt character name of the option. 391 * @return Values of the argument if option is set, and has an argument, otherwise null. 392 */ 393 public String[] getOptionValues(final char opt) { 394 return getOptionValues(String.valueOf(opt)); 395 } 396 397 /** 398 * Gets the array of values, if any, of an option. 399 * 400 * @param option string name of the option. 401 * @return Values of the argument if option is set, and has an argument, otherwise null. 402 * @since 1.5.0 403 */ 404 public String[] getOptionValues(final Option option) { 405 if (option == null) { 406 return null; 407 } 408 final List<String> values = new ArrayList<>(); 409 for (final Option processedOption : options) { 410 if (processedOption.equals(option)) { 411 values.addAll(processedOption.getValuesList()); 412 } 413 } 414 return values.isEmpty() ? null : values.toArray(EMPTY_STRING_ARRAY); 415 } 416 417 /** 418 * Gets the array of values, if any, of an option. 419 * 420 * @param opt string name of the option. 421 * @return Values of the argument if option is set, and has an argument, otherwise null. 422 */ 423 public String[] getOptionValues(final String opt) { 424 return getOptionValues(resolveOption(opt)); 425 } 426 427 /** 428 * Gets a version of this {@code Option} converted to a particular type. 429 * 430 * @param opt the name of the option. 431 * @param <T> The return type for the method. 432 * @return the value parsed into a particular object. 433 * @throws ParseException if there are problems turning the option value into the desired type 434 * @see PatternOptionBuilder 435 * @since 1.5.0 436 */ 437 public <T> T getParsedOptionValue(final char opt) throws ParseException { 438 return getParsedOptionValue(String.valueOf(opt)); 439 } 440 441 /** 442 * Gets a version of this {@code Option} converted to a particular type. 443 * 444 * @param opt the name of the option. 445 * @param defaultValue the default value to return if opt is not set. 446 * @param <T> The return type for the method. 447 * @return the value parsed into a particular object. 448 * @throws ParseException if there are problems turning the option value into the desired type 449 * @see PatternOptionBuilder 450 * @since 1.7.0 451 */ 452 public <T> T getParsedOptionValue(final char opt, final Supplier<T> defaultValue) throws ParseException { 453 return getParsedOptionValue(String.valueOf(opt), defaultValue); 454 } 455 456 /** 457 * Gets a version of this {@code Option} converted to a particular type. 458 * 459 * @param opt the name of the option. 460 * @param defaultValue the default value to return if opt is not set. 461 * @param <T> The return type for the method. 462 * @return the value parsed into a particular object. 463 * @throws ParseException if there are problems turning the option value into the desired type 464 * @see PatternOptionBuilder 465 * @since 1.7.0 466 */ 467 public <T> T getParsedOptionValue(final char opt, final T defaultValue) throws ParseException { 468 return getParsedOptionValue(String.valueOf(opt), defaultValue); 469 } 470 471 /** 472 * Gets a version of this {@code Option} converted to a particular type. 473 * 474 * @param option the name of the option. 475 * @param <T> The return type for the method. 476 * @return the value parsed into a particular object. 477 * @throws ParseException if there are problems turning the option value into the desired type 478 * @see PatternOptionBuilder 479 * @since 1.5.0 480 */ 481 public <T> T getParsedOptionValue(final Option option) throws ParseException { 482 return getParsedOptionValue(option, () -> null); 483 } 484 485 /** 486 * Gets a version of this {@code Option} converted to a particular type. 487 * 488 * @param option the name of the option. 489 * @param defaultValue the default value to return if opt is not set. 490 * @param <T> The return type for the method. 491 * @return the value parsed into a particular object. 492 * @throws ParseException if there are problems turning the option value into the desired type 493 * @see PatternOptionBuilder 494 * @since 1.7.0 495 */ 496 @SuppressWarnings("unchecked") 497 public <T> T getParsedOptionValue(final Option option, final Supplier<T> defaultValue) throws ParseException { 498 if (option == null) { 499 return get(defaultValue); 500 } 501 final String res = getOptionValue(option); 502 try { 503 if (res == null) { 504 return get(defaultValue); 505 } 506 return (T) option.getConverter().apply(res); 507 } catch (final Throwable e) { 508 throw ParseException.wrap(e); 509 } 510 } 511 512 /** 513 * Gets a version of this {@code Option} converted to a particular type. 514 * 515 * @param option the name of the option. 516 * @param defaultValue the default value to return if opt is not set. 517 * @param <T> The return type for the method. 518 * @return the value parsed into a particular object. 519 * @throws ParseException if there are problems turning the option value into the desired type 520 * @see PatternOptionBuilder 521 * @since 1.7.0 522 */ 523 public <T> T getParsedOptionValue(final Option option, final T defaultValue) throws ParseException { 524 return getParsedOptionValue(option, () -> defaultValue); 525 } 526 527 /** 528 * Gets a version of this {@code Option} converted to a particular type. 529 * 530 * @param opt the name of the option. 531 * @param <T> The return type for the method. 532 * @return the value parsed into a particular object. 533 * @throws ParseException if there are problems turning the option value into the desired type 534 * @see PatternOptionBuilder 535 * @since 1.2 536 */ 537 public <T> T getParsedOptionValue(final String opt) throws ParseException { 538 return getParsedOptionValue(resolveOption(opt)); 539 } 540 541 /** 542 * Gets a version of this {@code Option} converted to a particular type. 543 * 544 * @param opt the name of the option. 545 * @param defaultValue the default value to return if opt is not set. 546 * @param <T> The return type for the method. 547 * @return the value parsed into a particular object. 548 * @throws ParseException if there are problems turning the option value into the desired type 549 * @see PatternOptionBuilder 550 * @since 1.7.0 551 */ 552 public <T> T getParsedOptionValue(final String opt, final Supplier<T> defaultValue) throws ParseException { 553 return getParsedOptionValue(resolveOption(opt), defaultValue); 554 } 555 556 /** 557 * Gets a version of this {@code Option} converted to a particular type. 558 * 559 * @param opt the name of the option. 560 * @param defaultValue the default value to return if opt is not set. 561 * @param <T> The return type for the method. 562 * @return the value parsed into a particular object. 563 * @throws ParseException if there are problems turning the option value into the desired type 564 * @see PatternOptionBuilder 565 * @since 1.7.0 566 */ 567 public <T> T getParsedOptionValue(final String opt, final T defaultValue) throws ParseException { 568 return getParsedOptionValue(resolveOption(opt), defaultValue); 569 } 570 571 /** 572 * Handles deprecated options. 573 * 574 * @param option a deprecated option. 575 */ 576 private void handleDeprecated(final Option option) { 577 if (deprecatedHandler != null) { 578 deprecatedHandler.accept(option); 579 } 580 } 581 582 /** 583 * jkeyes - commented out until it is implemented properly 584 * <p> 585 * Dump state, suitable for debugging. 586 * </p> 587 * 588 * @return Stringified form of this object. 589 */ 590 591 /* 592 * public String toString() { StringBuilder buf = new StringBuilder(); 593 * 594 * buf.append("[ CommandLine: [ options: "); buf.append(options.toString()); buf.append(" ] [ args: "); 595 * buf.append(args.toString()); buf.append(" ] ]"); 596 * 597 * return buf.toString(); } 598 */ 599 600 /** 601 * Tests to see if an option has been set. 602 * 603 * @param opt character name of the option. 604 * @return true if set, false if not. 605 */ 606 public boolean hasOption(final char opt) { 607 return hasOption(String.valueOf(opt)); 608 } 609 610 /** 611 * Tests to see if an option has been set. 612 * 613 * @param opt the option to check. 614 * @return true if set, false if not. 615 * @since 1.5.0 616 */ 617 public boolean hasOption(final Option opt) { 618 return options.contains(opt); 619 } 620 621 /** 622 * Tests to see if an option has been set. 623 * 624 * @param opt Short name of the option. 625 * @return true if set, false if not. 626 */ 627 public boolean hasOption(final String opt) { 628 return hasOption(resolveOption(opt)); 629 } 630 631 /** 632 * Returns an iterator over the Option members of CommandLine. 633 * 634 * @return an {@code Iterator} over the processed {@link Option} members of this {@link CommandLine}. 635 */ 636 public Iterator<Option> iterator() { 637 return options.iterator(); 638 } 639 640 /** 641 * Parses a list of values as properties. All odd numbered values are property keys 642 * and even numbered values are property values. If there are an odd number of values 643 * the last value is assumed to be a boolean with a value of "true". 644 * @param props the properties to update. 645 * @param values the list of values to parse. 646 */ 647 private void processPropertiesFromValues(final Properties props, final List<String> values) { 648 for (int i = 0; i < values.size(); i += 2) { 649 if (i + 1 < values.size()) { 650 props.put(values.get(i), values.get(i + 1)); 651 } else { 652 props.put(values.get(i), "true"); 653 } 654 } 655 } 656 657 /** 658 * Retrieves the option object given the long or short option as a String 659 * 660 * @param opt short or long name of the option, may be null. 661 * @return Canonicalized option. 662 */ 663 private Option resolveOption(final String opt) { 664 final String actual = Util.stripLeadingHyphens(opt); 665 if (actual != null) { 666 for (final Option option : options) { 667 if (actual.equals(option.getOpt()) || actual.equals(option.getLongOpt())) { 668 if (option.isDeprecated()) { 669 handleDeprecated(option); 670 } 671 return option; 672 } 673 } 674 } 675 return null; 676 } 677 }