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