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 }