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