001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. 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 */ 017package org.apache.commons.cli2.validation; 018 019import java.text.NumberFormat; 020import java.text.ParsePosition; 021 022import java.util.List; 023import java.util.ListIterator; 024 025import org.apache.commons.cli2.resource.ResourceConstants; 026import org.apache.commons.cli2.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 Rob Oxspring 053 * @author John Keyes 054 */ 055public class NumberValidator implements Validator { 056 /** the <code>NumberFormat</code> being used. */ 057 private NumberFormat format; 058 059 /** the lower bound for argument values. */ 060 private Number minimum = null; 061 062 /** the upper bound for argument values */ 063 private Number maximum = null; 064 065 /** 066 * Creates a new NumberValidator based on the specified NumberFormat 067 * @param format the format of numbers to accept 068 */ 069 public NumberValidator(final NumberFormat format) { 070 setFormat(format); 071 } 072 073 /** 074 * Returns a <code>NumberValidator</code> for a currency format 075 * for the current default locale. 076 * @return a <code>NumberValidator</code> for a currency format 077 * for the current default locale. 078 */ 079 public static NumberValidator getCurrencyInstance() { 080 return new NumberValidator(NumberFormat.getCurrencyInstance()); 081 } 082 083 /** 084 * Returns a <code>NumberValidator</code> for an integer number format 085 * for the current default locale. 086 * @return a <code>NumberValidator</code> for an integer number format 087 * for the current default locale. 088 */ 089 public static NumberValidator getIntegerInstance() { 090 final NumberFormat format = NumberFormat.getNumberInstance(); 091 format.setParseIntegerOnly(true); 092 093 return new NumberValidator(format); 094 } 095 096 /** 097 * Returns a <code>NumberValidator</code> for a percentage format 098 * for the current default locale. 099 * @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}