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 }