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