1 15 package org.apache.tapestry.valid; 16 17 import java.math.BigDecimal ; 18 import java.math.BigInteger ; 19 import java.util.HashMap ; 20 import java.util.Map ; 21 22 import org.apache.hivemind.ApplicationRuntimeException; 23 import org.apache.hivemind.lib.util.StrategyRegistry; 24 import org.apache.hivemind.lib.util.StrategyRegistryImpl; 25 import org.apache.hivemind.util.PropertyUtils; 26 import org.apache.tapestry.IMarkupWriter; 27 import org.apache.tapestry.IRequestCycle; 28 import org.apache.tapestry.Tapestry; 29 import org.apache.tapestry.form.IFormComponent; 30 31 38 39 public class NumberValidator extends AbstractNumericValidator 40 { 41 private static final Map TYPES = new HashMap (); 42 43 static 44 { 45 TYPES.put("boolean", boolean.class); 46 TYPES.put("Boolean", Boolean .class); 47 TYPES.put("java.lang.Boolean", Boolean .class); 48 TYPES.put("char", char.class); 49 TYPES.put("Character", Character .class); 50 TYPES.put("java.lang.Character", Character .class); 51 TYPES.put("short", short.class); 52 TYPES.put("Short", Short .class); 53 TYPES.put("java.lang.Short", Short .class); 54 TYPES.put("int", int.class); 55 TYPES.put("Integer", Integer .class); 56 TYPES.put("java.lang.Integer", Integer .class); 57 TYPES.put("long", long.class); 58 TYPES.put("Long", Long .class); 59 TYPES.put("java.lang.Long", Long .class); 60 TYPES.put("float", float.class); 61 TYPES.put("Float", Float .class); 62 TYPES.put("java.lang.Float", Float .class); 63 TYPES.put("byte", byte.class); 64 TYPES.put("Byte", Byte .class); 65 TYPES.put("java.lang.Byte", Byte .class); 66 TYPES.put("double", double.class); 67 TYPES.put("Double", Double .class); 68 TYPES.put("java.lang.Double", Double .class); 69 TYPES.put("java.math.BigInteger", BigInteger .class); 70 TYPES.put("java.math.BigDecimal", BigDecimal .class); 71 } 72 73 private Class _valueTypeClass = int.class; 74 75 private Number _minimum; 76 77 private Number _maximum; 78 79 private static StrategyRegistry _numberAdaptors = new StrategyRegistryImpl(); 80 81 public final static int NUMBER_TYPE_INTEGER = 0; 82 83 public final static int NUMBER_TYPE_REAL = 1; 84 85 89 public static abstract class NumberStrategy 90 { 91 97 98 abstract public Number parse(String value); 99 100 107 abstract public int getNumberType(); 108 109 public int compare(Number left, Number right) 110 { 111 if (!left.getClass().equals(right.getClass())) 112 right = coerce(right); 113 114 Comparable lc = (Comparable ) left; 115 116 return lc.compareTo(right); 117 } 118 119 125 protected abstract Number coerce(Number number); 126 } 127 128 private static abstract class IntegerNumberAdaptor extends NumberStrategy 129 { 130 public int getNumberType() 131 { 132 return NUMBER_TYPE_INTEGER; 133 } 134 } 135 136 private static abstract class RealNumberAdaptor extends NumberStrategy 137 { 138 public int getNumberType() 139 { 140 return NUMBER_TYPE_REAL; 141 } 142 } 143 144 private static class ByteAdaptor extends IntegerNumberAdaptor 145 { 146 public Number parse(String value) 147 { 148 return new Byte (value); 149 } 150 151 protected Number coerce(Number number) 152 { 153 return new Byte (number.byteValue()); 154 } 155 } 156 157 private static class ShortAdaptor extends IntegerNumberAdaptor 158 { 159 public Number parse(String value) 160 { 161 return new Short (value); 162 } 163 164 protected Number coerce(Number number) 165 { 166 return new Short (number.shortValue()); 167 } 168 } 169 170 private static class IntAdaptor extends IntegerNumberAdaptor 171 { 172 public Number parse(String value) 173 { 174 return new Integer (value); 175 } 176 177 protected Number coerce(Number number) 178 { 179 return new Integer (number.intValue()); 180 } 181 } 182 183 private static class LongAdaptor extends IntegerNumberAdaptor 184 { 185 public Number parse(String value) 186 { 187 return new Long (value); 188 } 189 190 protected Number coerce(Number number) 191 { 192 return new Long (number.longValue()); 193 } 194 } 195 196 private static class FloatAdaptor extends RealNumberAdaptor 197 { 198 public Number parse(String value) 199 { 200 return new Float (value); 201 } 202 203 protected Number coerce(Number number) 204 { 205 return new Float (number.floatValue()); 206 } 207 } 208 209 private static class DoubleAdaptor extends RealNumberAdaptor 210 { 211 public Number parse(String value) 212 { 213 return new Double (value); 214 } 215 216 protected Number coerce(Number number) 217 { 218 return new Double (number.doubleValue()); 219 } 220 } 221 222 private static class BigDecimalAdaptor extends RealNumberAdaptor 223 { 224 public Number parse(String value) 225 { 226 return new BigDecimal (value); 227 } 228 229 protected Number coerce(Number number) 230 { 231 return new BigDecimal (number.doubleValue()); 232 } 233 } 234 235 private static class BigIntegerAdaptor extends IntegerNumberAdaptor 236 { 237 public Number parse(String value) 238 { 239 return new BigInteger (value); 240 } 241 242 protected Number coerce(Number number) 243 { 244 return new BigInteger (number.toString()); 245 } 246 } 247 248 static 249 { 250 NumberStrategy byteAdaptor = new ByteAdaptor(); 251 NumberStrategy shortAdaptor = new ShortAdaptor(); 252 NumberStrategy intAdaptor = new IntAdaptor(); 253 NumberStrategy longAdaptor = new LongAdaptor(); 254 NumberStrategy floatAdaptor = new FloatAdaptor(); 255 NumberStrategy doubleAdaptor = new DoubleAdaptor(); 256 257 _numberAdaptors.register(Byte .class, byteAdaptor); 258 _numberAdaptors.register(byte.class, byteAdaptor); 259 _numberAdaptors.register(Short .class, shortAdaptor); 260 _numberAdaptors.register(short.class, shortAdaptor); 261 _numberAdaptors.register(Integer .class, intAdaptor); 262 _numberAdaptors.register(int.class, intAdaptor); 263 _numberAdaptors.register(Long .class, longAdaptor); 264 _numberAdaptors.register(long.class, longAdaptor); 265 _numberAdaptors.register(Float .class, floatAdaptor); 266 _numberAdaptors.register(float.class, floatAdaptor); 267 _numberAdaptors.register(Double .class, doubleAdaptor); 268 _numberAdaptors.register(double.class, doubleAdaptor); 269 270 _numberAdaptors.register(BigDecimal .class, new BigDecimalAdaptor()); 271 _numberAdaptors.register(BigInteger .class, new BigIntegerAdaptor()); 272 } 273 274 public NumberValidator() 275 { 276 277 } 278 279 284 285 public NumberValidator(String initializer) 286 { 287 PropertyUtils.configureProperties(this, initializer); 288 } 289 290 public String toString(IFormComponent field, Object value) 291 { 292 if (value == null) 293 return null; 294 295 if (getZeroIsNull()) 296 { 297 Number number = (Number ) value; 298 299 if (number.doubleValue() == 0.0) 300 return null; 301 } 302 303 return value.toString(); 304 } 305 306 private NumberStrategy getStrategy(IFormComponent field) 307 { 308 NumberStrategy result = getStrategy(_valueTypeClass); 309 310 if (result == null) 311 throw new ApplicationRuntimeException(Tapestry.format( 312 "NumberValidator.no-adaptor-for-field", 313 field, 314 _valueTypeClass.getName())); 315 316 return result; 317 } 318 319 330 public static NumberStrategy getStrategy(Class type) 331 { 332 return (NumberStrategy) _numberAdaptors.getStrategy(type); 333 } 334 335 public Object toObject(IFormComponent field, String value) throws ValidatorException 336 { 337 if (checkRequired(field, value)) 338 return null; 339 340 NumberStrategy adaptor = getStrategy(field); 341 Number result = null; 342 343 try 344 { 345 result = adaptor.parse(value); 346 } 347 catch (NumberFormatException ex) 348 { 349 throw new ValidatorException(buildInvalidNumericFormatMessage(field), 350 ValidationConstraint.NUMBER_FORMAT); 351 } 352 353 if (_minimum != null && adaptor.compare(result, _minimum) < 0) 354 throw new ValidatorException(buildNumberTooSmallMessage(field, _minimum), 355 ValidationConstraint.TOO_SMALL); 356 357 if (_maximum != null && adaptor.compare(result, _maximum) > 0) 358 throw new ValidatorException(buildNumberTooLargeMessage(field, _maximum), 359 ValidationConstraint.TOO_LARGE); 360 361 return result; 362 } 363 364 public Number getMaximum() 365 { 366 return _maximum; 367 } 368 369 public boolean getHasMaximum() 370 { 371 return _maximum != null; 372 } 373 374 public void setMaximum(Number maximum) 375 { 376 _maximum = maximum; 377 } 378 379 public Number getMinimum() 380 { 381 return _minimum; 382 } 383 384 public boolean getHasMinimum() 385 { 386 return _minimum != null; 387 } 388 389 public void setMinimum(Number minimum) 390 { 391 _minimum = minimum; 392 } 393 394 397 398 public void renderValidatorContribution(IFormComponent field, IMarkupWriter writer, 399 IRequestCycle cycle) 400 { 401 if (!isClientScriptingEnabled()) 402 return; 403 404 if (!(isRequired() || _minimum != null || _maximum != null)) 405 return; 406 407 Map symbols = new HashMap (); 408 409 if (isRequired()) 410 symbols.put("requiredMessage", buildRequiredMessage(field)); 411 412 if (isIntegerNumber()) 413 symbols.put("formatMessage", buildInvalidIntegerFormatMessage(field)); 414 else 415 symbols.put("formatMessage", buildInvalidNumericFormatMessage(field)); 416 417 if (_minimum != null || _maximum != null) 418 symbols.put("rangeMessage", buildRangeMessage(field, _minimum, _maximum)); 419 420 processValidatorScript(getScriptPath(), cycle, field, symbols); 421 } 422 423 430 431 public void setValueType(String typeName) 432 { 433 Class typeClass = (Class ) TYPES.get(typeName); 434 435 if (typeClass == null) 436 throw new ApplicationRuntimeException(Tapestry.format( 437 "NumberValidator.unknown-type", 438 typeName)); 439 440 _valueTypeClass = typeClass; 441 } 442 443 444 445 public void setValueTypeClass(Class valueTypeClass) 446 { 447 _valueTypeClass = valueTypeClass; 448 } 449 450 455 456 public Class getValueTypeClass() 457 { 458 return _valueTypeClass; 459 } 460 461 462 463 public boolean isIntegerNumber() 464 { 465 NumberStrategy strategy = (NumberStrategy) _numberAdaptors.getStrategy(_valueTypeClass); 466 if (strategy == null) 467 return false; 468 469 return strategy.getNumberType() == NUMBER_TYPE_INTEGER; 470 } 471 472 protected String getDefaultScriptPath() 473 { 474 return "/org/apache/tapestry/valid/NumberValidator.script"; 475 } 476 } | Popular Tags |