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}