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