View Javadoc
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 (C) Intalio, Inc. All Rights Reserved.
32   *
33   * $Id$
34   */
35  package org.exolab.castor.xml.validators;
36  
37  import java.lang.reflect.Array;
38  import java.util.Enumeration;
39  import java.util.Vector;
40  
41  import org.exolab.castor.xml.TypeValidator;
42  import org.exolab.castor.xml.ValidationContext;
43  import org.exolab.castor.xml.ValidationException;
44  
45  /**
46   * A class for defining simple rules used for validating a content model.
47   * 
48   * @author <a href="mailto:kvisco@intalio.com">Keith Visco</a>
49   * @version $Revision$ $Date: 2004-10-01 07:25:46 -0600 (Fri, 01 Oct 2004) $
50   */
51  public class SimpleTypeValidator implements TypeValidator {
52  
53    /** The minimum number of occurences allowed. */
54    private int _minOccurs = 0;
55    /** The maximum number of occurences allowed. */
56    private int _maxOccurs = -1;
57    /** The type validate to delegate validation to. */
58    private TypeValidator _validator = null;
59  
60    /**
61     * Creates a default SimpleTypeValidator.
62     */
63    public SimpleTypeValidator() {
64      super();
65    }
66  
67    /**
68     * Creates a SimpleTypeValidator using the given TypeValidator for delegating validation.
69     * 
70     * @param validator The TypeValidator to use
71     */
72    public SimpleTypeValidator(final TypeValidator validator) {
73      super();
74      this._validator = validator;
75    }
76  
77    /**
78     * Sets the maximum number of times that the described field may occur.
79     *
80     * @param maxOccurs the maximum number of times that the described field may occur.
81     */
82    public void setMaxOccurs(final int maxOccurs) {
83      this._maxOccurs = maxOccurs;
84    }
85  
86    /**
87     * Sets the minimum number of times that the described field may occur.
88     *
89     * @param minOccurs the minimum number of times that the described field may occur.
90     */
91    public void setMinOccurs(final int minOccurs) {
92      this._minOccurs = minOccurs;
93    }
94  
95    /**
96     * Sets the TypeValidator to delegate validation to.
97     *
98     * @param validator the TypeValidator to delegate validation to.
99     */
100   public void setValidator(final TypeValidator validator) {
101     this._validator = validator;
102   }
103 
104   /**
105    * Validates the given Object.
106    *
107    * @param object the Object to validate.
108    * @param context the ValidationContext.
109    * @throws ValidationException if validation fails.
110    */
111   public void validate(final Object object, final ValidationContext context)
112       throws ValidationException {
113     boolean required = (_minOccurs > 0);
114 
115     if (object == null && required) {
116       String err = "This field is required and cannot be null.";
117       throw new ValidationException(err);
118     }
119 
120     if (object != null) {
121       Class type = object.getClass();
122 
123       int size = 1;
124       boolean byteArray = false;
125       if (type.isArray()) {
126         byteArray = (type.getComponentType() == Byte.TYPE);
127         if (!byteArray) {
128           size = Array.getLength(object);
129         }
130       }
131 
132       // -- check minimum
133       if (size < _minOccurs) {
134         String err = "A minimum of " + _minOccurs + " instance(s) of this field is required.";
135         throw new ValidationException(err);
136       }
137 
138       // -- check maximum
139       if (_maxOccurs >= 0 && size > _maxOccurs) {
140         String err = "A maximum of " + _maxOccurs + " instance(s) of this field are allowed.";
141         throw new ValidationException(err);
142       }
143 
144       if (_validator == null) {
145         return;
146       }
147 
148       // -- check type
149       if (isPrimitive(type) || (type == String.class)) {
150         _validator.validate(object, context);
151       } else if (byteArray) {
152         // -- do nothing for now
153       } else if (type.isArray()) {
154         size = Array.getLength(object);
155         for (int i = 0; i < size; i++) {
156           _validator.validate(Array.get(object, i), context);
157         }
158       } else if (object instanceof java.util.Enumeration) {
159         Enumeration enumeration = (Enumeration) object;
160         while (enumeration.hasMoreElements()) {
161           _validator.validate(enumeration.nextElement(), context);
162         }
163       } else if (object instanceof java.util.Vector) {
164         Vector vector = (Vector) object;
165         for (int i = 0; i < vector.size(); i++) {
166           _validator.validate(vector.elementAt(i), context);
167         }
168       } else {
169         _validator.validate(object, context);
170       }
171     }
172   }
173 
174   // -------------------/
175   // - Private Methods -/
176   // -------------------/
177 
178   /**
179    * Returns true if the given class type should be treated as a primitive. Wrapper objects such as
180    * java.lang.Integer, and java.lang.Float, will be treated as primitives.
181    *
182    * @param type the Class to check
183    * @return true if the given class should be treated as a primitive type.
184    */
185   private boolean isPrimitive(final Class type) {
186     if (type.isPrimitive()) {
187       return true;
188     }
189 
190     return (type == Boolean.class || type == Byte.class || type == Character.class
191         || type == Double.class || type == Float.class || type == Integer.class
192         || type == Long.class || type == Short.class);
193   }
194 
195 }