1 /* 2 * Redistribution and use of this software and associated documentation 3 * ("Software"), with or without modification, are permitted provided 4 * that the following conditions are met: 5 * 6 * 1. Redistributions of source code must retain copyright 7 * statements and notices. Redistributions must also contain a 8 * copy of this document. 9 * 10 * 2. Redistributions in binary form must reproduce the 11 * above copyright notice, this list of conditions and the 12 * following disclaimer in the documentation and/or other 13 * materials provided with the distribution. 14 * 15 * 3. The name "Exolab" must not be used to endorse or promote 16 * products derived from this Software without prior written 17 * permission of Intalio, Inc. For written permission, 18 * please contact info@exolab.org. 19 * 20 * 4. Products derived from this Software may not be called "Exolab" 21 * nor may "Exolab" appear in their names without prior written 22 * permission of Intalio, Inc. Exolab is a registered 23 * trademark of Intalio, Inc. 24 * 25 * 5. Due credit should be given to the Exolab Project 26 * (http://www.exolab.org/). 27 * 28 * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS 29 * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT 30 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 31 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 32 * INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 33 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 34 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 35 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 37 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 38 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 39 * OF THE POSSIBILITY OF SUCH DAMAGE. 40 * 41 * Copyright 1999-2003 (C) Intalio, Inc. All Rights Reserved. 42 * 43 * $Id$ 44 */ 45 package org.exolab.castor.xml.validators; 46 47 import java.text.MessageFormat; 48 49 import org.castor.xml.XMLProperties; 50 import org.exolab.castor.xml.TypeValidator; 51 import org.exolab.castor.xml.ValidationContext; 52 import org.exolab.castor.xml.ValidationException; 53 54 /** 55 * The Integer Validation class. This class handles validation for the primitive 56 * <code>long</code> and <code>java.lang.Long</code> types as well as all 57 * xsd:integer-derived types such as positive-integer and negative-integer 58 * 59 * @author <a href="mailto:kvisco@intalio.com">Keith Visco</a> 60 * @version $Revision$ $Date: 2006-04-25 15:08:23 -0600 (Tue, 25 Apr 61 * 2006) $ 62 */ 63 public class IntegerValidator extends PatternValidator implements TypeValidator { 64 65 /** If true, we perform "minimum value" validation. */ 66 private boolean _useMin = false; 67 /** If true, we perform "maximum value" validation. */ 68 private boolean _useMax = false; 69 /** If true, we perform "fixed" validation. */ 70 private boolean _useFixed = false; 71 /** Minimum value (inclusive) for this long. (Not used unless _useMin == true.) */ 72 private long _min = 0; 73 /** Maximum value (inclusive) for this long. (Not used unless _useMax == true.) */ 74 private long _max = 0; 75 /** Maximum number of digits in this long. (Not applied if < 0.) */ 76 private int _totalDigits = -1; 77 /** Fixed value of this long. (Not used unless _useFixed == true.) */ 78 private long _fixed = 0; 79 80 /** 81 * Creates a new IntegerValidator with no restrictions. 82 */ 83 public IntegerValidator() { 84 super(); 85 } 86 87 /** 88 * Clears the fixed value for this IntegerValidator. 89 */ 90 public void clearFixed() { 91 _useFixed = false; 92 } 93 94 /** 95 * Clears the maximum value for this IntegerValidator. 96 */ 97 public void clearMax() { 98 _useMax = false; 99 } 100 101 /** 102 * Clears the minimum value for this IntegerValidator. 103 */ 104 public void clearMin() { 105 _useMin = false; 106 } 107 108 /** 109 * Returns the configured fixed value for Integer validation. Returns 110 * null if no fixed value has been configured. 111 * 112 * @return the fixed value to validate against. 113 */ 114 public Long getFixed() { 115 if (_useFixed) { 116 return new Long(_fixed); 117 } 118 return null; 119 } 120 121 /** 122 * Returns the configured maximum value for xsd:integer validation. Returns 123 * null if no maximum has been configured. 124 * 125 * @return the maximum (inclusive) value to validate against. 126 */ 127 public Long getMaxInclusive() { 128 if (_useMax) { 129 return new Long(_max); 130 } 131 return null; 132 } 133 134 /** 135 * Returns the configured minimum value for xsd:integer validation. Returns 136 * null if no minimum has been configured. 137 * 138 * @return the minimum (inclusive) value to validate against. 139 */ 140 public Long getMinInclusive() { 141 if (_useMin) { 142 return new Long(_min); 143 } 144 return null; 145 } 146 147 /** 148 * Returns the configured maximum number of digits (inclusive) for 149 * xsd:integer validation. Returns null if no maximum number of digits has 150 * been configured. 151 * 152 * @return the maximum number of digits to validate against. 153 */ 154 public Integer getTotalDigits() { 155 if (_totalDigits >= 0) { 156 return new Integer(_totalDigits); 157 } 158 return null; 159 } 160 161 /** 162 * Returns true if a fixed value to validate against has been set. 163 * 164 * @return true if a fixed value has been set. 165 */ 166 public boolean hasFixed() { 167 return _useFixed; 168 } 169 170 /** 171 * Sets the fixed value that integers validated with this validated must be 172 * equal to. 173 * <p> 174 * NOTE: Using Fixed values takes preceedence over using max and mins, and 175 * is really the same as setting both max-inclusive and min-inclusive to the 176 * same value 177 * 178 * @param fixedValue 179 * the fixed value an integer validated with this validator must 180 * be equal to. 181 */ 182 public void setFixed(final long fixedValue) { 183 _useFixed = true; 184 this._fixed = fixedValue; 185 } 186 187 /** 188 * Sets the fixed value that integers validated with this validated must be 189 * equal to. 190 * <p> 191 * NOTE: Using Fixed values takes preceedence over using max and mins, and 192 * is really the same as setting both max-inclusive and min-inclusive to the 193 * same value 194 * 195 * Added for backward compatibility with old <xs:integer> implementation. 196 * 197 * @param fixedValue 198 * the fixed value an integer validated with this validator must 199 * be equal to. 200 */ 201 public void setFixed(final int fixedValue) { 202 _useFixed = true; 203 this._fixed = fixedValue; 204 } 205 206 /** 207 * Sets the fixed value for xsd:Integer validation. 208 * <p> 209 * NOTE: If maximum and/or minimum values have been set and the fixed value 210 * is not within that max/min range, then no xsd:Integer will pass 211 * validation. This is as according to the XML Schema spec. 212 * 213 * @param fixedValue 214 * the fixed value that a xsd:Integer validated with this 215 * validator must be equal to. 216 */ 217 public void setFixed(final Long fixedValue) { 218 _useFixed = true; 219 this._fixed = fixedValue.intValue(); 220 } 221 222 /** 223 * Sets the minimum (exclusive) value for xsd:integer validation. To pass 224 * validation, an xsd:Integer must be greater than this value. 225 * 226 * @param minValue 227 * the minimum (exclusive) value for xsd:Integer validation. 228 */ 229 public void setMinExclusive(final long minValue) { 230 _useMin = true; 231 _min = minValue + 1; 232 } 233 234 /** 235 * Sets the minimum (exclusive) value for xsd:integer validation. To pass 236 * validation, an xsd:Integer must be greater than this value. 237 * 238 * Added for backward compatibility with old <xs:integer> implementation. 239 * 240 * @param minValue 241 * the minimum (exclusive) value for xsd:Integer validation. 242 */ 243 public void setMinExclusive(final int minValue) { 244 _useMin = true; 245 _min = minValue + 1; 246 } 247 248 /** 249 * Sets the minimum (inclusive) value for xsd:integer validation. To pass 250 * validation, an xsd:integer must be greater than or equal to this value. 251 * 252 * @param minValue 253 * the minimum (inclusive) value for xsd:integer validation. 254 */ 255 public void setMinInclusive(final long minValue) { 256 _useMin = true; 257 _min = minValue; 258 } 259 260 /** 261 * Sets the minimum (inclusive) value for xsd:integer validation. To pass 262 * validation, an xsd:integer must be greater than or equal to this value. 263 * 264 * Added for backward compatibility with old <xs:integer> implementation. 265 * 266 * @param minValue 267 * the minimum (inclusive) value for xsd:integer validation. 268 */ 269 public void setMinInclusive(final int minValue) { 270 _useMin = true; 271 _min = minValue; 272 } 273 274 /** 275 * Sets the maximum (exclusive) value for xsd:integer validation. To pass 276 * validation, a xsd:integer must be less than this value. 277 * 278 * @param maxValue 279 * the maximum (exclusive) value for xsd:integer validation. 280 */ 281 public void setMaxExclusive(final long maxValue) { 282 _useMax = true; 283 _max = maxValue - 1; 284 } 285 286 /** 287 * Sets the maximum (exclusive) value for xsd:integer validation. To pass 288 * validation, a xsd:integer must be less than this value. 289 * 290 * Added for backward compatibility with old <xs:integer> implementation. 291 * 292 * @param maxValue 293 * the maximum (exclusive) value for xsd:integer validation. 294 */ 295 public void setMaxExclusive(final int maxValue) { 296 _useMax = true; 297 _max = maxValue - 1; 298 } 299 300 301 /** 302 * Sets the maximum (inclusive) value for xsd:integer validation. To pass 303 * validation, a xsd:integer must be less than or equal to this value. 304 * 305 * @param maxValue 306 * the maximum (inclusive) value for xsd:integer validation. 307 */ 308 public void setMaxInclusive(final long maxValue) { 309 _useMax = true; 310 _max = maxValue; 311 } 312 313 /** 314 * Sets the maximum (inclusive) value for xsd:integer validation. To pass 315 * validation, a xsd:integer must be less than or equal to this value. 316 * 317 * Added for backward compatibility with old <xs:integer> implementation. 318 * 319 * @param maxValue 320 * the maximum (inclusive) value for xsd:integer validation. 321 */ 322 public void setMaxInclusive(final int maxValue) { 323 _useMax = true; 324 _max = maxValue; 325 } 326 327 /** 328 * Sets the maximum number of digits for xsd:integer validation. To pass 329 * validation, a xsd:integer must have this many digits or fewer. Leading 330 * zeros are not counted. 331 * 332 * @param totalDig 333 * the maximum (inclusive) number of digits for xsd:integer 334 * validation. (must be > 0) 335 */ 336 public void setTotalDigits(final int totalDig) { 337 if (totalDig <= 0) { 338 throw new IllegalArgumentException( 339 "IntegerValidator: the totalDigits facet must be positive"); 340 } 341 _totalDigits = totalDig; 342 } 343 344 /** 345 * Validates the given Object. 346 * 347 * @param value 348 * the long to validate 349 * @param context 350 * the ValidationContext 351 * @throws ValidationException if the object fails validation. 352 */ 353 public void validate(final long value, final ValidationContext context) 354 throws ValidationException { 355 if (_useFixed && value != _fixed) { 356 String err = MessageFormat.format(resourceBundle.getString("integerValidator.error.not.fixed.value"), 357 new Object[] {"long", value, _fixed }); 358 throw new ValidationException(err); 359 } 360 361 if (_useMin && value < _min) { 362 String err = MessageFormat.format(resourceBundle.getString("integerValidator.error.less.than.minimum"), 363 new Object[] {"long", value, _min }); 364 throw new ValidationException(err); 365 } 366 367 if (_useMax && value > _max) { 368 String err = MessageFormat.format(resourceBundle.getString("integerValidator.error.greater.than.maximum"), 369 new Object[] {"long", value, _min }); 370 throw new ValidationException(err); 371 } 372 373 if (_totalDigits != -1) { 374 int length = Long.toString(value).length(); 375 if (value < 0) { 376 length--; 377 } 378 if (length > _totalDigits) { 379 String err = MessageFormat.format(resourceBundle.getString("integerValidator.error.too.many.digits"), 380 new Object[] {"long", value, _totalDigits }); 381 throw new ValidationException(err); 382 } 383 } 384 385 if (hasPattern()) { 386 super.validate(Long.toString(value), context); 387 } 388 } 389 390 /** 391 * Validates the given Object. 392 * 393 * @param object 394 * the Object to validate 395 * @throws ValidationException if the object fails validation. 396 */ 397 public void validate(final Object object) throws ValidationException { 398 validate(object, (ValidationContext) null); 399 } 400 401 /** 402 * Validates the given Object. 403 * 404 * @param object 405 * the Object to validate 406 * @param context 407 * the ValidationContext 408 * @throws ValidationException if the object fails validation. 409 */ 410 public void validate(final Object object, final ValidationContext context) 411 throws ValidationException { 412 if (object == null) { 413 throw new ValidationException(resourceBundle.getString("integerValidator.error.null.object")); 414 } 415 416 long value = 0; 417 try { 418 value = ((Long) object).longValue(); 419 } catch (Exception ex) { 420 String lenientProperty = context.getInternalContext() 421 .getStringProperty(XMLProperties.LENIENT_INTEGER_VALIDATION); 422 if (Boolean.valueOf(lenientProperty).booleanValue()) { 423 try { 424 value = ((Integer) object).longValue(); 425 } catch (Exception e) { 426 String err = MessageFormat.format(resourceBundle.getString("integerValidator.error.wrong.class.lenient"), 427 new Object[] { object.getClass().getName() }); 428 throw new ValidationException(err); 429 } 430 } else { 431 String err = MessageFormat.format(resourceBundle.getString("integerValidator.error.wrong.class"), 432 new Object[] { object.getClass().getName() }); 433 throw new ValidationException(err); 434 } 435 } 436 validate(value, context); 437 } 438 439 }