View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.cli2.validation;
18  
19  import java.text.NumberFormat;
20  import java.text.ParsePosition;
21  
22  import java.util.List;
23  import java.util.ListIterator;
24  
25  import org.apache.commons.cli2.resource.ResourceConstants;
26  import org.apache.commons.cli2.resource.ResourceHelper;
27  
28  /**
29   * The <code>NumberValidator</code> validates the string argument
30   * values are numbers.  If the value is a number, the string value in
31   * the {@link java.util.List} of values is replaced with the
32   * {@link java.lang.Number} instance.
33   *
34   * A maximum and minimum value can also be specified using
35   * the {@link #setMaximum setMaximum}, and the
36   * {@link #setMinimum setMinimum} methods.
37   *
38   * The following example shows how to limit the valid values
39   * for the age attribute to integers less than 100.
40   *
41   * <pre>
42   * ...
43   * ArgumentBuilder builder = new ArgumentBuilder();
44   * NumberValidator validator = NumberValidator.getIntegerInstance();
45   * validator.setMaximum(new Integer(100));
46   *
47   * Argument age =
48   *     builder.withName("age");
49   *            .withValidator(validator);
50   * </pre>
51   *
52   * @author Rob Oxspring
53   * @author John Keyes
54   */
55  public class NumberValidator implements Validator {
56      /** the <code>NumberFormat</code> being used. */
57      private NumberFormat format;
58  
59      /** the lower bound for argument values. */
60      private Number minimum = null;
61  
62      /** the upper bound for argument values */
63      private Number maximum = null;
64  
65      /**
66       * Creates a new NumberValidator based on the specified NumberFormat
67       * @param format the format of numbers to accept
68       */
69      public NumberValidator(final NumberFormat format) {
70          setFormat(format);
71      }
72  
73      /**
74       * Returns a <code>NumberValidator</code> for a currency format
75       * for the current default locale.
76       * @return a <code>NumberValidator</code> for a currency format
77       * for the current default locale.
78       */
79      public static NumberValidator getCurrencyInstance() {
80          return new NumberValidator(NumberFormat.getCurrencyInstance());
81      }
82  
83      /**
84       * Returns a <code>NumberValidator</code> for an integer number format
85       * for the current default locale.
86       * @return a <code>NumberValidator</code> for an integer number format
87       * for the current default locale.
88       */
89      public static NumberValidator getIntegerInstance() {
90          final NumberFormat format = NumberFormat.getNumberInstance();
91          format.setParseIntegerOnly(true);
92  
93          return new NumberValidator(format);
94      }
95  
96      /**
97       * Returns a <code>NumberValidator</code> for a percentage format
98       * for the current default locale.
99       * @return a <code>NumberValidator</code> for a percentage format
100      * for the current default locale.
101      */
102     public static NumberValidator getPercentInstance() {
103         return new NumberValidator(NumberFormat.getPercentInstance());
104     }
105 
106     /**
107      * Returns a <code>NumberValidator</code> for a general-purpose
108      * number format for the current default locale.
109      * @return a <code>NumberValidator</code> for a general-purpose
110      * number format for the current default locale.
111      */
112     public static NumberValidator getNumberInstance() {
113         return new NumberValidator(NumberFormat.getNumberInstance());
114     }
115 
116     /**
117      * Validate the list of values against the list of permitted values.
118      * If a value is valid, replace the string in the <code>values</code>
119      * {@link java.util.List} with the {@link java.lang.Number} instance.
120      *
121      * @see org.apache.commons.cli2.validation.Validator#validate(java.util.List)
122      */
123     public void validate(final List values)
124         throws InvalidArgumentException {
125         for (final ListIterator i = values.listIterator(); i.hasNext();) {
126             final String value = (String) i.next();
127 
128             final ParsePosition pp = new ParsePosition(0);
129             final Number number = format.parse(value, pp);
130 
131             if (pp.getIndex() < value.length()) {
132                 throw new InvalidArgumentException(value);
133             }
134 
135             if (((minimum != null) && (number.doubleValue() < minimum.doubleValue())) ||
136                     ((maximum != null) && (number.doubleValue() > maximum.doubleValue()))) {
137                 throw new InvalidArgumentException(ResourceHelper.getResourceHelper().getMessage(ResourceConstants.NUMBERVALIDATOR_NUMBER_OUTOFRANGE,
138                                                                                                  new Object[] {
139                                                                                                      value
140                                                                                                  }));
141             }
142 
143             i.set(number);
144         }
145     }
146 
147     /**
148      * Return the format being used to validate argument values against.
149      *
150      * @return the format being used to validate argument values against.
151      */
152     public NumberFormat getFormat() {
153         return format;
154     }
155 
156     /**
157      * Specify the format being used to validate argument values against.
158      *
159      * @param format the format being used to validate argument values against.
160      */
161     protected void setFormat(NumberFormat format) {
162         this.format = format;
163     }
164 
165     /**
166      * Return the maximum value allowed for an argument value.
167      *
168      * @return the maximum value allowed for an argument value.
169      */
170     public Number getMaximum() {
171         return maximum;
172     }
173 
174     /**
175      * Specify the maximum value allowed for an argument value.
176      *
177      * @param maximum the maximum value allowed for an argument value.
178      */
179     public void setMaximum(Number maximum) {
180         this.maximum = maximum;
181     }
182 
183     /**
184      * Return the minimum value allowed for an argument value.
185      *
186      * @return the minimum value allowed for an argument value.
187      */
188     public Number getMinimum() {
189         return minimum;
190     }
191 
192     /**
193      * Specify the minimum value allowed for an argument value.
194      *
195      * @param minimum the minimum value allowed for an argument value.
196      */
197     public void setMinimum(Number minimum) {
198         this.minimum = minimum;
199     }
200 }