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