View Javadoc
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 }