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 */
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. 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 }