View Javadoc
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 &lt;xs:integer&gt; 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 &lt;xs:integer&gt; 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 &lt;xs:integer&gt; 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 &lt;xs:integer&gt; 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 &lt;xs:integer&gt; 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 }