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