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 2000-2004 (C) Intalio, Inc. All Rights Reserved. 42 * 43 * $Id$ 44 */ 45 package org.exolab.castor.xml.validators; 46 47 import java.text.MessageFormat; 48 import java.util.Collections; 49 import java.util.LinkedList; 50 import java.util.List; 51 import java.util.Locale; 52 import java.util.ResourceBundle; 53 54 import org.exolab.castor.util.RegExpEvaluator; 55 import org.exolab.castor.xml.ValidationContext; 56 import org.exolab.castor.xml.ValidationException; 57 58 /** 59 * A simple abstract class used for validating types which allow the pattern 60 * facet. 61 * 62 * @author <a href="mailto:kvisco-at-intalio.com">Keith Visco</a> 63 * @author <a href="mailto:edward.kuns@aspect.com">Edward Kuns</a> 64 * @version $Revision$ $Date: 2004-12-11 02:13:52 -0700 (Sat, 11 Dec 2004) $ 65 */ 66 public abstract class PatternValidator { 67 68 protected static ResourceBundle resourceBundle; 69 70 static { 71 resourceBundle = ResourceBundle.getBundle("ValidationMessages", Locale 72 .getDefault()); 73 } 74 75 /** 76 * The regular expressions to match against. 77 */ 78 private LinkedList<String> _patterns = new LinkedList<String>(); 79 80 /** 81 * If true, object is nillable, otherwise it is not. 82 */ 83 private boolean _nillable = false; 84 85 /** 86 * An instance of the regular expression evaluator if necessary. 87 */ 88 private RegExpEvaluator _regex = null; 89 90 /** 91 * Creates a new {@link PatternValidator} with no initial regular expression. 92 */ 93 public PatternValidator() { 94 super(); 95 96 } 97 98 /** 99 * Creates a new {@link PatternValidator} with the given initial regular expression. 100 * 101 * @param pattern 102 * the regular expression to validate against 103 */ 104 public PatternValidator(final String pattern) { 105 _patterns.add(pattern); 106 } 107 108 /** 109 * Returns the collection of regular expression patterns. 110 * 111 * @return the collection of regular expression patterns. 112 * @see #setPattern 113 */ 114 public List<String> getPatterns() { 115 return Collections.unmodifiableList(_patterns); 116 } 117 118 /** 119 * Returns whether or not objects validated by this Validator are nillable 120 * (are allowed to be null). 121 * 122 * @return true if null is a valid value 123 */ 124 public boolean isNillable() { 125 return _nillable; 126 } 127 128 /** 129 * Returns true if a regular expression has been set for this 130 * PatternValidator. 131 * 132 * @return true if a regular expression has been set for this 133 * PatternValidator 134 */ 135 public boolean hasPattern() { 136 return !_patterns.isEmpty(); 137 } 138 139 /** 140 * Sets whether or not objects validated by this Validator are allowed to be 141 * null (nillable). 142 * 143 * @param nillable 144 * a boolean that when true indicates null values pass validation 145 */ 146 public void setNillable(final boolean nillable) { 147 _nillable = nillable; 148 } 149 150 /** 151 * Sets the regular expression to validate against. 152 * 153 * @param pattern 154 * the regular expression to use when validating 155 */ 156 public void addPattern(final String pattern) { 157 _patterns.add(pattern); 158 } 159 160 /** 161 * Clear all configured patterns. 162 */ 163 public void clearPatterns() { 164 _patterns.clear(); 165 } 166 167 /** 168 * Validates the given String against the regular expression pattern of this 169 * PatternValidator. 170 * 171 * @param str 172 * the string to validate 173 * @param context 174 * the validation context 175 * 176 * @see #setPattern 177 * @throws ValidationException 178 * if the given String is not matched by the regular expression 179 * pattern 180 */ 181 public void validate(final String str, final ValidationContext context) 182 throws ValidationException { 183 if (_patterns.isEmpty()) { 184 return; 185 } 186 187 if (context == null) { 188 throw new IllegalArgumentException(resourceBundle.getString("patternValidator.error.exception")); 189 } 190 191 if (_regex == null) { 192 initEvaluator(context); 193 } 194 195 // Loop over all patterns and return (success) if any one of them matches 196 for (String pattern : _patterns) { 197 _regex.setExpression(pattern); 198 if (_regex.matches(str)) { 199 return; 200 } 201 } 202 203 // If we get here, all patterns failed. 204 StringBuffer buff = new StringBuffer("'" + str + "'"); 205 if (_patterns.size() == 1) { 206 buff.append(MessageFormat.format(resourceBundle 207 .getString("patternValidator.error.pattern.not.match"), 208 new Object[] { _patterns.getFirst() })); 209 } else { 210 StringBuffer patterns = new StringBuffer(); 211 for (String pattern : _patterns) { 212 patterns.append("\""); 213 patterns.append(pattern); 214 patterns.append("\""); 215 } 216 217 buff.append(MessageFormat.format(resourceBundle 218 .getString("patternValidator.error.pattern.not.match.any"), 219 new Object[] { patterns.toString() })); 220 } 221 throw new ValidationException(buff.toString()); 222 } 223 224 /** 225 * Validates the given Object. 226 * 227 * @param object 228 * the Object to validate 229 * @param context 230 * the ValidationContext 231 * @throws ValidationException 232 * if the given String is not matched by the regular expression 233 * pattern 234 */ 235 public void validate(final Object object, final ValidationContext context) 236 throws ValidationException { 237 if (object == null) { 238 if (!_nillable) { 239 String err = resourceBundle.getString("patternValidator.error.cannot.validate.null.object"); 240 throw new ValidationException(err); 241 } 242 return; 243 } 244 validate(object.toString(), context); 245 } 246 247 /** 248 * Initializes the regular expression validator. 249 * @param context 250 * the ValidationContext 251 */ 252 private void initEvaluator(final ValidationContext context) { 253 _regex = context.getInternalContext().getRegExpEvaluator(); 254 if (_regex == null && hasPattern()) { 255 throw new IllegalStateException(resourceBundle.getString("patternValidator.error.exception.noPatterns")); 256 } 257 } 258 259 }