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 org.exolab.castor.xml.TypeValidator;
48  import org.exolab.castor.xml.ValidationContext;
49  import org.exolab.castor.xml.ValidationException;
50  import org.exolab.castor.xml.XMLConstants;
51  
52  /**
53   * The String Validation class.
54   *
55   * @author <a href="mailto:kvisco@intalio.com">Keith Visco</a>
56   * @version $Revision$ $Date: 2004-12-11 02:13:52 -0700 (Sat, 11 Dec 2004) $
57   */
58  public class StringValidator extends PatternValidator implements TypeValidator {
59  
60      /** If true, this field must be present. */
61      private boolean             _required   = false;
62      /** Whitespace handing for this String.  (Really belongs elsewhere.) */
63      private String              _whiteSpace = XMLConstants.WHITESPACE_PRESERVE;
64      /** Exact length required of the string.  0 means no length requirement. */
65      private int                 _length     = 0;
66      /** Minimum length required of the string.  0 means no minimum length requirement. */
67      private int                 _minLength  = 0;
68      /** Maximum length required of the string.  -1 means no maximum length requirement. */
69      private int                 _maxLength  = -1;
70      /** Fixed value of this string, null if none is set. */
71      private String              _fixed      = null;
72  
73      /**
74       * Creates a new StringValidator with no restrictions.
75       */
76      public StringValidator() {
77          super();
78      } // -- StringValidator
79  
80      /**
81       * Clears the fixed value for this ShortValidator.
82       */
83      public void clearFixed() {
84          _fixed = null;
85      } // -- clearFixed
86  
87      /**
88       * Sets the fixed value in which all valid Strings must match.
89       *
90       * @param fixedValue
91       *            the fixed value that all Strings must match
92       */
93      public void setFixed(final String fixedValue) {
94          this._fixed = fixedValue;
95      } // -- setFixedValue
96  
97      /**
98       * Only used for backward compatibility for object model generated with an
99       * old version of Castor.
100      *
101      * @param fixedValue
102      *            the fixed value that all Strings must match
103      *
104      * @deprecated since 0.9.4_beta
105      */
106     public void setFixedValue(final String fixedValue) {
107         setFixed(fixedValue);
108     }
109 
110     /**
111      * Sets the maximum string length for String validation. To pass validation,
112      * a String must be shorter than or equal to this length. To remove this
113      * facet, set a negative value.
114      *
115      * @param maxLength
116      *            the maximum length for valid Strings
117      */
118     public void setMaxLength(final int maxLength) {
119         this._maxLength = maxLength;
120     } // -- setMaxLength
121 
122     /**
123      * Sets the minimum string length for String validation. To pass validation,
124      * a String must be longer than or equal to this length. To remove this
125      * facet, set a negative value.
126      *
127      * @param minLength
128      *            the minimum length for valid Strings
129      */
130     public void setMinLength(final int minLength) {
131         this._minLength = minLength;
132     } // -- setMinLength
133 
134     /**
135      * Sets the required string length for String validation. To pass
136      * validation, a String must be exactly this many characters long. To remove
137      * this facet, set a negative value.
138      *
139      * @param length
140      *            the required length for valid Strings
141      */
142     public void setLength(final int length) {
143         this._length = length;
144         setMaxLength(length);
145         setMinLength(length);
146     } // -- setLength
147 
148     /**
149      * Sets whether or not a String is required (non null).
150      *
151      * @param required
152      *            the flag indicating whether this string must be non-null.
153      */
154     public void setRequired(final boolean required) {
155         this._required = required;
156     } // -- setRequired
157 
158     /**
159      * Sets the whiteSpace facet of the validator.
160      * <p>
161      * The value of the whiteSpace facet must be one of the following:
162      * <ul>
163      * <li>preserve</li>
164      * <li>replace</li>
165      * <li>collapse</li>
166      * </ul>
167      * any other value will generate a Warning and set the whiteSpace to
168      * preserve.
169      * <p>
170      * FIXME:  This is not really a function of validation, but of XML
171      * processing before the string is returned from the XML processor.  This
172      * should be moved to the FieldHandler, or somewhere else, but not here.
173      *
174      * @param value
175      *            the whiteSpace value
176      */
177     public void setWhiteSpace(final String value) {
178         if (value.equals(XMLConstants.WHITESPACE_PRESERVE)) {
179             this._whiteSpace = value;
180         } else if (value.equals(XMLConstants.WHITESPACE_REPLACE)) {
181             this._whiteSpace = value;
182         } else if (value.equals(XMLConstants.WHITESPACE_COLLAPSE)) {
183             this._whiteSpace = value;
184         } else {
185             System.out.println("Warning: '" + value
186                     + "' is a bad entry for the whiteSpace value");
187             this._whiteSpace = XMLConstants.WHITESPACE_PRESERVE;
188         }
189     } // -- setWhiteSpace
190 
191     /**
192      * Normalizes the given string according to the whiteSpace facet used.
193      * <p>
194      * FIXME: THIS METHOD SHOULD NOT BE HERE..SHOULD BE MOVED TO A FieldHandler
195      * or to the Unmarshaller...but not here!!! (kvisco 20030125)
196      * @param value
197      *            the String to normalize
198      * @return the normalized string.
199      */
200     public String normalize(final String value) {
201         if (value == null) {
202             return null;
203         }
204 
205         if (value.length() == 0) {
206             return value;
207         }
208 
209         char[] chars = value.toCharArray();
210         int length = chars.length;
211 
212         for (int i = 0; i < length; i++) {
213             switch (chars[i]) {
214                 case '\t':
215                 case '\r':
216                 case '\n':
217                     chars[i] = ' ';
218                     break;
219                 default:
220                     continue;
221             }
222         }
223 
224         if (_whiteSpace.equals(XMLConstants.WHITESPACE_COLLAPSE)) {
225             // -- heavy method to keep compatibility
226             // -- with JDK 1.1 (can't use Vector.toArray)
227             char[] temp = new char[chars.length];
228             int tempCount = 0;
229             int i = 0;
230             while (i < length - 1) {
231                 if (chars[i] == ' ') {
232                     // --put the first space
233                     temp[tempCount] = chars[i];
234                     tempCount++;
235                     // --skip the others
236                     i++;
237                     while (i < length - 1 && chars[i] == ' ') {
238                         i++;
239                     }
240                     continue;
241                 }
242                 temp[tempCount] = chars[i];
243                 tempCount++;
244                 i++;
245             }
246             // --we are at the end
247             if (chars[i] != ' ') {
248                 temp[tempCount] = chars[i];
249             }
250 
251             length = ++tempCount;
252             chars = temp;
253         }
254 
255         return new String(chars, 0, length);
256     }
257 
258     /**
259      * Validates the given Object.
260      *
261      * @param value
262      *            the string to validate
263      * @param context
264      *            the ValidationContext
265      * @throws ValidationException if the object fails validation.
266      */
267     public void validate(final String value, final ValidationContext context)
268                                                     throws ValidationException {
269         if (value == null) {
270             if (_required && !isNillable()) {
271                 String err = "this is a required field and cannot be null.";
272                 throw new ValidationException(err);
273             }
274             return;
275         }
276 
277         if (_fixed != null && !_fixed.equals(value)) {
278             String err = "strings of this type must be equal to the fixed value of " + _fixed;
279             throw new ValidationException(err);
280         }
281 
282         int len = value.length();
283 
284         if (_length > 0 && len != _length) {
285             String err = "Strings of this type must have a length of " + _length + " characters";
286             throw new ValidationException(err);
287         }
288 
289         if (_minLength > 0 && len < _minLength) {
290             String err = "Strings of this type must have a minimum length of " + _minLength
291                     + " characters";
292             throw new ValidationException(err);
293         }
294 
295         if (_maxLength >= 0 && len > _maxLength) {
296             String err = "Strings of this type must have a maximum length of " + _maxLength
297                     + " characters";
298             throw new ValidationException(err);
299         }
300 
301         if (hasPattern()) {
302             super.validate(value, context);
303         }
304 
305         if (!this._whiteSpace.equals(XMLConstants.WHITESPACE_PRESERVE)) {
306             normalize(value);
307         }
308     } // -- validate
309 
310     /**
311      * Validates the given Object.
312      *
313      * @param object
314      *            the Object to validate
315      * @throws ValidationException if the object fails validation.
316      */
317     public void validate(final Object object) throws ValidationException {
318         validate(object, (ValidationContext) null);
319     } // -- validate
320 
321     /**
322      * Validates the given Object.
323      *
324      * @param object
325      *            the Object to validate
326      * @param context
327      *            the ValidationContext
328      * @throws ValidationException if the object fails validation.
329      */
330     public void validate(final Object object, final ValidationContext context)
331                                                     throws ValidationException {
332         if (object == null) {
333             if (_required) {
334                 String err = "this is a required field and cannot be null.";
335                 throw new ValidationException(err);
336             }
337             return;
338         }
339 
340         validate(object.toString(), context);
341     } //-- validate
342 
343 } //-- StringValidator