001/* 002 * Copyright 2008-2017 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2008-2017 UnboundID Corp. 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.util.ArrayList; 026import java.util.Arrays; 027import java.util.Collections; 028import java.util.Iterator; 029import java.util.List; 030 031import com.unboundid.util.Mutable; 032import com.unboundid.util.ThreadSafety; 033import com.unboundid.util.ThreadSafetyLevel; 034 035import static com.unboundid.util.args.ArgsMessages.*; 036 037 038 039/** 040 * This class defines an argument that is intended to hold one or more integer 041 * values. Integer arguments must take values. By default, any value will be 042 * allowed, but it is possible to restrict the set of values to a given range 043 * using upper and lower bounds. 044 */ 045@Mutable() 046@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) 047public final class IntegerArgument 048 extends Argument 049{ 050 /** 051 * The serial version UID for this serializable class. 052 */ 053 private static final long serialVersionUID = 3364985217337213643L; 054 055 056 057 // The set of values assigned to this argument. 058 private final ArrayList<Integer> values; 059 060 // The lower bound for this argument. 061 private final int lowerBound; 062 063 // The upper bound for this argument. 064 private final int upperBound; 065 066 // The argument value validators that have been registered for this argument. 067 private final List<ArgumentValueValidator> validators; 068 069 // The list of default values that will be used if no values were provided. 070 private final List<Integer> defaultValues; 071 072 073 074 /** 075 * Creates a new integer argument with the provided information. It will not 076 * be required, will permit at most one occurrence, will use a default 077 * placeholder, will not have a default value, and will not impose any 078 * restrictions on the range of values that may be assigned to this argument. 079 * 080 * @param shortIdentifier The short identifier for this argument. It may 081 * not be {@code null} if the long identifier is 082 * {@code null}. 083 * @param longIdentifier The long identifier for this argument. It may 084 * not be {@code null} if the short identifier is 085 * {@code null}. 086 * @param description A human-readable description for this argument. 087 * It must not be {@code null}. 088 * 089 * @throws ArgumentException If there is a problem with the definition of 090 * this argument. 091 */ 092 public IntegerArgument(final Character shortIdentifier, 093 final String longIdentifier, final String description) 094 throws ArgumentException 095 { 096 this(shortIdentifier, longIdentifier, false, 1, null, description); 097 } 098 099 100 101 /** 102 * Creates a new integer argument with the provided information. There will 103 * not be any default values, nor will there be any restriction on values that 104 * may be assigned to this argument. 105 * 106 * @param shortIdentifier The short identifier for this argument. It may 107 * not be {@code null} if the long identifier is 108 * {@code null}. 109 * @param longIdentifier The long identifier for this argument. It may 110 * not be {@code null} if the short identifier is 111 * {@code null}. 112 * @param isRequired Indicates whether this argument is required to 113 * be provided. 114 * @param maxOccurrences The maximum number of times this argument may be 115 * provided on the command line. A value less than 116 * or equal to zero indicates that it may be present 117 * any number of times. 118 * @param valuePlaceholder A placeholder to display in usage information to 119 * indicate that a value must be provided. It may 120 * be {@code null} if a default placeholder should 121 * be used. 122 * @param description A human-readable description for this argument. 123 * It must not be {@code null}. 124 * 125 * @throws ArgumentException If there is a problem with the definition of 126 * this argument. 127 */ 128 public IntegerArgument(final Character shortIdentifier, 129 final String longIdentifier, final boolean isRequired, 130 final int maxOccurrences, 131 final String valuePlaceholder, 132 final String description) 133 throws ArgumentException 134 { 135 this(shortIdentifier, longIdentifier, isRequired, maxOccurrences, 136 valuePlaceholder, description, Integer.MIN_VALUE, Integer.MAX_VALUE, 137 (List<Integer>) null); 138 } 139 140 141 142 /** 143 * Creates a new integer argument with the provided information. There will 144 * not be any default values, but the range of values that will be allowed may 145 * be restricted. 146 * 147 * @param shortIdentifier The short identifier for this argument. It may 148 * not be {@code null} if the long identifier is 149 * {@code null}. 150 * @param longIdentifier The long identifier for this argument. It may 151 * not be {@code null} if the short identifier is 152 * {@code null}. 153 * @param isRequired Indicates whether this argument is required to 154 * be provided. 155 * @param maxOccurrences The maximum number of times this argument may be 156 * provided on the command line. A value less than 157 * or equal to zero indicates that it may be present 158 * any number of times. 159 * @param valuePlaceholder A placeholder to display in usage information to 160 * indicate that a value must be provided. It may 161 * be {@code null} if a default placeholder should 162 * be used. 163 * @param description A human-readable description for this argument. 164 * It must not be {@code null}. 165 * @param lowerBound The smallest value that this argument is allowed 166 * to have. It should be {@code Integer.MIN_VALUE} 167 * if there should be no lower bound. 168 * @param upperBound The largest value that this argument is allowed 169 * to have. It should be {@code Integer.MAX_VALUE} 170 * if there should be no upper bound. 171 * 172 * @throws ArgumentException If there is a problem with the definition of 173 * this argument. 174 */ 175 public IntegerArgument(final Character shortIdentifier, 176 final String longIdentifier, final boolean isRequired, 177 final int maxOccurrences, 178 final String valuePlaceholder, 179 final String description, 180 final int lowerBound, final int upperBound) 181 throws ArgumentException 182 { 183 this(shortIdentifier, longIdentifier, isRequired, maxOccurrences, 184 valuePlaceholder, description, lowerBound, upperBound, 185 (List<Integer>) null); 186 } 187 188 189 190 /** 191 * Creates a new integer argument with the provided information. There will 192 * not be any restriction on values that may be assigned to this argument. 193 * 194 * @param shortIdentifier The short identifier for this argument. It may 195 * not be {@code null} if the long identifier is 196 * {@code null}. 197 * @param longIdentifier The long identifier for this argument. It may 198 * not be {@code null} if the short identifier is 199 * {@code null}. 200 * @param isRequired Indicates whether this argument is required to 201 * be provided. 202 * @param maxOccurrences The maximum number of times this argument may be 203 * provided on the command line. A value less than 204 * or equal to zero indicates that it may be present 205 * any number of times. 206 * @param valuePlaceholder A placeholder to display in usage information to 207 * indicate that a value must be provided. It may 208 * be {@code null} if a default placeholder should 209 * be used. 210 * @param description A human-readable description for this argument. 211 * It must not be {@code null}. 212 * @param defaultValue The default value that will be used for this 213 * argument if no values are provided. It may be 214 * {@code null} if there should not be a default 215 * value. 216 * 217 * @throws ArgumentException If there is a problem with the definition of 218 * this argument. 219 */ 220 public IntegerArgument(final Character shortIdentifier, 221 final String longIdentifier, final boolean isRequired, 222 final int maxOccurrences, 223 final String valuePlaceholder, 224 final String description, 225 final Integer defaultValue) 226 throws ArgumentException 227 { 228 this(shortIdentifier, longIdentifier, isRequired, maxOccurrences, 229 valuePlaceholder, description, Integer.MIN_VALUE, Integer.MAX_VALUE, 230 ((defaultValue == null) ? null : Arrays.asList(defaultValue))); 231 } 232 233 234 235 /** 236 * Creates a new integer argument with the provided information. There will 237 * not be any restriction on values that may be assigned to this argument. 238 * 239 * @param shortIdentifier The short identifier for this argument. It may 240 * not be {@code null} if the long identifier is 241 * {@code null}. 242 * @param longIdentifier The long identifier for this argument. It may 243 * not be {@code null} if the short identifier is 244 * {@code null}. 245 * @param isRequired Indicates whether this argument is required to 246 * be provided. 247 * @param maxOccurrences The maximum number of times this argument may be 248 * provided on the command line. A value less than 249 * or equal to zero indicates that it may be present 250 * any number of times. 251 * @param valuePlaceholder A placeholder to display in usage information to 252 * indicate that a value must be provided. It may 253 * be {@code null} if a default placeholder should 254 * be used. 255 * @param description A human-readable description for this argument. 256 * It must not be {@code null}. 257 * @param defaultValues The set of default values that will be used for 258 * this argument if no values are provided. 259 * 260 * @throws ArgumentException If there is a problem with the definition of 261 * this argument. 262 */ 263 public IntegerArgument(final Character shortIdentifier, 264 final String longIdentifier, final boolean isRequired, 265 final int maxOccurrences, 266 final String valuePlaceholder, 267 final String description, 268 final List<Integer> defaultValues) 269 throws ArgumentException 270 { 271 this(shortIdentifier, longIdentifier, isRequired, maxOccurrences, 272 valuePlaceholder, description, Integer.MIN_VALUE, Integer.MAX_VALUE, 273 defaultValues); 274 } 275 276 277 278 /** 279 * Creates a new integer argument with the provided information. 280 * 281 * @param shortIdentifier The short identifier for this argument. It may 282 * not be {@code null} if the long identifier is 283 * {@code null}. 284 * @param longIdentifier The long identifier for this argument. It may 285 * not be {@code null} if the short identifier is 286 * {@code null}. 287 * @param isRequired Indicates whether this argument is required to 288 * be provided. 289 * @param maxOccurrences The maximum number of times this argument may be 290 * provided on the command line. A value less than 291 * or equal to zero indicates that it may be present 292 * any number of times. 293 * @param valuePlaceholder A placeholder to display in usage information to 294 * indicate that a value must be provided. It may 295 * be {@code null} if a default placeholder should 296 * be used. 297 * @param description A human-readable description for this argument. 298 * It must not be {@code null}. 299 * @param lowerBound The smallest value that this argument is allowed 300 * to have. It should be {@code Integer.MIN_VALUE} 301 * if there should be no lower bound. 302 * @param upperBound The largest value that this argument is allowed 303 * to have. It should be {@code Integer.MAX_VALUE} 304 * if there should be no upper bound. 305 * @param defaultValue The default value that will be used for this 306 * argument if no values are provided. It may be 307 * {@code null} if there should not be a default 308 * value. 309 * 310 * @throws ArgumentException If there is a problem with the definition of 311 * this argument. 312 */ 313 public IntegerArgument(final Character shortIdentifier, 314 final String longIdentifier, final boolean isRequired, 315 final int maxOccurrences, 316 final String valuePlaceholder, 317 final String description, final int lowerBound, 318 final int upperBound, 319 final Integer defaultValue) 320 throws ArgumentException 321 { 322 this(shortIdentifier, longIdentifier, isRequired, maxOccurrences, 323 valuePlaceholder, description, lowerBound, upperBound, 324 ((defaultValue == null) ? null : Arrays.asList(defaultValue))); 325 } 326 327 328 329 /** 330 * Creates a new integer argument with the provided information. 331 * 332 * @param shortIdentifier The short identifier for this argument. It may 333 * not be {@code null} if the long identifier is 334 * {@code null}. 335 * @param longIdentifier The long identifier for this argument. It may 336 * not be {@code null} if the short identifier is 337 * {@code null}. 338 * @param isRequired Indicates whether this argument is required to 339 * be provided. 340 * @param maxOccurrences The maximum number of times this argument may be 341 * provided on the command line. A value less than 342 * or equal to zero indicates that it may be present 343 * any number of times. 344 * @param valuePlaceholder A placeholder to display in usage information to 345 * indicate that a value must be provided. It may 346 * be {@code null} if a default placeholder should 347 * be used. 348 * @param description A human-readable description for this argument. 349 * It must not be {@code null}. 350 * @param lowerBound The smallest value that this argument is allowed 351 * to have. It should be {@code Integer.MIN_VALUE} 352 * if there should be no lower bound. 353 * @param upperBound The largest value that this argument is allowed 354 * to have. It should be {@code Integer.MAX_VALUE} 355 * if there should be no upper bound. 356 * @param defaultValues The set of default values that will be used for 357 * this argument if no values are provided. 358 * 359 * @throws ArgumentException If there is a problem with the definition of 360 * this argument. 361 */ 362 public IntegerArgument(final Character shortIdentifier, 363 final String longIdentifier, final boolean isRequired, 364 final int maxOccurrences, 365 final String valuePlaceholder, 366 final String description, final int lowerBound, 367 final int upperBound, 368 final List<Integer> defaultValues) 369 throws ArgumentException 370 { 371 super(shortIdentifier, longIdentifier, isRequired, maxOccurrences, 372 (valuePlaceholder == null) 373 ? INFO_PLACEHOLDER_VALUE.get() 374 : valuePlaceholder, 375 description); 376 377 this.lowerBound = lowerBound; 378 this.upperBound = upperBound; 379 380 if ((defaultValues == null) || defaultValues.isEmpty()) 381 { 382 this.defaultValues = null; 383 } 384 else 385 { 386 this.defaultValues = Collections.unmodifiableList(defaultValues); 387 } 388 389 values = new ArrayList<Integer>(5); 390 validators = new ArrayList<ArgumentValueValidator>(5); 391 } 392 393 394 395 /** 396 * Creates a new integer argument that is a "clean" copy of the provided 397 * source argument. 398 * 399 * @param source The source argument to use for this argument. 400 */ 401 private IntegerArgument(final IntegerArgument source) 402 { 403 super(source); 404 405 lowerBound = source.lowerBound; 406 upperBound = source.upperBound; 407 defaultValues = source.defaultValues; 408 validators = new ArrayList<ArgumentValueValidator>(source.validators); 409 values = new ArrayList<Integer>(5); 410 } 411 412 413 414 /** 415 * Retrieves the smallest value that this argument will be allowed to have. 416 * 417 * @return The smallest value that this argument will be allowed to have. 418 */ 419 public int getLowerBound() 420 { 421 return lowerBound; 422 } 423 424 425 426 /** 427 * Retrieves the largest value that this argument will be allowed to have. 428 * 429 * @return The largest value that this argument will be allowed to have. 430 */ 431 public int getUpperBound() 432 { 433 return upperBound; 434 } 435 436 437 438 /** 439 * Retrieves the list of default values for this argument, which will be used 440 * if no values were provided. 441 * 442 * @return The list of default values for this argument, or {@code null} if 443 * there are no default values. 444 */ 445 public List<Integer> getDefaultValues() 446 { 447 return defaultValues; 448 } 449 450 451 452 /** 453 * Updates this argument to ensure that the provided validator will be invoked 454 * for any values provided to this argument. This validator will be invoked 455 * after all other validation has been performed for this argument. 456 * 457 * @param validator The argument value validator to be invoked. It must not 458 * be {@code null}. 459 */ 460 public void addValueValidator(final ArgumentValueValidator validator) 461 { 462 validators.add(validator); 463 } 464 465 466 467 /** 468 * {@inheritDoc} 469 */ 470 @Override() 471 protected void addValue(final String valueString) 472 throws ArgumentException 473 { 474 final int intValue; 475 try 476 { 477 intValue = Integer.parseInt(valueString); 478 } 479 catch (Exception e) 480 { 481 throw new ArgumentException(ERR_INTEGER_VALUE_NOT_INT.get(valueString, 482 getIdentifierString()), e); 483 } 484 485 if (intValue < lowerBound) 486 { 487 throw new ArgumentException(ERR_INTEGER_VALUE_BELOW_LOWER_BOUND.get( 488 intValue, getIdentifierString(), 489 lowerBound)); 490 } 491 492 if (intValue > upperBound) 493 { 494 throw new ArgumentException(ERR_INTEGER_VALUE_ABOVE_UPPER_BOUND.get( 495 intValue, getIdentifierString(), 496 upperBound)); 497 } 498 499 if (values.size() >= getMaxOccurrences()) 500 { 501 throw new ArgumentException(ERR_ARG_MAX_OCCURRENCES_EXCEEDED.get( 502 getIdentifierString())); 503 } 504 505 for (final ArgumentValueValidator v : validators) 506 { 507 v.validateArgumentValue(this, valueString); 508 } 509 510 values.add(intValue); 511 } 512 513 514 515 /** 516 * Retrieves the value for this argument, or the default value if none was 517 * provided. If this argument has multiple values, then the first will be 518 * returned. 519 * 520 * @return The value for this argument, or the default value if none was 521 * provided, or {@code null} if it does not have any values or 522 * default values. 523 */ 524 public Integer getValue() 525 { 526 if (values.isEmpty()) 527 { 528 if ((defaultValues == null) || defaultValues.isEmpty()) 529 { 530 return null; 531 } 532 else 533 { 534 return defaultValues.get(0); 535 } 536 } 537 538 return values.get(0); 539 } 540 541 542 543 /** 544 * Retrieves the set of values for this argument, or the default values if 545 * none were provided. 546 * 547 * @return The set of values for this argument, or the default values if none 548 * were provided. 549 */ 550 public List<Integer> getValues() 551 { 552 if (values.isEmpty() && (defaultValues != null)) 553 { 554 return defaultValues; 555 } 556 557 return Collections.unmodifiableList(values); 558 } 559 560 561 562 /** 563 * {@inheritDoc} 564 */ 565 @Override() 566 public List<String> getValueStringRepresentations(final boolean useDefault) 567 { 568 final List<Integer> intValues; 569 if (values.isEmpty()) 570 { 571 if (useDefault) 572 { 573 intValues = defaultValues; 574 } 575 else 576 { 577 return Collections.emptyList(); 578 } 579 } 580 else 581 { 582 intValues = values; 583 } 584 585 if ((intValues == null) || intValues.isEmpty()) 586 { 587 return Collections.emptyList(); 588 } 589 590 final ArrayList<String> valueStrings = 591 new ArrayList<String>(intValues.size()); 592 for (final Integer i : intValues) 593 { 594 valueStrings.add(i.toString()); 595 } 596 return Collections.unmodifiableList(valueStrings); 597 } 598 599 600 601 /** 602 * {@inheritDoc} 603 */ 604 @Override() 605 protected boolean hasDefaultValue() 606 { 607 return ((defaultValues != null) && (! defaultValues.isEmpty())); 608 } 609 610 611 612 /** 613 * {@inheritDoc} 614 */ 615 @Override() 616 public String getDataTypeName() 617 { 618 return INFO_INTEGER_TYPE_NAME.get(); 619 } 620 621 622 623 /** 624 * {@inheritDoc} 625 */ 626 @Override() 627 public String getValueConstraints() 628 { 629 return INFO_INTEGER_CONSTRAINTS_LOWER_AND_UPPER_BOUND.get(lowerBound, 630 upperBound); 631 } 632 633 634 635 /** 636 * {@inheritDoc} 637 */ 638 @Override() 639 protected void reset() 640 { 641 super.reset(); 642 values.clear(); 643 } 644 645 646 647 /** 648 * {@inheritDoc} 649 */ 650 @Override() 651 public IntegerArgument getCleanCopy() 652 { 653 return new IntegerArgument(this); 654 } 655 656 657 658 /** 659 * {@inheritDoc} 660 */ 661 @Override() 662 protected void addToCommandLine(final List<String> argStrings) 663 { 664 if (values != null) 665 { 666 for (final Integer i : values) 667 { 668 argStrings.add(getIdentifierString()); 669 if (isSensitive()) 670 { 671 argStrings.add("***REDACTED"); 672 } 673 else 674 { 675 argStrings.add(i.toString()); 676 } 677 } 678 } 679 } 680 681 682 683 /** 684 * {@inheritDoc} 685 */ 686 @Override() 687 public void toString(final StringBuilder buffer) 688 { 689 buffer.append("IntegerArgument("); 690 appendBasicToStringInfo(buffer); 691 692 buffer.append(", lowerBound="); 693 buffer.append(lowerBound); 694 buffer.append(", upperBound="); 695 buffer.append(upperBound); 696 697 if ((defaultValues != null) && (! defaultValues.isEmpty())) 698 { 699 if (defaultValues.size() == 1) 700 { 701 buffer.append(", defaultValue='"); 702 buffer.append(defaultValues.get(0).toString()); 703 } 704 else 705 { 706 buffer.append(", defaultValues={"); 707 708 final Iterator<Integer> iterator = defaultValues.iterator(); 709 while (iterator.hasNext()) 710 { 711 buffer.append('\''); 712 buffer.append(iterator.next().toString()); 713 buffer.append('\''); 714 715 if (iterator.hasNext()) 716 { 717 buffer.append(", "); 718 } 719 } 720 721 buffer.append('}'); 722 } 723 } 724 725 buffer.append(')'); 726 } 727}