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