001/* 002 * Copyright 2008-2015 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2008-2015 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. There will 076 * not be any default values, nor will there be any restriction on values that 077 * may be assigned to this argument. 078 * 079 * @param shortIdentifier The short identifier for this argument. It may 080 * not be {@code null} if the long identifier is 081 * {@code null}. 082 * @param longIdentifier The long identifier for this argument. It may 083 * not be {@code null} if the short identifier is 084 * {@code null}. 085 * @param isRequired Indicates whether this argument is required to 086 * be provided. 087 * @param maxOccurrences The maximum number of times this argument may be 088 * provided on the command line. A value less than 089 * or equal to zero indicates that it may be present 090 * any number of times. 091 * @param valuePlaceholder A placeholder to display in usage information to 092 * indicate that a value must be provided. It must 093 * not be {@code null}. 094 * @param description A human-readable description for this argument. 095 * It must not be {@code null}. 096 * 097 * @throws ArgumentException If there is a problem with the definition of 098 * this argument. 099 */ 100 public IntegerArgument(final Character shortIdentifier, 101 final String longIdentifier, final boolean isRequired, 102 final int maxOccurrences, 103 final String valuePlaceholder, 104 final String description) 105 throws ArgumentException 106 { 107 this(shortIdentifier, longIdentifier, isRequired, maxOccurrences, 108 valuePlaceholder, description, Integer.MIN_VALUE, Integer.MAX_VALUE, 109 (List<Integer>) null); 110 } 111 112 113 114 /** 115 * Creates a new integer argument with the provided information. There will 116 * not be any default values, but the range of values that will be allowed may 117 * be restricted. 118 * 119 * @param shortIdentifier The short identifier for this argument. It may 120 * not be {@code null} if the long identifier is 121 * {@code null}. 122 * @param longIdentifier The long identifier for this argument. It may 123 * not be {@code null} if the short identifier is 124 * {@code null}. 125 * @param isRequired Indicates whether this argument is required to 126 * be provided. 127 * @param maxOccurrences The maximum number of times this argument may be 128 * provided on the command line. A value less than 129 * or equal to zero indicates that it may be present 130 * any number of times. 131 * @param valuePlaceholder A placeholder to display in usage information to 132 * indicate that a value must be provided. It must 133 * not be {@code null}. 134 * @param description A human-readable description for this argument. 135 * It must not be {@code null}. 136 * @param lowerBound The smallest value that this argument is allowed 137 * to have. It should be {@code Integer.MIN_VALUE} 138 * if there should be no lower bound. 139 * @param upperBound The largest value that this argument is allowed 140 * to have. It should be {@code Integer.MAX_VALUE} 141 * if there should be no upper bound. 142 * 143 * @throws ArgumentException If there is a problem with the definition of 144 * this argument. 145 */ 146 public IntegerArgument(final Character shortIdentifier, 147 final String longIdentifier, final boolean isRequired, 148 final int maxOccurrences, 149 final String valuePlaceholder, 150 final String description, 151 final int lowerBound, final int upperBound) 152 throws ArgumentException 153 { 154 this(shortIdentifier, longIdentifier, isRequired, maxOccurrences, 155 valuePlaceholder, description, lowerBound, upperBound, 156 (List<Integer>) null); 157 } 158 159 160 161 /** 162 * Creates a new integer argument with the provided information. There will 163 * not be any restriction on values that may be assigned to this argument. 164 * 165 * @param shortIdentifier The short identifier for this argument. It may 166 * not be {@code null} if the long identifier is 167 * {@code null}. 168 * @param longIdentifier The long identifier for this argument. It may 169 * not be {@code null} if the short identifier is 170 * {@code null}. 171 * @param isRequired Indicates whether this argument is required to 172 * be provided. 173 * @param maxOccurrences The maximum number of times this argument may be 174 * provided on the command line. A value less than 175 * or equal to zero indicates that it may be present 176 * any number of times. 177 * @param valuePlaceholder A placeholder to display in usage information to 178 * indicate that a value must be provided. It must 179 * not be {@code null}. 180 * @param description A human-readable description for this argument. 181 * It must not be {@code null}. 182 * @param defaultValue The default value that will be used for this 183 * argument if no values are provided. It may be 184 * {@code null} if there should not be a default 185 * value. 186 * 187 * @throws ArgumentException If there is a problem with the definition of 188 * this argument. 189 */ 190 public IntegerArgument(final Character shortIdentifier, 191 final String longIdentifier, final boolean isRequired, 192 final int maxOccurrences, 193 final String valuePlaceholder, 194 final String description, 195 final Integer defaultValue) 196 throws ArgumentException 197 { 198 this(shortIdentifier, longIdentifier, isRequired, maxOccurrences, 199 valuePlaceholder, description, Integer.MIN_VALUE, Integer.MAX_VALUE, 200 ((defaultValue == null) ? null : Arrays.asList(defaultValue))); 201 } 202 203 204 205 /** 206 * Creates a new integer argument with the provided information. There will 207 * not be any restriction on values that may be assigned to this argument. 208 * 209 * @param shortIdentifier The short identifier for this argument. It may 210 * not be {@code null} if the long identifier is 211 * {@code null}. 212 * @param longIdentifier The long identifier for this argument. It may 213 * not be {@code null} if the short identifier is 214 * {@code null}. 215 * @param isRequired Indicates whether this argument is required to 216 * be provided. 217 * @param maxOccurrences The maximum number of times this argument may be 218 * provided on the command line. A value less than 219 * or equal to zero indicates that it may be present 220 * any number of times. 221 * @param valuePlaceholder A placeholder to display in usage information to 222 * indicate that a value must be provided. It must 223 * not be {@code null}. 224 * @param description A human-readable description for this argument. 225 * It must not be {@code null}. 226 * @param defaultValues The set of default values that will be used for 227 * this argument if no values are provided. 228 * 229 * @throws ArgumentException If there is a problem with the definition of 230 * this argument. 231 */ 232 public IntegerArgument(final Character shortIdentifier, 233 final String longIdentifier, final boolean isRequired, 234 final int maxOccurrences, 235 final String valuePlaceholder, 236 final String description, 237 final List<Integer> defaultValues) 238 throws ArgumentException 239 { 240 this(shortIdentifier, longIdentifier, isRequired, maxOccurrences, 241 valuePlaceholder, description, Integer.MIN_VALUE, Integer.MAX_VALUE, 242 defaultValues); 243 } 244 245 246 247 /** 248 * Creates a new integer argument with the provided information. 249 * 250 * @param shortIdentifier The short identifier for this argument. It may 251 * not be {@code null} if the long identifier is 252 * {@code null}. 253 * @param longIdentifier The long identifier for this argument. It may 254 * not be {@code null} if the short identifier is 255 * {@code null}. 256 * @param isRequired Indicates whether this argument is required to 257 * be provided. 258 * @param maxOccurrences The maximum number of times this argument may be 259 * provided on the command line. A value less than 260 * or equal to zero indicates that it may be present 261 * any number of times. 262 * @param valuePlaceholder A placeholder to display in usage information to 263 * indicate that a value must be provided. It must 264 * not be {@code null}. 265 * @param description A human-readable description for this argument. 266 * It must not be {@code null}. 267 * @param lowerBound The smallest value that this argument is allowed 268 * to have. It should be {@code Integer.MIN_VALUE} 269 * if there should be no lower bound. 270 * @param upperBound The largest value that this argument is allowed 271 * to have. It should be {@code Integer.MAX_VALUE} 272 * if there should be no upper bound. 273 * @param defaultValue The default value that will be used for this 274 * argument if no values are provided. It may be 275 * {@code null} if there should not be a default 276 * value. 277 * 278 * @throws ArgumentException If there is a problem with the definition of 279 * this argument. 280 */ 281 public IntegerArgument(final Character shortIdentifier, 282 final String longIdentifier, final boolean isRequired, 283 final int maxOccurrences, 284 final String valuePlaceholder, 285 final String description, final int lowerBound, 286 final int upperBound, 287 final Integer defaultValue) 288 throws ArgumentException 289 { 290 this(shortIdentifier, longIdentifier, isRequired, maxOccurrences, 291 valuePlaceholder, description, lowerBound, upperBound, 292 ((defaultValue == null) ? null : Arrays.asList(defaultValue))); 293 } 294 295 296 297 /** 298 * Creates a new integer argument with the provided information. 299 * 300 * @param shortIdentifier The short identifier for this argument. It may 301 * not be {@code null} if the long identifier is 302 * {@code null}. 303 * @param longIdentifier The long identifier for this argument. It may 304 * not be {@code null} if the short identifier is 305 * {@code null}. 306 * @param isRequired Indicates whether this argument is required to 307 * be provided. 308 * @param maxOccurrences The maximum number of times this argument may be 309 * provided on the command line. A value less than 310 * or equal to zero indicates that it may be present 311 * any number of times. 312 * @param valuePlaceholder A placeholder to display in usage information to 313 * indicate that a value must be provided. It must 314 * not be {@code null}. 315 * @param description A human-readable description for this argument. 316 * It must not be {@code null}. 317 * @param lowerBound The smallest value that this argument is allowed 318 * to have. It should be {@code Integer.MIN_VALUE} 319 * if there should be no lower bound. 320 * @param upperBound The largest value that this argument is allowed 321 * to have. It should be {@code Integer.MAX_VALUE} 322 * if there should be no upper bound. 323 * @param defaultValues The set of default values that will be used for 324 * this argument if no values are provided. 325 * 326 * @throws ArgumentException If there is a problem with the definition of 327 * this argument. 328 */ 329 public IntegerArgument(final Character shortIdentifier, 330 final String longIdentifier, final boolean isRequired, 331 final int maxOccurrences, 332 final String valuePlaceholder, 333 final String description, final int lowerBound, 334 final int upperBound, 335 final List<Integer> defaultValues) 336 throws ArgumentException 337 { 338 super(shortIdentifier, longIdentifier, isRequired, maxOccurrences, 339 valuePlaceholder, description); 340 341 if (valuePlaceholder == null) 342 { 343 throw new ArgumentException(ERR_ARG_MUST_TAKE_VALUE.get( 344 getIdentifierString())); 345 } 346 347 this.lowerBound = lowerBound; 348 this.upperBound = upperBound; 349 350 if ((defaultValues == null) || defaultValues.isEmpty()) 351 { 352 this.defaultValues = null; 353 } 354 else 355 { 356 this.defaultValues = Collections.unmodifiableList(defaultValues); 357 } 358 359 values = new ArrayList<Integer>(5); 360 validators = new ArrayList<ArgumentValueValidator>(5); 361 } 362 363 364 365 /** 366 * Creates a new integer argument that is a "clean" copy of the provided 367 * source argument. 368 * 369 * @param source The source argument to use for this argument. 370 */ 371 private IntegerArgument(final IntegerArgument source) 372 { 373 super(source); 374 375 lowerBound = source.lowerBound; 376 upperBound = source.upperBound; 377 defaultValues = source.defaultValues; 378 validators = new ArrayList<ArgumentValueValidator>(source.validators); 379 values = new ArrayList<Integer>(5); 380 } 381 382 383 384 /** 385 * Retrieves the smallest value that this argument will be allowed to have. 386 * 387 * @return The smallest value that this argument will be allowed to have. 388 */ 389 public int getLowerBound() 390 { 391 return lowerBound; 392 } 393 394 395 396 /** 397 * Retrieves the largest value that this argument will be allowed to have. 398 * 399 * @return The largest value that this argument will be allowed to have. 400 */ 401 public int getUpperBound() 402 { 403 return upperBound; 404 } 405 406 407 408 /** 409 * Retrieves the list of default values for this argument, which will be used 410 * if no values were provided. 411 * 412 * @return The list of default values for this argument, or {@code null} if 413 * there are no default values. 414 */ 415 public List<Integer> getDefaultValues() 416 { 417 return defaultValues; 418 } 419 420 421 422 /** 423 * Updates this argument to ensure that the provided validator will be invoked 424 * for any values provided to this argument. This validator will be invoked 425 * after all other validation has been performed for this argument. 426 * 427 * @param validator The argument value validator to be invoked. It must not 428 * be {@code null}. 429 */ 430 public void addValueValidator(final ArgumentValueValidator validator) 431 { 432 validators.add(validator); 433 } 434 435 436 437 /** 438 * {@inheritDoc} 439 */ 440 @Override() 441 protected void addValue(final String valueString) 442 throws ArgumentException 443 { 444 final int intValue; 445 try 446 { 447 intValue = Integer.parseInt(valueString); 448 } 449 catch (Exception e) 450 { 451 throw new ArgumentException(ERR_INTEGER_VALUE_NOT_INT.get(valueString, 452 getIdentifierString()), e); 453 } 454 455 if (intValue < lowerBound) 456 { 457 throw new ArgumentException(ERR_INTEGER_VALUE_BELOW_LOWER_BOUND.get( 458 intValue, getIdentifierString(), 459 lowerBound)); 460 } 461 462 if (intValue > upperBound) 463 { 464 throw new ArgumentException(ERR_INTEGER_VALUE_ABOVE_UPPER_BOUND.get( 465 intValue, getIdentifierString(), 466 upperBound)); 467 } 468 469 if (values.size() >= getMaxOccurrences()) 470 { 471 throw new ArgumentException(ERR_ARG_MAX_OCCURRENCES_EXCEEDED.get( 472 getIdentifierString())); 473 } 474 475 for (final ArgumentValueValidator v : validators) 476 { 477 v.validateArgumentValue(this, valueString); 478 } 479 480 values.add(intValue); 481 } 482 483 484 485 /** 486 * Retrieves the value for this argument, or the default value if none was 487 * provided. If this argument has multiple values, then the first will be 488 * returned. 489 * 490 * @return The value for this argument, or the default value if none was 491 * provided, or {@code null} if it does not have any values or 492 * default values. 493 */ 494 public Integer getValue() 495 { 496 if (values.isEmpty()) 497 { 498 if ((defaultValues == null) || defaultValues.isEmpty()) 499 { 500 return null; 501 } 502 else 503 { 504 return defaultValues.get(0); 505 } 506 } 507 508 return values.get(0); 509 } 510 511 512 513 /** 514 * Retrieves the set of values for this argument, or the default values if 515 * none were provided. 516 * 517 * @return The set of values for this argument, or the default values if none 518 * were provided. 519 */ 520 public List<Integer> getValues() 521 { 522 if (values.isEmpty() && (defaultValues != null)) 523 { 524 return defaultValues; 525 } 526 527 return Collections.unmodifiableList(values); 528 } 529 530 531 532 /** 533 * {@inheritDoc} 534 */ 535 @Override() 536 protected boolean hasDefaultValue() 537 { 538 return ((defaultValues != null) && (! defaultValues.isEmpty())); 539 } 540 541 542 543 /** 544 * {@inheritDoc} 545 */ 546 @Override() 547 public String getDataTypeName() 548 { 549 return INFO_INTEGER_TYPE_NAME.get(); 550 } 551 552 553 554 /** 555 * {@inheritDoc} 556 */ 557 @Override() 558 public String getValueConstraints() 559 { 560 return INFO_INTEGER_CONSTRAINTS_LOWER_AND_UPPER_BOUND.get(lowerBound, 561 upperBound); 562 } 563 564 565 566 /** 567 * {@inheritDoc} 568 */ 569 @Override() 570 public IntegerArgument getCleanCopy() 571 { 572 return new IntegerArgument(this); 573 } 574 575 576 577 /** 578 * {@inheritDoc} 579 */ 580 @Override() 581 public void toString(final StringBuilder buffer) 582 { 583 buffer.append("IntegerArgument("); 584 appendBasicToStringInfo(buffer); 585 586 buffer.append(", lowerBound="); 587 buffer.append(lowerBound); 588 buffer.append(", upperBound="); 589 buffer.append(upperBound); 590 591 if ((defaultValues != null) && (! defaultValues.isEmpty())) 592 { 593 if (defaultValues.size() == 1) 594 { 595 buffer.append(", defaultValue='"); 596 buffer.append(defaultValues.get(0).toString()); 597 } 598 else 599 { 600 buffer.append(", defaultValues={"); 601 602 final Iterator<Integer> iterator = defaultValues.iterator(); 603 while (iterator.hasNext()) 604 { 605 buffer.append('\''); 606 buffer.append(iterator.next().toString()); 607 buffer.append('\''); 608 609 if (iterator.hasNext()) 610 { 611 buffer.append(", "); 612 } 613 } 614 615 buffer.append('}'); 616 } 617 } 618 619 buffer.append(')'); 620 } 621}