001 /*
002 * Copyright 2008-2016 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2008-2016 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 */
021 package com.unboundid.util.args;
022
023
024
025 import java.util.ArrayList;
026 import java.util.Arrays;
027 import java.util.Collections;
028 import java.util.Iterator;
029 import java.util.List;
030
031 import com.unboundid.util.Mutable;
032 import com.unboundid.util.ThreadSafety;
033 import com.unboundid.util.ThreadSafetyLevel;
034
035 import 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)
047 public 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 }