/**
* Redistribution and use of this software and associated documentation
* ("Software"), with or without modification, are permitted provided
* that the following conditions are met:
*
* 1. Redistributions of source code must retain copyright
* statements and notices. Redistributions must also contain a
* copy of this document.
*
* 2. Redistributions in binary form must reproduce the
* above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. The name "Exolab" must not be used to endorse or promote
* products derived from this Software without prior written
* permission of Intalio, Inc. For written permission,
* please contact info@exolab.org.
*
* 4. Products derived from this Software may not be called "Exolab"
* nor may "Exolab" appear in their names without prior written
* permission of Intalio, Inc. Exolab is a registered
* trademark of Intalio, Inc.
*
* 5. Due credit should be given to the Exolab Project
* (http://www.exolab.org/).
*
* THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Copyright 2000-2004 (C) Intalio, Inc. All Rights Reserved.
*
* $Id: FieldValidator.java,v 1.10 2004/10/09 04:58:55 kvisco Exp $
*/
package org.exolab.castor.xml;
import java.util.List;
import java.util.Vector;
import java.util.Enumeration;
import java.lang.reflect.Array;
import org.exolab.castor.mapping.FieldHandler;
/**
* Handles field validation
*
* @author <a href="mailto:kvisco-at-intalio.com">Keith Visco</a>
* @version $Revision: 1.10 $ $Date: 2004/10/09 04:58:55 $
*/
public class FieldValidator extends Validator {
private static final String ERROR_NAME = "-error-if-this-is-used-";
private int minOccurs = 0; //-- default minimum occurance
private int maxOccurs = -1; //-- default maximum occurance [none]
private XMLFieldDescriptor _descriptor = null;
/**
* The actual type validator which is used to validate
* single instances of the field.
**/
private TypeValidator _validator = null;
/**
* Creates a default FieldValidator
*
**/
public FieldValidator() {
super();
} //-- FieldValidator
/**
* Creates a new FieldValidator using the given TypeValidator
* @param validator the TypeValidator to delegate validation to
**/
public FieldValidator(TypeValidator validator) {
super();
this._validator = validator;
} //-- FieldValidator
/**
* Returns the mimimum number of occurances for a given object.
*
* @returns the mimimum number of occurances for a given object.
* A zero value denotes no lower bound
* (ie. the object is optional)
**/
public int getMinOccurs() {
return minOccurs;
} //-- getMinOccurs
/**
* Returns the maximum number of occurances for a given object.
*
* @returns the maximum number of occurances for a given object.
* A negative value denotes no upper bound.
*
**/
public int getMaxOccurs() {
return maxOccurs;
} //-- getMaxOccurs
/**
* Returns true if a TypeValidator has been set
*
* @return true if a TypeValidator has been set
**/
public TypeValidator getTypeValidator() {
return _validator;
} //-- getTypeValidator
/**
* Returns true if a TypeValidator has been set
*
* @return true if a TypeValidator has been set
**/
public boolean hasTypeValidator() {
return (_validator != null);
} //-- hasTypeValidator
/**
* Sets the mimimum number of occurances for a given object
*
* @param minOccurs the minimum number of times an object must occur
* in order to be valid.
* A zero, or negative value denotes no lower bound
* (ie. the object is optional)
**/
public void setMinOccurs(int minOccurs) {
this.minOccurs = (minOccurs < 0) ? 0 : minOccurs;
} //-- setMinOccurs
/**
* Sets the maximum number of occurances for a given object
*
* @param maxOccurs the maximum number of times an object
* may occur. A negative value denotes no upper bound.
*
**/
public void setMaxOccurs(int maxOccurs) {
this.maxOccurs = maxOccurs;
} //-- setMaxOccurs
/**
* Sets the field descriptor to use for obtaining information
* about the field to validate, such as the field name, the field
* handler, etc.
* @param descriptor the field descriptor for the field to validate
**/
public void setDescriptor(XMLFieldDescriptor descriptor) {
this._descriptor = descriptor;
} //-- setDescriptor
public void setValidator(TypeValidator validator) {
this._validator = validator;
} //-- setValidator
/**
* Validates the given Object
*
* @param object the Object that contains the field to validate
* @param context the ValidationContext
*/
public void validate(Object object, ValidationContext context)
throws ValidationException
{
if (_descriptor == null) return;
if (object == null) return;
//-- Do not validate references as these should
//-- be validated elsewhere, validating them
//-- here could cause endless loops
if (_descriptor.isReference()) return;
//-- don't validate "transient" fields...
if (_descriptor.isTransient()) return;
FieldHandler handler = _descriptor.getHandler();
if (handler == null) return;
//-- get the value of the field
Object value = handler.getValue(object);
if (value == null) {
if (!_descriptor.isRequired() || _descriptor.isNillable()) return;
String err = "The field '" + _descriptor.getFieldName() + "' ";
if (!ERROR_NAME.equals(_descriptor.getXMLName())) {
err += "(whose xml name is '" + _descriptor.getXMLName() + "') ";
}
err += "is a required field of class '" + object.getClass().getName();
throw new ValidationException(err);
}
//-- prevent endless loop!
//-- have we seen this object yet?
if (context != null) {
if (context.isValidated(object))
return;
//-- mark object as processed
context.addValidated(object);
}
Class type = value.getClass();
int size = 1;
try {
boolean byteArray = false;
if (type.isArray()) {
byteArray = (type.getComponentType() == Byte.TYPE);
if (!byteArray) {
size = Array.getLength(value);
if (_validator != null) {
for (int i = 0; i < size; i++)
_validator.validate(Array.get(value, i), context);
}
else {
for (int i = 0; i < size; i++)
super.validate(Array.get(value, i), context);
}
}
}
//-- <NOTE>
//-- The following code should be changed
//-- to use CollectionHandler
//-- </NOTE>
else if (value instanceof Enumeration) {
Enumeration enumeration = (Enumeration)value;
size = 0;
while (enumeration.hasMoreElements()) {
++size;
Object obj = enumeration.nextElement();
if (_validator != null)
_validator.validate(obj, context);
else
super.validate(obj, context);
}
}
else if (value instanceof Vector) {
Vector vector = (Vector)value;
size = vector.size();
for (int i = 0; i < size; i++) {
if (_validator != null)
_validator.validate(vector.elementAt(i), context);
else
super.validate(vector.elementAt(i), context);
}
}
else if (value instanceof List) {
List list = (List)value;
size = list.size();
for (int i = 0; i < size; i++) {
if (_validator != null)
_validator.validate(list.get(i), context);
else
super.validate(list.get(i), context);
}
}
else {
if (_validator != null)
_validator.validate(value, context);
else
super.validate(value, context);
}
}
catch(ValidationException vx) {
//-- add additional validation information
String err = "The following exception occured while validating field: " +
_descriptor.getFieldName() + " of class: " + object.getClass().getName();
throw new ValidationException(err, vx);
}
//-- Check size of collection
//-- check minimum
if (size < minOccurs) {
//-- If any items exist (size != 0) or the descriptor
//-- is marked as required then we need to report the
//-- error. Otherwise size == 0 and field is not
//-- required, so no error.
if ((size != 0) || (_descriptor.isRequired())) {
String err = "A minimum of " + minOccurs + " ";
err += _descriptor.getFieldName() + " object(s) ";
if (!ERROR_NAME.equals(_descriptor.getXMLName())) {
err += "(whose xml name is '" + _descriptor.getXMLName() + "') ";
}
err += "are required for class: " + object.getClass().getName();
throw new ValidationException(err);
}
}
//-- check maximum
if ((maxOccurs >= 0) && (size > maxOccurs)) {
String err = "A maximum of " + maxOccurs + " ";
err += _descriptor.getFieldName() + " object(s) ";
if (!ERROR_NAME.equals(_descriptor.getXMLName())) {
err += "(whose xml name is '" + _descriptor.getXMLName() + "') ";
}
err += "are required for class: " + object.getClass().getName() + ".";
throw new ValidationException(err);
}
if (context != null) {
context.removeValidated(object);
}
} //-- validate
} //-- FieldValidator