001 /*
002 * Copyright 2003-2005 The Apache Software Foundation
003 * Copyright 2005 Stephen McConnell
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package net.dpml.cli.validation;
018
019 import java.text.NumberFormat;
020 import java.text.ParsePosition;
021
022 import java.util.List;
023 import java.util.ListIterator;
024
025 import net.dpml.cli.resource.ResourceConstants;
026 import net.dpml.cli.resource.ResourceHelper;
027
028 /**
029 * The <code>NumberValidator</code> validates the string argument
030 * values are numbers. If the value is a number, the string value in
031 * the {@link java.util.List} of values is replaced with the
032 * {@link java.lang.Number} instance.
033 *
034 * A maximum and minimum value can also be specified using
035 * the {@link #setMaximum setMaximum}, and the
036 * {@link #setMinimum setMinimum} methods.
037 *
038 * The following example shows how to limit the valid values
039 * for the age attribute to integers less than 100.
040 *
041 * <pre>
042 * ...
043 * ArgumentBuilder builder = new ArgumentBuilder();
044 * NumberValidator validator = NumberValidator.getIntegerInstance();
045 * validator.setMaximum(new Integer(100));
046 *
047 * Argument age =
048 * builder.withName("age");
049 * .withValidator(validator);
050 * </pre>
051 *
052 * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
053 * @version @PROJECT-VERSION@
054 */
055 public class NumberValidator implements Validator
056 {
057 /** the <code>NumberFormat</code> being used. */
058 private NumberFormat m_format;
059
060 /** the lower bound for argument values. */
061 private Number m_minimum = null;
062
063 /** the upper bound for argument values */
064 private Number m_maximum = null;
065
066 /**
067 * Creates a new NumberValidator based on the specified NumberFormat
068 * @param format the format of numbers to accept
069 */
070 public NumberValidator( final NumberFormat format )
071 {
072 setFormat( format );
073 }
074
075 /**
076 * Returns a <code>NumberValidator</code> for a currency format
077 * for the current default locale.
078 * @return a <code>NumberValidator</code> for a currency format
079 * for the current default locale.
080 */
081 public static NumberValidator getCurrencyInstance()
082 {
083 return new NumberValidator( NumberFormat.getCurrencyInstance() );
084 }
085
086 /**
087 * Returns a <code>NumberValidator</code> for an integer number format
088 * for the current default locale.
089 * @return a <code>NumberValidator</code> for an integer number format
090 * for the current default locale.
091 */
092 public static NumberValidator getIntegerInstance()
093 {
094 final NumberFormat format = NumberFormat.getNumberInstance();
095 format.setParseIntegerOnly( true );
096 return new NumberValidator( format );
097 }
098
099 /**
100 * Returns a <code>NumberValidator</code> for a percentage format
101 * for the current default locale.
102 * @return a <code>NumberValidator</code> for a percentage format
103 * for the current default locale.
104 */
105 public static NumberValidator getPercentInstance()
106 {
107 return new NumberValidator( NumberFormat.getPercentInstance() );
108 }
109
110 /**
111 * Returns a <code>NumberValidator</code> for a general-purpose
112 * number format for the current default locale.
113 * @return a <code>NumberValidator</code> for a general-purpose
114 * number format for the current default locale.
115 */
116 public static NumberValidator getNumberInstance()
117 {
118 return new NumberValidator( NumberFormat.getNumberInstance() );
119 }
120
121 /**
122 * Validate the list of values against the list of permitted values.
123 * If a value is valid, replace the string in the <code>values</code>
124 * {@link java.util.List} with the {@link java.lang.Number} instance.
125 *
126 * @param values the list of values to validate
127 * @exception InvalidArgumentException if a value is invalid
128 * @see net.dpml.cli.validation.Validator#validate(java.util.List)
129 */
130 public void validate( final List values ) throws InvalidArgumentException
131 {
132 for( final ListIterator i = values.listIterator(); i.hasNext();)
133 {
134 final Object next = i.next();
135 if( next instanceof Number )
136 {
137 return;
138 }
139 final String value = (String) next;
140 final ParsePosition pp = new ParsePosition( 0 );
141 final Number number = m_format.parse( value, pp );
142 if( pp.getIndex() < value.length() )
143 {
144 throw new InvalidArgumentException( value );
145 }
146 if(
147 ( ( m_minimum != null ) && ( number.doubleValue() < m_minimum.doubleValue() ) )
148 || ( ( m_maximum != null ) && ( number.doubleValue() > m_maximum.doubleValue() ) )
149 )
150 {
151 throw new InvalidArgumentException(
152 ResourceHelper.getResourceHelper().getMessage(
153 ResourceConstants.NUMBERVALIDATOR_NUMBER_OUTOFRANGE,
154 new Object[]{value} ) );
155 }
156 i.set( number );
157 }
158 }
159
160 /**
161 * Return the format being used to validate argument values against.
162 *
163 * @return the format being used to validate argument values against.
164 */
165 public NumberFormat getFormat()
166 {
167 return m_format;
168 }
169
170 /**
171 * Specify the format being used to validate argument values against.
172 *
173 * @param format the format being used to validate argument values against.
174 */
175 protected void setFormat( NumberFormat format )
176 {
177 m_format = format;
178 }
179
180 /**
181 * Return the maximum value allowed for an argument value.
182 *
183 * @return the maximum value allowed for an argument value.
184 */
185 public Number getMaximum()
186 {
187 return m_maximum;
188 }
189
190 /**
191 * Specify the maximum value allowed for an argument value.
192 *
193 * @param maximum the maximum value allowed for an argument value.
194 */
195 public void setMaximum( Number maximum )
196 {
197 m_maximum = maximum;
198 }
199
200 /**
201 * Return the minimum value allowed for an argument value.
202 *
203 * @return the minimum value allowed for an argument value.
204 */
205 public Number getMinimum()
206 {
207 return m_minimum;
208 }
209
210 /**
211 * Specify the minimum value allowed for an argument value.
212 *
213 * @param minimum the minimum value allowed for an argument value.
214 */
215 public void setMinimum( Number minimum )
216 {
217 m_minimum = minimum;
218 }
219 }