001/* 002 * Copyright 2008-2019 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2008-2019 Ping Identity Corporation 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU General Public License (GPLv2 only) 010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 011 * as published by the Free Software Foundation. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Public License for more details. 017 * 018 * You should have received a copy of the GNU General Public License 019 * along with this program; if not, see <http://www.gnu.org/licenses>. 020 */ 021package com.unboundid.util.args; 022 023 024 025import java.io.Serializable; 026 027import java.util.ArrayList; 028import java.util.Collections; 029import java.util.Iterator; 030import java.util.LinkedHashMap; 031import java.util.List; 032import java.util.Map; 033 034import com.unboundid.util.LDAPSDKUsageException; 035import com.unboundid.util.Mutable; 036import com.unboundid.util.NotExtensible; 037import com.unboundid.util.StaticUtils; 038import com.unboundid.util.ThreadSafety; 039import com.unboundid.util.ThreadSafetyLevel; 040 041import static com.unboundid.util.args.ArgsMessages.*; 042 043 044 045/** 046 * This class defines a generic command line argument, which provides 047 * functionality applicable to all argument types. Subclasses may enforce 048 * additional constraints or provide additional functionality. 049 */ 050@NotExtensible() 051@Mutable() 052@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) 053public abstract class Argument 054 implements Serializable 055{ 056 /** 057 * The serial version UID for this serializable class. 058 */ 059 private static final long serialVersionUID = -6938320885602903919L; 060 061 062 063 // Indicates whether this argument should be excluded from usage information. 064 private boolean isHidden; 065 066 // Indicates whether this argument has been registered with the argument 067 // parser. 068 private boolean isRegistered; 069 070 // Indicates whether this argument is required to be present. 071 private final boolean isRequired; 072 073 // Indicates whether values of this argument should be considered sensitive. 074 private boolean isSensitive; 075 076 // Indicates whether this argument is used to display usage information. 077 private boolean isUsageArgument; 078 079 // The maximum number of times this argument is allowed to be provided. 080 private int maxOccurrences; 081 082 // The number of times this argument was included in the provided command line 083 // arguments. 084 private int numOccurrences; 085 086 // The set of short identifiers for this argument, associated with an 087 // indication as to whether the identifier should be hidden. 088 private final Map<Character,Boolean> shortIdentifiers; 089 090 // The set of long identifiers for this argument, associated with an 091 // indication as to whether the identifier should be hidden. 092 private final Map<String,Boolean> longIdentifiers; 093 094 // The argument group name for this argument, if any. 095 private String argumentGroupName; 096 097 // The description for this argument. 098 private final String description; 099 100 // The value placeholder for this argument, or {@code null} if it does not 101 // take a value. 102 private final String valuePlaceholder; 103 104 105 106 /** 107 * Creates a new argument with the provided information. 108 * 109 * @param shortIdentifier The short identifier for this argument. It may 110 * not be {@code null} if the long identifier is 111 * {@code null}. 112 * @param longIdentifier The long identifier for this argument. It may 113 * not be {@code null} if the short identifier is 114 * {@code null}. 115 * @param isRequired Indicates whether this argument is required to 116 * be provided. 117 * @param maxOccurrences The maximum number of times this argument may be 118 * provided on the command line. A value less than 119 * or equal to zero indicates that it may be present 120 * any number of times. 121 * @param valuePlaceholder A placeholder to display in usage information to 122 * indicate that a value must be provided. If this 123 * is {@code null}, then the argument will not be 124 * allowed to take a value. If it is not 125 * {@code null}, then the argument will be required 126 * to take a value. 127 * @param description A human-readable description for this argument. 128 * It must not be {@code null}. 129 * 130 * @throws ArgumentException If there is a problem with the definition of 131 * this argument. 132 */ 133 protected Argument(final Character shortIdentifier, 134 final String longIdentifier, 135 final boolean isRequired, final int maxOccurrences, 136 final String valuePlaceholder, final String description) 137 throws ArgumentException 138 { 139 if (description == null) 140 { 141 throw new ArgumentException(ERR_ARG_DESCRIPTION_NULL.get()); 142 } 143 144 if ((shortIdentifier == null) && (longIdentifier == null)) 145 { 146 throw new ArgumentException(ERR_ARG_NO_IDENTIFIERS.get()); 147 } 148 149 shortIdentifiers = new LinkedHashMap<>(StaticUtils.computeMapCapacity(5)); 150 if (shortIdentifier != null) 151 { 152 shortIdentifiers.put(shortIdentifier, false); 153 } 154 155 longIdentifiers = new LinkedHashMap<>(StaticUtils.computeMapCapacity(5)); 156 if (longIdentifier != null) 157 { 158 longIdentifiers.put(longIdentifier, false); 159 } 160 161 this.isRequired = isRequired; 162 this.valuePlaceholder = valuePlaceholder; 163 this.description = description; 164 165 if (maxOccurrences > 0) 166 { 167 this.maxOccurrences = maxOccurrences; 168 } 169 else 170 { 171 this.maxOccurrences = Integer.MAX_VALUE; 172 } 173 174 argumentGroupName = null; 175 numOccurrences = 0; 176 isHidden = false; 177 isRegistered = false; 178 isSensitive = false; 179 isUsageArgument = false; 180 } 181 182 183 184 /** 185 * Creates a new argument with the same generic information as the provided 186 * argument. It will not be registered with any argument parser. 187 * 188 * @param source The argument to use as the source for this argument. 189 */ 190 protected Argument(final Argument source) 191 { 192 argumentGroupName = source.argumentGroupName; 193 isHidden = source.isHidden; 194 isRequired = source.isRequired; 195 isSensitive = source.isSensitive; 196 isUsageArgument = source.isUsageArgument; 197 maxOccurrences = source.maxOccurrences; 198 description = source.description; 199 valuePlaceholder = source.valuePlaceholder; 200 201 isRegistered = false; 202 numOccurrences = 0; 203 204 shortIdentifiers = new LinkedHashMap<>(source.shortIdentifiers); 205 longIdentifiers = new LinkedHashMap<>(source.longIdentifiers); 206 } 207 208 209 210 /** 211 * Indicates whether this argument has a short identifier. 212 * 213 * @return {@code true} if it has a short identifier, or {@code false} if 214 * not. 215 */ 216 public final boolean hasShortIdentifier() 217 { 218 return (! shortIdentifiers.isEmpty()); 219 } 220 221 222 223 /** 224 * Retrieves the short identifier for this argument. If there is more than 225 * one, then the first will be returned. 226 * 227 * @return The short identifier for this argument, or {@code null} if none is 228 * defined. 229 */ 230 public final Character getShortIdentifier() 231 { 232 for (final Map.Entry<Character,Boolean> e : shortIdentifiers.entrySet()) 233 { 234 if (e.getValue()) 235 { 236 continue; 237 } 238 239 return e.getKey(); 240 } 241 242 return null; 243 } 244 245 246 247 /** 248 * Retrieves the list of all short identifiers, including hidden identifiers, 249 * for this argument. 250 * 251 * @return The list of all short identifiers for this argument, or an empty 252 * list if there are no short identifiers. 253 */ 254 public final List<Character> getShortIdentifiers() 255 { 256 return getShortIdentifiers(true); 257 } 258 259 260 261 /** 262 * Retrieves the list of short identifiers for this argument. 263 * 264 * @param includeHidden Indicates whether to include hidden identifiers in 265 * the list that is returned. 266 * 267 * @return The list of short identifiers for this argument, or an empty list 268 * if there are none. 269 */ 270 public final List<Character> getShortIdentifiers(final boolean includeHidden) 271 { 272 final ArrayList<Character> identifierList = 273 new ArrayList<>(shortIdentifiers.size()); 274 for (final Map.Entry<Character,Boolean> e : shortIdentifiers.entrySet()) 275 { 276 if (includeHidden || (! e.getValue())) 277 { 278 identifierList.add(e.getKey()); 279 } 280 } 281 282 return Collections.unmodifiableList(identifierList); 283 } 284 285 286 287 /** 288 * Adds the provided character to the set of short identifiers for this 289 * argument. It will not be hidden. Note that this must be called before 290 * this argument is registered with the argument parser. 291 * 292 * @param c The character to add to the set of short identifiers for this 293 * argument. It must not be {@code null}. 294 * 295 * @throws ArgumentException If this argument is already registered with the 296 * argument parser. 297 */ 298 public final void addShortIdentifier(final Character c) 299 throws ArgumentException 300 { 301 addShortIdentifier(c, false); 302 } 303 304 305 306 /** 307 * Adds the provided character to the set of short identifiers for this 308 * argument. Note that this must be called before this argument is registered 309 * with the argument parser. 310 * 311 * @param c The character to add to the set of short identifiers for 312 * this argument. It must not be {@code null}. 313 * @param isHidden Indicates whether the provided identifier should be 314 * hidden. If this is {@code true}, then the identifier can 315 * be used to target this argument on the command line, but 316 * it will not be included in usage information. 317 * 318 * @throws ArgumentException If this argument is already registered with the 319 * argument parser. 320 */ 321 public final void addShortIdentifier(final Character c, 322 final boolean isHidden) 323 throws ArgumentException 324 { 325 if (isRegistered) 326 { 327 throw new ArgumentException(ERR_ARG_ID_CHANGE_AFTER_REGISTERED.get( 328 getIdentifierString())); 329 } 330 331 shortIdentifiers.put(c, isHidden); 332 } 333 334 335 336 /** 337 * Indicates whether this argument has a long identifier. 338 * 339 * @return {@code true} if it has a long identifier, or {@code false} if 340 * not. 341 */ 342 public final boolean hasLongIdentifier() 343 { 344 return (! longIdentifiers.isEmpty()); 345 } 346 347 348 349 /** 350 * Retrieves the long identifier for this argument. If it has multiple long 351 * identifiers, then the first will be returned. 352 * 353 * @return The long identifier for this argument, or {@code null} if none is 354 * defined. 355 */ 356 public final String getLongIdentifier() 357 { 358 for (final Map.Entry<String,Boolean> e : longIdentifiers.entrySet()) 359 { 360 if (e.getValue()) 361 { 362 continue; 363 } 364 365 return e.getKey(); 366 } 367 368 return null; 369 } 370 371 372 373 /** 374 * Retrieves the list of all long identifiers, including hidden identifiers, 375 * for this argument. 376 * 377 * @return The list of all long identifiers for this argument, or an empty 378 * list if there are no long identifiers. 379 */ 380 public final List<String> getLongIdentifiers() 381 { 382 return getLongIdentifiers(true); 383 } 384 385 386 387 /** 388 * Retrieves the list of long identifiers for this argument. 389 * 390 * @param includeHidden Indicates whether to include hidden identifiers in 391 * the list that is returned. 392 * 393 * @return The long identifier for this argument, or an empty list if there 394 * are none. 395 */ 396 public final List<String> getLongIdentifiers(final boolean includeHidden) 397 { 398 final ArrayList<String> identifierList = 399 new ArrayList<>(longIdentifiers.size()); 400 for (final Map.Entry<String,Boolean> e : longIdentifiers.entrySet()) 401 { 402 if (includeHidden || (! e.getValue())) 403 { 404 identifierList.add(e.getKey()); 405 } 406 } 407 408 return Collections.unmodifiableList(identifierList); 409 } 410 411 412 413 /** 414 * Adds the provided string to the set of short identifiers for this argument. 415 * It will not be hidden. Note that this must be called before this argument 416 * is registered with the argument parser. 417 * 418 * @param s The string to add to the set of short identifiers for this 419 * argument. It must not be {@code null}. 420 * 421 * @throws ArgumentException If this argument is already registered with the 422 * argument parser. 423 */ 424 public final void addLongIdentifier(final String s) 425 throws ArgumentException 426 { 427 addLongIdentifier(s, false); 428 } 429 430 431 432 /** 433 * Adds the provided string to the set of short identifiers for this argument. 434 * Note that this must be called before this argument is registered with the 435 * argument parser. 436 * 437 * @param s The string to add to the set of short identifiers for 438 * this argument. It must not be {@code null}. 439 * @param isHidden Indicates whether the provided identifier should be 440 * hidden. If this is {@code true}, then the identifier can 441 * be used to target this argument on the command line, but 442 * it will not be included in usage information. 443 * 444 * @throws ArgumentException If this argument is already registered with the 445 * argument parser. 446 */ 447 public final void addLongIdentifier(final String s, final boolean isHidden) 448 throws ArgumentException 449 { 450 if (isRegistered) 451 { 452 throw new ArgumentException(ERR_ARG_ID_CHANGE_AFTER_REGISTERED.get( 453 getIdentifierString())); 454 } 455 456 longIdentifiers.put(s, isHidden); 457 } 458 459 460 461 /** 462 * Retrieves a string that may be used to identify this argument. If a long 463 * identifier is defined, then the value returned will be two dashes followed 464 * by that string. Otherwise, the value returned will be a single dash 465 * followed by the short identifier. 466 * 467 * @return A string that may be used to identify this argument. 468 */ 469 public final String getIdentifierString() 470 { 471 for (final Map.Entry<String,Boolean> e : longIdentifiers.entrySet()) 472 { 473 if (! e.getValue()) 474 { 475 return "--" + e.getKey(); 476 } 477 } 478 479 for (final Map.Entry<Character,Boolean> e : shortIdentifiers.entrySet()) 480 { 481 if (! e.getValue()) 482 { 483 return "-" + e.getKey(); 484 } 485 } 486 487 // This should never happen. 488 throw new LDAPSDKUsageException( 489 ERR_ARG_NO_NON_HIDDEN_IDENTIFIER.get(toString())); 490 } 491 492 493 494 /** 495 * Indicates whether this argument is required to be provided. 496 * 497 * @return {@code true} if this argument is required to be provided, or 498 * {@code false} if not. 499 */ 500 public final boolean isRequired() 501 { 502 return isRequired; 503 } 504 505 506 507 /** 508 * Retrieves the maximum number of times that this argument may be provided. 509 * 510 * @return The maximum number of times that this argument may be provided. 511 */ 512 public final int getMaxOccurrences() 513 { 514 return maxOccurrences; 515 } 516 517 518 519 /** 520 * Specifies the maximum number of times that this argument may be provided. 521 * 522 * @param maxOccurrences The maximum number of times that this argument 523 * may be provided. A value less than or equal to 524 * zero indicates that there should be no limit on the 525 * maximum number of occurrences. 526 */ 527 public final void setMaxOccurrences(final int maxOccurrences) 528 { 529 if (maxOccurrences <= 0) 530 { 531 this.maxOccurrences = Integer.MAX_VALUE; 532 } 533 else 534 { 535 this.maxOccurrences = maxOccurrences; 536 } 537 } 538 539 540 541 /** 542 * Indicates whether this argument takes a value. 543 * 544 * @return {@code true} if this argument takes a value, or {@code false} if 545 * not. 546 */ 547 public boolean takesValue() 548 { 549 return (valuePlaceholder != null); 550 } 551 552 553 554 /** 555 * Retrieves the value placeholder string for this argument. 556 * 557 * @return The value placeholder string for this argument, or {@code null} if 558 * it does not take a value. 559 */ 560 public final String getValuePlaceholder() 561 { 562 return valuePlaceholder; 563 } 564 565 566 567 /** 568 * Retrieves a list containing the string representations of the values for 569 * this argument, if any. The list returned does not necessarily need to 570 * include values that will be acceptable to the argument, but it should imply 571 * what the values are (e.g., in the case of a boolean argument that doesn't 572 * take a value, it may be the string "true" or "false" even if those values 573 * are not acceptable to the argument itself). 574 * 575 * @param useDefault Indicates whether to use any configured default value 576 * if the argument doesn't have a user-specified value. 577 * 578 * @return A string representation of the value for this argument, or an 579 * empty list if the argument does not have a value. 580 */ 581 public abstract List<String> getValueStringRepresentations( 582 boolean useDefault); 583 584 585 586 /** 587 * Retrieves the description for this argument. 588 * 589 * @return The description for this argument. 590 */ 591 public final String getDescription() 592 { 593 return description; 594 } 595 596 597 598 /** 599 * Retrieves the name of the argument group to which this argument belongs. 600 * 601 * @return The name of the argument group to which this argument belongs, or 602 * {@code null} if this argument has not been assigned to any group. 603 */ 604 public final String getArgumentGroupName() 605 { 606 return argumentGroupName; 607 } 608 609 610 611 /** 612 * Sets the name of the argument group to which this argument belongs. If 613 * a tool updates arguments to specify an argument group for some or all of 614 * the arguments, then the usage information will have the arguments listed 615 * together in their respective groups. Note that usage arguments should 616 * generally not be assigned to an argument group. 617 * 618 * @param argumentGroupName The argument group name for this argument. It 619 * may be {@code null} if this argument should not 620 * be assigned to any particular group. 621 */ 622 public final void setArgumentGroupName(final String argumentGroupName) 623 { 624 this.argumentGroupName = argumentGroupName; 625 } 626 627 628 629 /** 630 * Indicates whether this argument should be excluded from usage information. 631 * 632 * @return {@code true} if this argument should be excluded from usage 633 * information, or {@code false} if not. 634 */ 635 public final boolean isHidden() 636 { 637 return isHidden; 638 } 639 640 641 642 /** 643 * Specifies whether this argument should be excluded from usage information. 644 * 645 * @param isHidden Specifies whether this argument should be excluded from 646 * usage information. 647 */ 648 public final void setHidden(final boolean isHidden) 649 { 650 this.isHidden = isHidden; 651 } 652 653 654 655 /** 656 * Indicates whether this argument is intended to be used to trigger the 657 * display of usage information. If a usage argument is provided on the 658 * command line, then the argument parser will not complain about missing 659 * required arguments or unresolved dependencies. 660 * 661 * @return {@code true} if this argument is a usage argument, or 662 * {@code false} if not. 663 */ 664 public final boolean isUsageArgument() 665 { 666 return isUsageArgument; 667 } 668 669 670 671 /** 672 * Specifies whether this argument should be considered a usage argument. 673 * 674 * @param isUsageArgument Specifies whether this argument should be 675 * considered a usage argument. 676 */ 677 public final void setUsageArgument(final boolean isUsageArgument) 678 { 679 this.isUsageArgument = isUsageArgument; 680 } 681 682 683 684 /** 685 * Indicates whether this argument was either included in the provided set of 686 * command line arguments or has a default value that can be used instead. 687 * This method should not be called until after the argument parser has 688 * processed the provided set of arguments. 689 * 690 * @return {@code true} if this argument was included in the provided set of 691 * command line arguments, or {@code false} if not. 692 */ 693 public final boolean isPresent() 694 { 695 return ((numOccurrences > 0) || hasDefaultValue()); 696 } 697 698 699 700 /** 701 * Retrieves the number of times that this argument was included in the 702 * provided set of command line arguments. This method should not be called 703 * until after the argument parser has processed the provided set of 704 * arguments. 705 * 706 * @return The number of times that this argument was included in the 707 * provided set of command line arguments. 708 */ 709 public final int getNumOccurrences() 710 { 711 return numOccurrences; 712 } 713 714 715 716 /** 717 * Increments the number of occurrences for this argument in the provided set 718 * of command line arguments. This method should only be called by the 719 * argument parser. 720 * 721 * @throws ArgumentException If incrementing the number of occurrences would 722 * exceed the maximum allowed number. 723 */ 724 final void incrementOccurrences() 725 throws ArgumentException 726 { 727 if (numOccurrences >= maxOccurrences) 728 { 729 throw new ArgumentException(ERR_ARG_MAX_OCCURRENCES_EXCEEDED.get( 730 getIdentifierString())); 731 } 732 733 numOccurrences++; 734 } 735 736 737 738 /** 739 * Adds the provided value to the set of values for this argument. This 740 * method should only be called by the argument parser. 741 * 742 * @param valueString The string representation of the value. 743 * 744 * @throws ArgumentException If the provided value is not acceptable, if 745 * this argument does not accept values, or if 746 * this argument already has the maximum allowed 747 * number of values. 748 */ 749 protected abstract void addValue(String valueString) 750 throws ArgumentException; 751 752 753 754 /** 755 * Indicates whether this argument has one or more default values that will be 756 * used if it is not provided on the command line. 757 * 758 * @return {@code true} if this argument has one or more default values, or 759 * {@code false} if not. 760 */ 761 protected abstract boolean hasDefaultValue(); 762 763 764 765 /** 766 * Indicates whether values of this argument are considered sensitive. 767 * Argument values that are considered sensitive will be obscured in places 768 * where they may be shown. 769 * 770 * @return {@code true} if values of this argument are considered sensitive, 771 * or {@code false} if not. 772 */ 773 public final boolean isSensitive() 774 { 775 return isSensitive; 776 } 777 778 779 780 /** 781 * Specifies whether values of this argument are considered sensitive. 782 * Argument values that are considered sensitive will be obscured in places 783 * where they may be shown. 784 * 785 * @param isSensitive Indicates whether values of this argument are 786 * considered sensitive. 787 */ 788 public final void setSensitive(final boolean isSensitive) 789 { 790 this.isSensitive = isSensitive; 791 } 792 793 794 795 /** 796 * Indicates whether this argument has been registered with the argument 797 * parser. 798 * 799 * @return {@code true} if this argument has been registered with the 800 * argument parser, or {@code false} if not. 801 */ 802 boolean isRegistered() 803 { 804 return isRegistered; 805 } 806 807 808 809 /** 810 * Specifies that this argument has been registered with the argument parser. 811 * This method should only be called by the argument parser method used to 812 * register the argument. 813 * 814 * @throws ArgumentException If this argument has already been registered. 815 */ 816 void setRegistered() 817 throws ArgumentException 818 { 819 if (isRegistered) 820 { 821 throw new ArgumentException(ERR_ARG_ALREADY_REGISTERED.get( 822 getIdentifierString())); 823 } 824 825 isRegistered = true; 826 } 827 828 829 830 /** 831 * Retrieves a concise name of the data type with which this argument is 832 * associated. 833 * 834 * @return A concise name of the data type with which this argument is 835 * associated. 836 */ 837 public abstract String getDataTypeName(); 838 839 840 841 /** 842 * Retrieves a human-readable string with information about any constraints 843 * that may be imposed for values of this argument. 844 * 845 * @return A human-readable string with information about any constraints 846 * that may be imposed for values of this argument, or {@code null} 847 * if there are none. 848 */ 849 public String getValueConstraints() 850 { 851 return null; 852 } 853 854 855 856 /** 857 * Resets this argument so that it appears in the same form as before it was 858 * used to parse arguments. Subclasses that override this method must call 859 * {@code super.reset()} to ensure that all necessary reset processing is 860 * performed. 861 */ 862 protected void reset() 863 { 864 numOccurrences = 0; 865 } 866 867 868 869 /** 870 * Creates a copy of this argument that is "clean" and appears as if it has 871 * not been used in the course of parsing an argument set. The new argument 872 * will have all of the same identifiers and constraints as this parser. 873 * 874 * @return The "clean" copy of this argument. 875 */ 876 public abstract Argument getCleanCopy(); 877 878 879 880 /** 881 * Updates the provided list to add any strings that should be included on the 882 * command line in order to represent this argument's current state. 883 * 884 * @param argStrings The list to update with the string representation of 885 * the command-line arguments. 886 */ 887 protected abstract void addToCommandLine(List<String> argStrings); 888 889 890 891 /** 892 * Retrieves a string representation of this argument. 893 * 894 * @return A string representation of this argument. 895 */ 896 public final String toString() 897 { 898 final StringBuilder buffer = new StringBuilder(); 899 toString(buffer); 900 return buffer.toString(); 901 } 902 903 904 905 /** 906 * Appends a string representation of this argument to the provided buffer. 907 * 908 * @param buffer The buffer to which the information should be appended. 909 */ 910 public abstract void toString(StringBuilder buffer); 911 912 913 914 /** 915 * Appends a basic set of information for this argument to the provided 916 * buffer in a form suitable for use in the {@code toString} method. 917 * 918 * @param buffer The buffer to which information should be appended. 919 */ 920 protected void appendBasicToStringInfo(final StringBuilder buffer) 921 { 922 switch (shortIdentifiers.size()) 923 { 924 case 0: 925 // Nothing to add. 926 break; 927 928 case 1: 929 buffer.append("shortIdentifier='-"); 930 buffer.append(shortIdentifiers.keySet().iterator().next()); 931 buffer.append('\''); 932 break; 933 934 default: 935 buffer.append("shortIdentifiers={"); 936 937 final Iterator<Character> iterator = 938 shortIdentifiers.keySet().iterator(); 939 while (iterator.hasNext()) 940 { 941 buffer.append("'-"); 942 buffer.append(iterator.next()); 943 buffer.append('\''); 944 945 if (iterator.hasNext()) 946 { 947 buffer.append(", "); 948 } 949 } 950 buffer.append('}'); 951 break; 952 } 953 954 if (! shortIdentifiers.isEmpty()) 955 { 956 buffer.append(", "); 957 } 958 959 switch (longIdentifiers.size()) 960 { 961 case 0: 962 // Nothing to add. 963 break; 964 965 case 1: 966 buffer.append("longIdentifier='--"); 967 buffer.append(longIdentifiers.keySet().iterator().next()); 968 buffer.append('\''); 969 break; 970 971 default: 972 buffer.append("longIdentifiers={"); 973 974 final Iterator<String> iterator = longIdentifiers.keySet().iterator(); 975 while (iterator.hasNext()) 976 { 977 buffer.append("'--"); 978 buffer.append(iterator.next()); 979 buffer.append('\''); 980 981 if (iterator.hasNext()) 982 { 983 buffer.append(", "); 984 } 985 } 986 buffer.append('}'); 987 break; 988 } 989 990 buffer.append(", description='"); 991 buffer.append(description); 992 993 if (argumentGroupName != null) 994 { 995 buffer.append("', argumentGroup='"); 996 buffer.append(argumentGroupName); 997 } 998 999 buffer.append("', isRequired="); 1000 buffer.append(isRequired); 1001 1002 buffer.append(", maxOccurrences="); 1003 if (maxOccurrences == 0) 1004 { 1005 buffer.append("unlimited"); 1006 } 1007 else 1008 { 1009 buffer.append(maxOccurrences); 1010 } 1011 1012 if (valuePlaceholder == null) 1013 { 1014 buffer.append(", takesValue=false"); 1015 } 1016 else 1017 { 1018 buffer.append(", takesValue=true, valuePlaceholder='"); 1019 buffer.append(valuePlaceholder); 1020 buffer.append('\''); 1021 } 1022 1023 if (isHidden) 1024 { 1025 buffer.append(", isHidden=true"); 1026 } 1027 } 1028}