blob: 0023f1e5107e2b783aa90b92b174728d663eadb4 [file] [log] [blame]
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 2001 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 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 end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Xerces" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``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 THE APACHE SOFTWARE FOUNDATION 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.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 2001, International
* Business Machines, Inc., http://www.apache.org. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.xerces.impl.dv.xs_new;
import org.apache.xerces.impl.dv.XSSimpleType;
import org.apache.xerces.impl.dv.XSAtomicSimpleType;
import org.apache.xerces.impl.dv.XSListSimpleType;
import org.apache.xerces.impl.dv.XSUnionSimpleType;
import org.apache.xerces.impl.dv.XSFacets;
import org.apache.xerces.impl.dv.InvalidDatatypeValueException;
import org.apache.xerces.impl.dv.InvalidDatatypeFacetException;
import org.apache.xerces.impl.dv.ValidatedInfo;
import org.apache.xerces.impl.dv.DatatypeMessageProvider;
import org.apache.xerces.impl.validation.ValidationContext;
import org.apache.xerces.impl.xs.XSTypeDecl;
import org.apache.xerces.util.XMLChar;
import org.apache.xerces.impl.xpath.regex.RegularExpression;
import java.util.Vector;
import java.util.StringTokenizer;
/**
* @author Sandy Gao, IBM
* @author Neeraj Bajaj, Sun Microsystems, inc.
*
* @version $Id$
*/
class XSSimpleTypeDecl implements XSAtomicSimpleType, XSListSimpleType, XSUnionSimpleType {
static final short DV_ANYSIMPLETYPE = 0;
static final short DV_STRING = 1;
static final short DV_BOOLEAN = 2;
static final short DV_DECIMAL = 3;
static final short DV_FLOAT = 4;
static final short DV_DOUBLE = 5;
static final short DV_DURATION = 6;
static final short DV_DATETIME = 7;
static final short DV_TIME = 8;
static final short DV_DATE = 9;
static final short DV_GYEARMONTH = 10;
static final short DV_GYEAR = 11;
static final short DV_GMONTHDAY = 12;
static final short DV_GDAY = 13;
static final short DV_GMONTH = 14;
static final short DV_HEXBINARY = 15;
static final short DV_BASE64BINARY = 16;
static final short DV_ANYURI = 17;
static final short DV_QNAME = 18;
static final short DV_NOTATION = 19;
static final short DV_ID = 20;
static final short DV_IDREF = 21;
static final short DV_ENTITY = 22;
static final short DV_LIST = 23;
static final short DV_UNION = 24;
static final TypeValidator[] fDVs = {
new AnySimpleDV(),
new StringDV(),
new BooleanDV(),
new DecimalDV(),
new FloatDV(),
new DoubleDV(),
new DurationDV(),
new DateTimeDV(),
new TimeDV(),
new DateDV(),
new YearMonthDV(),
new YearDV(),
new MonthDayDV(),
new DayDV(),
new MonthDV(),
new HexBinaryDV(),
new Base64BinaryDV(),
new AnyURIDV(),
new QNameDV(),
new QNameDV(), // notation use the same one as qname
new IDDV(),
new IDREFDV(),
new EntityDV(),
new ListDV(),
new UnionDV()
};
static final short SPECIAL_TOKEN_NONE = 0;
static final short SPECIAL_TOKEN_NMTOKEN = 1;
static final short SPECIAL_TOKEN_NAME = 2;
static final short SPECIAL_TOKEN_NCNAME = 3;
static final String[] SPECIAL_TOKEN_STRING = {
"NONE", "NMTOKEN", "Name", "NCName",
};
static final String[] WS_FACET_STRING = {
"preserve", "collapse", "replace",
};
private XSSimpleTypeDecl fItemType;
private XSSimpleTypeDecl[] fMemberTypes;
private String fTypeName;
private String fTargetNamespace;
private short fFinalSet = 0;
private XSSimpleTypeDecl fBase;
private short fVariety = -1;
private short fValidationDV = -1;
private short fFacetsDefined = 0;
private short fFixedFacet = 0;
//for constraining facets
private short fWhiteSpace = 0;
private int fLength = -1;
private int fMinLength = -1;
private int fMaxLength = -1;
private int fTotalDigits = -1;
private int fFractionDigits = -1;
private Vector fPattern;
private Vector fEnumeration;
private Object fMaxInclusive;
private Object fMaxExclusive;
private Object fMinExclusive;
private Object fMinInclusive;
private short fTokenType = SPECIAL_TOKEN_NONE;
// for fundamental facets
private short fOrdered;
private short fCardinality;
private boolean fBounded;
private boolean fNumeric;
private ValidatedInfo fTempInfo = new ValidatedInfo();
//Create a new built-in primitive types (and id/idref/entity)
protected XSSimpleTypeDecl(XSSimpleTypeDecl base, String name, short validateDV,
short ordered, boolean bounded,
short cardinality, boolean numeric) {
fBase = base;
fTypeName = name;
fTargetNamespace = SchemaDVFactoryImpl.URI_SCHEMAFORSCHEMA;
fVariety = VARIETY_ATOMIC;
fValidationDV = validateDV;
fFacetsDefined = FACET_WHITESPACE;
if (validateDV == DV_STRING) {
fWhiteSpace = WS_PRESERVE;
} else {
fWhiteSpace = WS_COLLAPSE;
fFixedFacet = FACET_WHITESPACE;
}
}
//Create a new simple type for restriction.
protected XSSimpleTypeDecl(XSSimpleTypeDecl base, String name, String uri, short finalSet) {
fBase = base;
fTypeName = name;
fTargetNamespace = uri;
fFinalSet = finalSet;
fVariety = fBase.fVariety;
fValidationDV = fBase.fValidationDV;
switch (fVariety) {
case VARIETY_ATOMIC:
break;
case VARIETY_LIST:
fItemType = fBase.fItemType;
break;
case VARIETY_UNION:
fMemberTypes = fBase.fMemberTypes;
break;
}
// always inherit facets from the base.
// in case a type is created, but applyFacets is not called
fLength = fBase.fLength;
fMinLength = fBase.fMinLength;
fMaxLength = fBase.fMaxLength;
fPattern = fBase.fPattern;
fEnumeration = fBase.fEnumeration;
fWhiteSpace = fBase.fWhiteSpace;
fMaxExclusive = fBase.fMaxExclusive;
fMaxInclusive = fBase.fMaxInclusive;
fMinExclusive = fBase.fMinExclusive;
fMinInclusive = fBase.fMinInclusive;
fTotalDigits = fBase.fTotalDigits;
fFractionDigits = fBase.fFractionDigits;
fTokenType = fBase.fTokenType;
fFixedFacet = fBase.fFixedFacet;
fFacetsDefined = fBase.fFacetsDefined;
//we also set fundamental facets information in case applyFacets is not called.
caclFundamentalFacets();
}
//Create a new simple type for list.
protected XSSimpleTypeDecl(String name, String uri, short finalSet, XSSimpleTypeDecl itemType) {
fBase = fAnySimpleType;
fTypeName = name;
fTargetNamespace = uri;
fFinalSet = finalSet;
fVariety = VARIETY_LIST;
fItemType = (XSSimpleTypeDecl)itemType;
fValidationDV = DV_LIST;
fFacetsDefined = FACET_WHITESPACE;
fFixedFacet = FACET_WHITESPACE;
fWhiteSpace = WS_COLLAPSE;
//setting fundamental facets
caclFundamentalFacets();
}
//Create a new simple type for union.
protected XSSimpleTypeDecl(String name, String uri, short finalSet, XSSimpleTypeDecl[] memberTypes) {
fBase = fAnySimpleType;
fTypeName = name;
fTargetNamespace = uri;
fFinalSet = finalSet;
fVariety = VARIETY_UNION;
fMemberTypes = memberTypes;
fValidationDV = DV_UNION;
// even for union, we set whitespace to something
// this will never be used, but we can use fFacetsDefined to check
// whether applyFacets() is allwwed: it's not allowed
// if fFacetsDefined != 0
fFacetsDefined = FACET_WHITESPACE;
fWhiteSpace = WS_COLLAPSE;
//setting fundamental facets
caclFundamentalFacets();
}
public short getXSType () {
return XSTypeDecl.SIMPLE_TYPE;
}
public String getTypeName() {
return fTypeName;
}
public String getTargetNamespace() {
return fTargetNamespace;
}
public short getFinalSet(){
return fFinalSet;
}
public XSTypeDecl getBaseType(){
return fBase;
}
public boolean isAnonymous() {
return fTypeName == null;
}
public short getVariety(){
return fVariety;
}
public short getDefinedFacets() {
return fFacetsDefined;
}
public boolean isIDType(){
return (fValidationDV == DV_ID);
}
public boolean isNOTATIONType(){
return (fValidationDV == DV_NOTATION);
}
// REVISIT
public XSSimpleType getPrimitiveType() {
if (fVariety == VARIETY_ATOMIC)
return null;
else
return null;
}
public XSSimpleType getItemType() {
if (fVariety == VARIETY_LIST)
return fItemType;
else
return null;
}
public XSSimpleType[] getMemberTypes() {
if (fVariety == VARIETY_UNION)
return fMemberTypes;
else
return null;
}
/**
* If <restriction> is chosen
*/
public void applyFacets(XSFacets facets, short presentFacet, short fixedFacet, ValidationContext context)
throws InvalidDatatypeFacetException {
applyFacets(facets, presentFacet, fixedFacet, (short)0, context);
}
/**
* built-in derived types by restriction
*/
void applyFacets1(XSFacets facets, short presentFacet, short fixedFacet) {
try {
applyFacets(facets, presentFacet, fixedFacet, (short)0, null);
} catch (InvalidDatatypeFacetException e) {
// should never gets here, internel error
throw new RuntimeException("internal error");
}
}
/**
* built-in derived types by restriction
*/
void applyFacets1(XSFacets facets, short presentFacet, short fixedFacet, short tokenType) {
try {
applyFacets(facets, presentFacet, fixedFacet, tokenType, null);
} catch (InvalidDatatypeFacetException e) {
// should never gets here, internel error
throw new RuntimeException("internal error");
}
}
/**
* If <restriction> is chosen, or built-in derived types by restriction
*/
void applyFacets(XSFacets facets, short presentFacet, short fixedFacet, short tokenType, ValidationContext context)
throws InvalidDatatypeFacetException {
// clear facets. because we always inherit facets in the constructor
// REVISIT: in fact, we don't need to clear them.
// we can convert 5 string values (4 bounds + 1 enum) to actual values,
// store them somewhere, then do facet checking at once, instead of
// going through the following steps. (lots of checking are redundant:
// for example, ((presentFacet & FACET_XXX) != 0))
fFacetsDefined = 0;
fFixedFacet = 0;
int result = 0 ;
// step 1: parse present facets
short allowedFacet = fDVs[fValidationDV].getAllowedFacets();
// length
if ((presentFacet & FACET_LENGTH) != 0) {
if ((allowedFacet & FACET_LENGTH) == 0) {
reportError("non-supported facet");
} else {
fLength = facets.length;
fFacetsDefined |= FACET_LENGTH;
if ((fixedFacet & FACET_LENGTH) != 0)
fFixedFacet |= FACET_LENGTH;
// check 4.3.1.c0 must: length >= 0
if (fLength < 0)
reportError("length value '"+facets.length+"' must be a nonNegativeInteger");
}
}
// minLength
if ((presentFacet & FACET_MINLENGTH) != 0) {
if ((allowedFacet & FACET_MINLENGTH) == 0) {
reportError("non-supported facet");
} else {
fMinLength = facets.minLength;
fFacetsDefined |= FACET_MINLENGTH;
if ((fixedFacet & FACET_MINLENGTH) != 0)
fFixedFacet |= FACET_MINLENGTH;
// check 4.3.2.c0 must: minLength >= 0
if (fMinLength < 0)
reportError("minLength value '"+facets.minLength+"' must be a nonNegativeInteger");
}
}
// maxLength
if ((presentFacet & FACET_MAXLENGTH) != 0) {
if ((allowedFacet & FACET_MAXLENGTH) == 0) {
reportError("non-supported facet");
} else {
fMaxLength = facets.maxLength;
fFacetsDefined |= FACET_MAXLENGTH;
if ((fixedFacet & FACET_MAXLENGTH) != 0)
fFixedFacet |= FACET_MAXLENGTH;
// check 4.3.3.c0 must: maxLength >= 0
if (fMaxLength < 0)
reportError("maxLength value '"+facets.maxLength+"' must be a nonNegativeInteger");
}
}
// pattern
if ((presentFacet & FACET_PATTERN) != 0) {
if ((allowedFacet & FACET_PATTERN) == 0) {
reportError("non-supported facet");
} else {
RegularExpression regex = null;
try {
regex = new RegularExpression(facets.pattern, "X");
} catch (Exception e) {
reportError("pattern value '"+facets.pattern+"' is not valid: " + e.getLocalizedMessage());
}
if (regex != null) {
fPattern = new Vector();
fPattern.addElement(regex);
fFacetsDefined |= FACET_PATTERN;
if ((fixedFacet & FACET_PATTERN) != 0)
fFixedFacet |= FACET_PATTERN;
}
}
}
// enumeration
if ((presentFacet & FACET_ENUMERATION) != 0) {
if ((allowedFacet & FACET_ENUMERATION) == 0) {
reportError("non-supported facet");
} else {
fEnumeration = new Vector();
Vector enumVals = facets.enumeration;
for (int i = 0; i < enumVals.size(); i++) {
try {
// check 4.3.5.c0 must: enumeration values from the value space of base
fEnumeration.addElement(this.fBase.validate((String)enumVals.elementAt(i), context, fTempInfo));
} catch (InvalidDatatypeValueException ide) {
reportError("Value of enumeration '" + enumVals.elementAt(i) + "' must be from the value space of base");
}
}
fFacetsDefined |= FACET_ENUMERATION;
if ((fixedFacet & FACET_ENUMERATION) != 0)
fFixedFacet |= FACET_ENUMERATION;
}
}
// whiteSpace
if ((presentFacet & FACET_WHITESPACE) != 0) {
if ((allowedFacet & FACET_WHITESPACE) == 0) {
reportError("non-supported facet");
} else {
fWhiteSpace = facets.whiteSpace;
fFacetsDefined |= FACET_WHITESPACE;
if ((fixedFacet & FACET_WHITESPACE) != 0)
fFixedFacet |= FACET_WHITESPACE;
}
}
// maxInclusive
if ((presentFacet & FACET_MAXINCLUSIVE) != 0) {
if ((allowedFacet & FACET_MAXINCLUSIVE) == 0) {
reportError("non-supported facet");
} else {
try {
fMaxInclusive = getActualValue(facets.maxInclusive, context, fTempInfo);
fFacetsDefined |= FACET_MAXINCLUSIVE;
if ((fixedFacet & FACET_MAXINCLUSIVE) != 0)
fFixedFacet |= FACET_MAXINCLUSIVE;
} catch (InvalidDatatypeValueException ide) {
reportError("maxInclusive value '"+facets.maxInclusive+"' is invalid");
}
}
}
// maxExclusive
if ((presentFacet & FACET_MAXEXCLUSIVE) != 0) {
if ((allowedFacet & FACET_MAXEXCLUSIVE) == 0) {
reportError("non-supported facet");
} else {
try {
fMaxExclusive = getActualValue(facets.maxExclusive, context, fTempInfo);
fFacetsDefined |= FACET_MAXEXCLUSIVE;
if ((fixedFacet & FACET_MAXEXCLUSIVE) != 0)
fFixedFacet |= FACET_MAXEXCLUSIVE;
} catch (InvalidDatatypeValueException ide) {
reportError("maxExclusive value '"+facets.maxExclusive+"' is invalid");
}
}
}
// minExclusive
if ((presentFacet & FACET_MINEXCLUSIVE) != 0) {
if ((allowedFacet & FACET_MINEXCLUSIVE) == 0) {
reportError("non-supported facet");
} else {
try {
fMinExclusive = getActualValue(facets.minExclusive, context, fTempInfo);
fFacetsDefined |= FACET_MINEXCLUSIVE;
if ((fixedFacet & FACET_MINEXCLUSIVE) != 0)
fFixedFacet |= FACET_MINEXCLUSIVE;
} catch (InvalidDatatypeValueException ide) {
reportError("minExclusive value '"+facets.minExclusive+"' is invalid");
}
}
}
// minInclusive
if ((presentFacet & FACET_MININCLUSIVE) != 0) {
if ((allowedFacet & FACET_MININCLUSIVE) == 0) {
reportError("non-supported facet");
} else {
try {
fMinInclusive = getActualValue(facets.minInclusive, context, fTempInfo);
fFacetsDefined |= FACET_MININCLUSIVE;
if ((fixedFacet & FACET_MININCLUSIVE) != 0)
fFixedFacet |= FACET_MININCLUSIVE;
} catch (InvalidDatatypeValueException ide) {
reportError("minInclusive value '"+facets.minInclusive+"' is invalid");
}
}
}
// totalDigits
if ((presentFacet & FACET_TOTALDIGITS) != 0) {
if ((allowedFacet & FACET_TOTALDIGITS) == 0) {
reportError("non-supported facet");
} else {
fTotalDigits = facets.totalDigits;
fFacetsDefined |= FACET_TOTALDIGITS;
if ((fixedFacet & FACET_TOTALDIGITS) != 0)
fFixedFacet |= FACET_TOTALDIGITS;
// check 4.3.11.c0 must: totalDigits > 0
if (fTotalDigits <= 0)
reportError("totalDigits value '"+facets.totalDigits+"' must be a positiveInteger");
}
}
// fractionDigits
if ((presentFacet & FACET_FRACTIONDIGITS) != 0) {
if ((allowedFacet & FACET_FRACTIONDIGITS) == 0) {
reportError("non-supported facet");
} else {
fFractionDigits = facets.fractionDigits;
fFacetsDefined |= FACET_FRACTIONDIGITS;
if ((fixedFacet & FACET_FRACTIONDIGITS) != 0)
fFixedFacet |= FACET_FRACTIONDIGITS;
// check 4.3.12.c0 must: fractionDigits >= 0
if (fFractionDigits < 0)
reportError("fractionDigits value '"+facets.fractionDigits+"' must be a positiveInteger");
}
}
// token type: internal use, so do less checking
if (tokenType != SPECIAL_TOKEN_NONE) {
fTokenType = tokenType;
}
// step 2: check facets against each other: length, bounds
if(fFacetsDefined != 0) {
// check 4.3.1.c1 error: length & (maxLength | minLength)
if((fFacetsDefined & FACET_LENGTH) != 0 ){
if( (fFacetsDefined & FACET_MINLENGTH) != 0 ){
reportError("it is an error for both length and min length to be present" );
}
else if((fFacetsDefined & FACET_MAXLENGTH) != 0 ){
reportError("it is an error for both length and max length to be present" );
}
}
// check 4.3.2.c1 must: minLength <= maxLength
if(((fFacetsDefined & FACET_MINLENGTH ) != 0 ) && ((fFacetsDefined & FACET_MAXLENGTH) != 0))
{
if(fMinLength > fMaxLength)
reportError("value of minLength = " + fMinLength + "must be less than value of maxLength = "+ fMaxLength);
}
// check 4.3.8.c1 error: maxInclusive + maxExclusive
if (((fFacetsDefined & FACET_MAXEXCLUSIVE) != 0) && ((fFacetsDefined & FACET_MAXINCLUSIVE) != 0)) {
reportError( "It is an error for both maxInclusive and maxExclusive to be specified for the same datatype" );
}
// check 4.3.9.c1 error: minInclusive + minExclusive
if (((fFacetsDefined & FACET_MINEXCLUSIVE) != 0) && ((fFacetsDefined & FACET_MININCLUSIVE) != 0)) {
reportError("It is an error for both minInclusive and minExclusive to be specified for the same datatype" );
}
// check 4.3.7.c1 must: minInclusive <= maxInclusive
if (((fFacetsDefined & FACET_MAXINCLUSIVE) != 0) && ((fFacetsDefined & FACET_MININCLUSIVE) != 0)) {
result = fDVs[fValidationDV].compare(fMinInclusive, fMaxInclusive);
if (result != -1 && result != 0)
reportError("minInclusive value ='" + getStringValue(fMinInclusive) + "'must be <= maxInclusive value ='" +
getStringValue(fMaxInclusive) + "'. " );
}
// check 4.3.8.c2 must: minExclusive <= maxExclusive ??? minExclusive < maxExclusive
if (((fFacetsDefined & FACET_MAXEXCLUSIVE) != 0) && ((fFacetsDefined & FACET_MINEXCLUSIVE) != 0)) {
result = fDVs[fValidationDV].compare(fMinExclusive, fMaxExclusive);
if (result != -1 && result != 0)
reportError( "minExclusive value ='" + getStringValue(fMinExclusive) + "' must be <= maxExclusive value ='" +
getStringValue(fMaxExclusive) + "'. " );
}
// check 4.3.9.c2 must: minExclusive < maxInclusive
if (((fFacetsDefined & FACET_MAXINCLUSIVE) != 0) && ((fFacetsDefined & FACET_MINEXCLUSIVE) != 0)) {
if (fDVs[fValidationDV].compare(fMinExclusive, fMaxInclusive) != -1)
reportError( "minExclusive value ='" + getStringValue(fMinExclusive) + "' must be < maxInclusive value ='" +
getStringValue(fMaxInclusive) + "'. " );
}
// check 4.3.10.c1 must: minInclusive < maxExclusive
if (((fFacetsDefined & FACET_MAXEXCLUSIVE) != 0) && ((fFacetsDefined & FACET_MININCLUSIVE) != 0)) {
if (fDVs[fValidationDV].compare(fMinInclusive, fMaxExclusive) != -1)
reportError( "minInclusive value ='" + getStringValue(fMinInclusive) + "' must be < maxExclusive value ='" +
getStringValue(fMaxExclusive) + "'. " );
}
// check 4.3.12.c1 must: fractionDigits <= totalDigits
if (((fFacetsDefined & FACET_FRACTIONDIGITS) != 0) &&
((fFacetsDefined & FACET_TOTALDIGITS) != 0)) {
if (fFractionDigits > fTotalDigits)
reportError( "fractionDigits value ='" + this.fFractionDigits + "' must be <= totalDigits value ='" +
this.fTotalDigits + "'. " );
}
// step 3: check facets against base
// check 4.3.1.c1 error: length & (fBase.maxLength | fBase.minLength)
if ( ((fFacetsDefined & FACET_LENGTH ) != 0 ) ) {
if ( ((fBase.fFacetsDefined & FACET_MAXLENGTH ) != 0 ) ) {
reportError("It is an error for both length and maxLength to be members of facets" );
}
else if ( ((fBase.fFacetsDefined & FACET_MINLENGTH ) != 0 ) ) {
reportError("It is an error for both length and minLength to be members of facets" );
}
else if ( (fBase.fFacetsDefined & FACET_LENGTH) != 0 ) {
// check 4.3.1.c2 error: length != fBase.length
if ( fLength != fBase.fLength )
reportError( "Value of length = '" + fLength +
"' must be = the value of fBase.length = '" + fBase.fLength + "'");
}
}
// check 4.3.1.c1 error: fBase.length & (maxLength | minLength)
if ( ((fBase.fFacetsDefined & FACET_LENGTH ) != 0 ) ) {
if ( ((fFacetsDefined & FACET_MAXLENGTH ) != 0 ) ) {
reportError("It is an error for both length and maxLength to be members of facets" );
}
else if ( ((fFacetsDefined & FACET_MINLENGTH ) != 0 ) ) {
reportError("It is an error for both length and minLength to be members of facets" );
}
}
// check 4.3.2.c1 must: minLength <= fBase.maxLength
if ( ((fFacetsDefined & FACET_MINLENGTH ) != 0 ) ) {
if ( (fBase.fFacetsDefined & FACET_MAXLENGTH ) != 0 ) {
if ( fMinLength > fBase.fMaxLength ) {
reportError( "Value of minLength = '" + fMinLength +
"' must be <= the value of maxLength = '" + fMaxLength + "'");
}
}
else if ( (fBase.fFacetsDefined & FACET_MINLENGTH) != 0 ) {
if ( (fBase.fFixedFacet & FACET_MINLENGTH) != 0 && fMinLength != fBase.fMinLength ) {
reportError( "minLength value = '" + fMinLength +
"' must be equal to fBase.minLength value = '" +
fBase.fMinLength + "' with attribute {fixed} = true" );
}
// check 4.3.2.c2 error: minLength < fBase.minLength
if ( fMinLength < fBase.fMinLength ) {
reportError( "Value of minLength = '" + fMinLength +
"' must be >= the value of fBase.minLength = '" + fBase.fMinLength + "'");
}
}
}
// check 4.3.2.c1 must: maxLength < fBase.minLength
if ( ((fFacetsDefined & FACET_MAXLENGTH ) != 0 ) && ((fBase.fFacetsDefined & FACET_MINLENGTH ) != 0 ))
{
if ( fMaxLength < fBase.fMinLength) {
reportError( "Value of maxLength = '" + fMaxLength +
"' must be >= the value of fBase.minLength = '" + fBase.fMinLength + "'");
}
}
// check 4.3.3.c1 error: maxLength > fBase.maxLength
if ( (fFacetsDefined & FACET_MAXLENGTH) != 0 ) {
if ( (fBase.fFacetsDefined & FACET_MAXLENGTH) != 0 ){
if(( (fBase.fFixedFacet & FACET_MAXLENGTH) != 0 )&& fMaxLength != fBase.fMaxLength ) {
reportError( "maxLength value = '" + fMaxLength +
"' must be equal to fBase.maxLength value = '" +
fBase.fMaxLength + "' with attribute {fixed} = true" );
}
if ( fMaxLength > fBase.fMaxLength ) {
reportError( "Value of maxLength = '" + fMaxLength +
"' must be <= the value of fBase.maxLength = '" + fBase.fMaxLength + "'");
}
}
}
// check 4.3.7.c2 error:
// maxInclusive > fBase.maxInclusive
// maxInclusive >= fBase.maxExclusive
// maxInclusive < fBase.minInclusive
// maxInclusive <= fBase.minExclusive
if (((fFacetsDefined & FACET_MAXINCLUSIVE) != 0)) {
if (((fBase.fFacetsDefined & FACET_MAXINCLUSIVE) != 0)) {
result = fDVs[fValidationDV].compare(fMaxInclusive, fBase.fMaxInclusive);
if ((fBase.fFixedFacet & FACET_MAXINCLUSIVE) != 0 && result != 0) {
reportError( "maxInclusive value = '" + getStringValue(fMaxInclusive) +
"' must be equal to fBase.maxInclusive value = '" +
getStringValue(fBase.fMaxInclusive) + "' with attribute {fixed} = true" );
}
if (result != -1 && result != 0) {
reportError( "maxInclusive value ='" + getStringValue(fMaxInclusive) + "' must be <= fBase.maxInclusive value ='" +
getStringValue(fBase.fMaxInclusive) + "'" );
}
}
if (((fBase.fFacetsDefined & FACET_MAXEXCLUSIVE) != 0) &&
fDVs[fValidationDV].compare(fMaxInclusive, fBase.fMaxExclusive) != -1){
reportError( "maxInclusive value ='" + getStringValue(fMaxInclusive) + "' must be < fBase.maxExclusive value ='" +
getStringValue(fBase.fMaxExclusive) + "'" );
}
if ((( fBase.fFacetsDefined & FACET_MININCLUSIVE) != 0)) {
result = fDVs[fValidationDV].compare(fMaxInclusive, fBase.fMinInclusive);
if (result != 1 && result != 0) {
reportError( "maxInclusive value ='" + getStringValue(fMaxInclusive) + "' must be >= fBase.minInclusive value ='" +
getStringValue(fBase.fMinInclusive) + "'" );
}
}
if ((( fBase.fFacetsDefined & FACET_MINEXCLUSIVE) != 0) &&
fDVs[fValidationDV].compare(fMaxInclusive, fBase.fMinExclusive ) != 1)
reportError( "maxInclusive value ='" + getStringValue(fMaxInclusive) + "' must be > fBase.minExclusive value ='" +
getStringValue(fBase.fMinExclusive) + "'" );
}
// check 4.3.8.c3 error:
// maxExclusive > fBase.maxExclusive
// maxExclusive > fBase.maxInclusive
// maxExclusive <= fBase.minInclusive
// maxExclusive <= fBase.minExclusive
if (((fFacetsDefined & FACET_MAXEXCLUSIVE) != 0)) {
if ((( fBase.fFacetsDefined & FACET_MAXEXCLUSIVE) != 0)) {
result= fDVs[fValidationDV].compare(fMaxExclusive, fBase.fMaxExclusive);
if ((fBase.fFixedFacet & FACET_MAXEXCLUSIVE) != 0 && result != 0) {
reportError( "maxExclusive value = '" + getStringValue(fMaxExclusive) +
"' must be equal to fBase.maxExclusive value = '" +
getStringValue(fBase.fMaxExclusive) + "' with attribute {fixed} = true" );
}
if (result != -1 && result != 0) {
reportError( "maxExclusive value ='" + getStringValue(fMaxExclusive) + "' must be < fBase.maxExclusive value ='" +
getStringValue(fBase.fMaxExclusive) + "'" );
}
}
if ((( fBase.fFacetsDefined & FACET_MAXINCLUSIVE) != 0)) {
result= fDVs[fValidationDV].compare(fMaxExclusive, fBase.fMaxInclusive);
if (result != -1 && result != 0) {
reportError( "maxExclusive value ='" + getStringValue(fMaxExclusive) + "' must be <= fBase.maxInclusive value ='" +
getStringValue(fBase.fMaxInclusive) + "'" );
}
}
if ((( fBase.fFacetsDefined & FACET_MINEXCLUSIVE) != 0) &&
fDVs[fValidationDV].compare(fMaxExclusive, fBase.fMinExclusive ) != 1)
reportError( "maxExclusive value ='" + getStringValue(fMaxExclusive) + "' must be > fBase.minExclusive value ='" +
getStringValue(fBase.fMinExclusive) + "'" );
if ((( fBase.fFacetsDefined & FACET_MININCLUSIVE) != 0) &&
fDVs[fValidationDV].compare(fMaxExclusive, fBase.fMinInclusive) != 1)
reportError( "maxExclusive value ='" + getStringValue(fMaxExclusive) + "' must be > fBase.minInclusive value ='" +
getStringValue(fBase.fMinInclusive) + "'" );
}
// check 4.3.9.c3 error:
// minExclusive < fBase.minExclusive
// maxInclusive > fBase.maxInclusive
// minInclusive < fBase.minInclusive
// maxExclusive >= fBase.maxExclusive
if (((fFacetsDefined & FACET_MINEXCLUSIVE) != 0)) {
if ((( fBase.fFacetsDefined & FACET_MINEXCLUSIVE) != 0)) {
result= fDVs[fValidationDV].compare(fMinExclusive, fBase.fMinExclusive);
if ((fBase.fFixedFacet & FACET_MINEXCLUSIVE) != 0 &&
result != 0) {
reportError( "minExclusive value = '" + getStringValue(fMinExclusive) +
"' must be equal to fBase.minExclusive value = '" +
getStringValue(fBase.fMinExclusive) + "' with attribute {fixed} = true" );
}
if (result != 1 && result != 0) {
reportError( "minExclusive value ='" + getStringValue(fMinExclusive) + "' must be >= fBase.minExclusive value ='" +
getStringValue(fBase.fMinExclusive) + "'" );
}
}
if ((( fBase.fFacetsDefined & FACET_MAXINCLUSIVE) != 0)) {
result=fDVs[fValidationDV].compare(fMinExclusive, fBase.fMaxInclusive);
if (result != -1 && result != 0) {
reportError( "minExclusive value ='" + getStringValue(fMinExclusive) + "' must be <= fBase.maxInclusive value ='" +
getStringValue(fBase.fMaxInclusive) + "'" );
}
}
if ((( fBase.fFacetsDefined & FACET_MININCLUSIVE) != 0)) {
result = fDVs[fValidationDV].compare(fMinExclusive, fBase.fMinInclusive);
if (result != 1 && result != 0) {
reportError( "minExclusive value ='" + getStringValue(fMinExclusive) + "' must be >= fBase.minInclusive value ='" +
getStringValue(fBase.fMinInclusive) + "'" );
}
}
if ((( fBase.fFacetsDefined & FACET_MAXEXCLUSIVE) != 0) &&
fDVs[fValidationDV].compare(fMinExclusive, fBase.fMaxExclusive) != -1)
reportError( "minExclusive value ='" + getStringValue(fMinExclusive) + "' must be < fBase.maxExclusive value ='" +
getStringValue(fBase.fMaxExclusive) + "'" );
}
// check 4.3.10.c2 error:
// minInclusive < fBase.minInclusive
// minInclusive > fBase.maxInclusive
// minInclusive <= fBase.minExclusive
// minInclusive >= fBase.maxExclusive
if (((fFacetsDefined & FACET_MININCLUSIVE) != 0)) {
if (((fBase.fFacetsDefined & FACET_MININCLUSIVE) != 0)) {
result = fDVs[fValidationDV].compare(fMinInclusive, fBase.fMinInclusive);
if ((fBase.fFixedFacet & FACET_MININCLUSIVE) != 0 && result != 0) {
reportError( "minInclusive value = '" + getStringValue(fMinInclusive) +
"' must be equal to fBase.minInclusive value = '" +
getStringValue(fBase.fMinInclusive) + "' with attribute {fixed} = true" );
}
if (result != 1 && result != 0) {
reportError( "minInclusive value ='" + getStringValue(fMinInclusive) + "' must be >= fBase.minInclusive value ='" +
getStringValue(fBase.fMinInclusive) + "'" );
}
}
if ((( fBase.fFacetsDefined & FACET_MAXINCLUSIVE) != 0)) {
result=fDVs[fValidationDV].compare(fMinInclusive, fBase.fMaxInclusive);
if (result != -1 && result != 0) {
reportError( "minInclusive value ='" + getStringValue(fMinInclusive) + "' must be <= fBase.maxInclusive value ='" +
getStringValue(fBase.fMaxInclusive) + "'" );
}
}
if ((( fBase.fFacetsDefined & FACET_MINEXCLUSIVE) != 0) &&
fDVs[fValidationDV].compare(fMinInclusive, fBase.fMinExclusive ) != 1)
reportError( "minInclusive value ='" + getStringValue(fMinInclusive) + "' must be > fBase.minExclusive value ='" +
getStringValue(fBase.fMinExclusive) + "'" );
if ((( fBase.fFacetsDefined & FACET_MAXEXCLUSIVE) != 0) &&
fDVs[fValidationDV].compare(fMinInclusive, fBase.fMaxExclusive) != -1)
reportError( "minInclusive value ='" + getStringValue(fMinInclusive) + "' must be < fBase.maxExclusive value ='" +
getStringValue(fBase.fMaxExclusive) + "'" );
}
// check 4.3.11.c1 error: totalDigits > fBase.totalDigits
if (((fFacetsDefined & FACET_TOTALDIGITS) != 0)) {
if ((( fBase.fFacetsDefined & FACET_TOTALDIGITS) != 0)) {
if (fTotalDigits > fBase.fTotalDigits) {
reportError("totalDigits value = '" + fTotalDigits +
"' must be equal to fBase.totalDigits value = '" +
fBase.fTotalDigits +
"' with attribute {fixed} = true" );
}
if (fTotalDigits > fBase.fTotalDigits) {
reportError( "totalDigits value ='" + fTotalDigits + "' must be <= fBase.totalDigits value ='" +
fBase.fTotalDigits + "'" );
}
}
}
// check fixed value for fractionDigits
if (((fFacetsDefined & FACET_FRACTIONDIGITS) != 0)) {
if ((( fBase.fFacetsDefined & FACET_FRACTIONDIGITS) != 0)) {
if ((fBase.fFixedFacet & FACET_FRACTIONDIGITS) != 0 && fFractionDigits != fBase.fFractionDigits) {
reportError("fractionDigits value = '" + fFractionDigits +
"' must be equal to fBase.fractionDigits value = '" +
fBase.fFractionDigits +
"' with attribute {fixed} = true" );
}
}
}
// check 4.3.6.c1 error:
// (whiteSpace = preserve || whiteSpace = replace) && fBase.whiteSpace = collapese or
// whiteSpace = preserve && fBase.whiteSpace = replace
if ( (fFacetsDefined & FACET_WHITESPACE) != 0 && (fBase.fFacetsDefined & FACET_WHITESPACE) != 0 ){
if ( (fBase.fFixedFacet & FACET_WHITESPACE) != 0 && fWhiteSpace != fBase.fWhiteSpace ) {
reportError( "whiteSpace value = '" + whiteSpaceValue(fWhiteSpace) +
"' must be equal to fBase.whiteSpace value = '" +
whiteSpaceValue(fBase.fWhiteSpace) + "' with attribute {fixed} = true" );
}
if ( (fWhiteSpace == WS_PRESERVE || fWhiteSpace == WS_REPLACE) && fBase.fWhiteSpace == WS_COLLAPSE ){
reportError( "It is an error if whiteSpace = 'preserve' or 'replace' and fBase.whiteSpace = 'collapse'");
}
if ( fWhiteSpace == WS_PRESERVE && fBase.fWhiteSpace == WS_REPLACE ){
reportError( "It is an error if whiteSpace = 'preserve' and fBase.whiteSpace = 'replace'");
}
}
}//fFacetsDefined != null
// step 4: inherit other facets from base (including fTokeyType)
// inherit length
if ( (fFacetsDefined & FACET_LENGTH) == 0 && (fBase.fFacetsDefined & FACET_LENGTH) != 0 ) {
fFacetsDefined |= FACET_LENGTH;
fLength = fBase.fLength;
}
// inherit minLength
if ( (fFacetsDefined & FACET_MINLENGTH) == 0 && (fBase.fFacetsDefined & FACET_MINLENGTH) != 0 ) {
fFacetsDefined |= FACET_MINLENGTH;
fMinLength = fBase.fMinLength;
}
// inherit maxLength
if ((fFacetsDefined & FACET_MAXLENGTH) == 0 && (fBase.fFacetsDefined & FACET_MAXLENGTH) != 0 ) {
fFacetsDefined |= FACET_MAXLENGTH;
fMaxLength = fBase.fMaxLength;
}
// inherit pattern //???
if ( (fBase.fFacetsDefined & FACET_PATTERN) != 0 ) {
if ((fFacetsDefined & FACET_PATTERN) == 0) {
fPattern = new Vector();
fFacetsDefined |= FACET_PATTERN;
}
for (int i = fBase.fPattern.size()-1; i >= 0; i--)
fPattern.addElement(fBase.fPattern.elementAt(i));
}
// inherit whiteSpace
if ( (fFacetsDefined & FACET_WHITESPACE) == 0 && (fBase.fFacetsDefined & FACET_WHITESPACE) != 0 ) {
fFacetsDefined |= FACET_WHITESPACE;
fWhiteSpace = fBase.fWhiteSpace;
}
// inherit enumeration
if ((fFacetsDefined & FACET_ENUMERATION) == 0 && (fBase.fFacetsDefined & FACET_ENUMERATION) != 0) {
fFacetsDefined |= FACET_ENUMERATION;
fEnumeration = fBase.fEnumeration;
}
// inherit maxExclusive
if ((( fBase.fFacetsDefined & FACET_MAXEXCLUSIVE) != 0) &&
!((fFacetsDefined & FACET_MAXEXCLUSIVE) != 0) && !((fFacetsDefined & FACET_MAXINCLUSIVE) != 0)) {
fFacetsDefined |= FACET_MAXEXCLUSIVE;
fMaxExclusive = fBase.fMaxExclusive;
}
// inherit maxInclusive
if ((( fBase.fFacetsDefined & FACET_MAXINCLUSIVE) != 0) &&
!((fFacetsDefined & FACET_MAXEXCLUSIVE) != 0) && !((fFacetsDefined & FACET_MAXINCLUSIVE) != 0)) {
fFacetsDefined |= FACET_MAXINCLUSIVE;
fMaxInclusive = fBase.fMaxInclusive;
}
// inherit minExclusive
if ((( fBase.fFacetsDefined & FACET_MINEXCLUSIVE) != 0) &&
!((fFacetsDefined & FACET_MINEXCLUSIVE) != 0) && !((fFacetsDefined & FACET_MININCLUSIVE) != 0)) {
fFacetsDefined |= FACET_MINEXCLUSIVE;
fMinExclusive = fBase.fMinExclusive;
}
// inherit minExclusive
if ((( fBase.fFacetsDefined & FACET_MININCLUSIVE) != 0) &&
!((fFacetsDefined & FACET_MINEXCLUSIVE) != 0) && !((fFacetsDefined & FACET_MININCLUSIVE) != 0)) {
fFacetsDefined |= FACET_MININCLUSIVE;
fMinInclusive = fBase.fMinInclusive;
}
// inherit totalDigits
if ((( fBase.fFacetsDefined & FACET_TOTALDIGITS) != 0) &&
!((fFacetsDefined & FACET_TOTALDIGITS) != 0)) {
fFacetsDefined |= FACET_TOTALDIGITS;
fTotalDigits = fBase.fTotalDigits;
}
// inherit fractionDigits
if ((( fBase.fFacetsDefined & FACET_FRACTIONDIGITS) != 0)
&& !((fFacetsDefined & FACET_FRACTIONDIGITS) != 0)) {
fFacetsDefined |= FACET_FRACTIONDIGITS;
fFractionDigits = fBase.fFractionDigits;
}
//inherit tokeytype
if ((fTokenType == SPECIAL_TOKEN_NONE ) && (fBase.fTokenType != SPECIAL_TOKEN_NONE)) {
fTokenType = fBase.fTokenType ;
}
// step 5: mark fixed values
fFixedFacet |= fBase.fFixedFacet;
//step 6: setting fundamental facets
caclFundamentalFacets();
} //applyFacets()
/**
* validate a value, and return the compiled form
*/
public Object validate(String content, ValidationContext context, ValidatedInfo validatedInfo) throws InvalidDatatypeValueException {
// first normalize string value, and convert it to actual value
Object ob = getActualValue(content, context, fTempInfo);
validate(context, fTempInfo);
if (validatedInfo != null) {
validatedInfo.actualValue = fTempInfo.actualValue;
validatedInfo.normalizedValue = fTempInfo.normalizedValue;
validatedInfo.memberType = fTempInfo.memberType;
validatedInfo.memberTypes = fTempInfo.memberTypes;
}
return ob;
}
/**
* validate an actual value against this DV
*
* @param value the actual value that needs to be validated
* @param context the validation context
* @param validatedInfo used to provide the actual value and member types
*/
public void validate(ValidationContext context, ValidatedInfo validatedInfo)
throws InvalidDatatypeValueException {
// then validate the actual value against the facets
if (context.needFacetChecking() &&
(fFacetsDefined != 0 && fFacetsDefined != FACET_WHITESPACE)) {
checkFacets(validatedInfo);
}
// now check extra rules: for ID/IDREF/ENTITY
if (context.needExtraChecking()) {
checkExtraRules(context, validatedInfo);
}
}
private void checkFacets(ValidatedInfo validatedInfo) throws InvalidDatatypeValueException {
Object ob = validatedInfo.actualValue;
String content = validatedInfo.normalizedValue;
int length = fDVs[fValidationDV].getDataLength(ob);
// maxLength
if ( (fFacetsDefined & FACET_MAXLENGTH) != 0 ) {
if ( length > fMaxLength ) {
throw new InvalidDatatypeValueException("Value '"+content+
"' with length '"+length+
"' exceeds maximum length facet of '"+fMaxLength+"'");
}
}
//minLength
if ( (fFacetsDefined & FACET_MINLENGTH) != 0 ) {
if ( length < fMinLength ) {
throw new InvalidDatatypeValueException("Value '"+content+
"' with length '"+length+
"' is less than minimum length facet of '"+fMinLength+"'" );
}
}
//length
if ( (fFacetsDefined & FACET_LENGTH) != 0 ) {
if ( length != fLength ) {
throw new InvalidDatatypeValueException("Value '"+content+
"' with length '"+length+
"' is not equal to length facet '"+fLength+"'");
}
}
//enumeration
if ( ((fFacetsDefined & FACET_ENUMERATION) != 0 ) ) {
boolean present = false;
for (int i = 0; i < fEnumeration.size(); i++) {
if (isEqual(ob, fEnumeration.elementAt(i))) {
present = true;
break;
}
}
if(!present){
throw new InvalidDatatypeValueException(DatatypeMessageProvider.fgMessageKeys[DatatypeMessageProvider.NOT_ENUM_VALUE],
new Object [] {content});
}
}
//fractionDigits
if ((fFacetsDefined & FACET_FRACTIONDIGITS) != 0) {
int scale = fDVs[fValidationDV].getFractionDigits(ob);
if (scale > fFractionDigits) {
throw new InvalidDatatypeValueException(DatatypeMessageProvider.fgMessageKeys[DatatypeMessageProvider.FRACTION_EXCEEDED],
new Object[] {
"'" + content + "'" + " with fractionDigits = '"+ scale +"'",
"'" + fFractionDigits + "'"
});
}
}
//totalDigits
if ((fFacetsDefined & FACET_TOTALDIGITS)!=0) {
int totalDigits = fDVs[fValidationDV].getTotalDigits(ob);
if (totalDigits > fTotalDigits) {
throw new InvalidDatatypeValueException(DatatypeMessageProvider.fgMessageKeys[DatatypeMessageProvider.TOTALDIGITS_EXCEEDED],
new Object[] {
"'" + content + "'" + " with totalDigits = '"+ totalDigits +"'",
"'" + fTotalDigits + "'"
});
}
}
// REVISIT this part for error reporting
boolean minOk = true;
boolean maxOk = true;
String upperBound="";
String lowerBound="";
String lowerBoundIndicator = "";
String upperBoundIndicator = "";
int compare;
//maxinclusive
if ( (fFacetsDefined & FACET_MAXINCLUSIVE) != 0 ) {
compare = fDVs[fValidationDV].compare(ob, fMaxInclusive);
maxOk = (compare == -1 || compare == 0);
upperBound = fMaxInclusive.toString();
if ( upperBound != null ) {
upperBoundIndicator = "<=";
}
else {
upperBound="";
}
}
//maxExclusive
if ( (fFacetsDefined & FACET_MAXEXCLUSIVE) != 0 ) {
compare = fDVs[fValidationDV].compare(ob, fMaxExclusive );
maxOk = (compare == -1);
upperBound = fMaxExclusive.toString();
if ( upperBound != null ) {
upperBoundIndicator = "<";
}
else {
upperBound = "";
}
}
//minInclusive
if ( (fFacetsDefined & FACET_MININCLUSIVE) != 0 ) {
compare = fDVs[fValidationDV].compare(ob, fMinInclusive);
minOk = (compare == 1 || compare == 0);
lowerBound = fMinInclusive.toString();
if ( lowerBound != null ) {
lowerBoundIndicator = "<=";
}
else {
lowerBound = "";
}
}
//minExclusive
if ( (fFacetsDefined & FACET_MINEXCLUSIVE) != 0 ) {
compare = fDVs[fValidationDV].compare(ob, fMinExclusive);
minOk = (compare == 1);
lowerBound = fMinExclusive.toString();
if ( lowerBound != null ) {
lowerBoundIndicator = "<";
}
else {
lowerBound = "";
}
}
if ( !(minOk && maxOk) ){
throw new InvalidDatatypeValueException(DatatypeMessageProvider.fgMessageKeys[DatatypeMessageProvider.OUT_OF_BOUNDS],
new Object [] { ob.toString(), lowerBound, upperBound, lowerBoundIndicator, upperBoundIndicator});
}
}
private void checkExtraRules(ValidationContext context, ValidatedInfo validatedInfo) throws InvalidDatatypeValueException {
Object ob = validatedInfo.actualValue;
if (fVariety == VARIETY_ATOMIC) {
fDVs[fValidationDV].checkExtraRules(ob, context);
} else if (fVariety == VARIETY_LIST) {
Object[] values = (Object[])ob;
if (fItemType.fVariety == VARIETY_UNION) {
XSSimpleTypeDecl[] memberTypes = (XSSimpleTypeDecl[])validatedInfo.memberTypes;
XSSimpleType memberType = validatedInfo.memberType;
for (int i = values.length-1; i >= 0; i--) {
validatedInfo.actualValue = values[i];
validatedInfo.memberType = memberTypes[i];
fItemType.checkExtraRules(context, validatedInfo);
}
validatedInfo.memberType = memberType;
} else { // (fVariety == VARIETY_ATOMIC)
for (int i = values.length-1; i >= 0; i--) {
validatedInfo.actualValue = values[i];
fItemType.checkExtraRules(context, validatedInfo);
}
}
validatedInfo.actualValue = values;
} else { // (fVariety == VARIETY_UNION)
((XSSimpleTypeDecl)validatedInfo.memberType).checkExtraRules(context, validatedInfo);
}
}// checkExtraRules()
//we can still return object for internal use.
private Object getActualValue(String content, ValidationContext context, ValidatedInfo validatedInfo) throws InvalidDatatypeValueException{
if (fVariety == VARIETY_ATOMIC) {
String nvalue = normalize(content, fWhiteSpace);
// validate special kinds of token, in place of old pattern matching
if (fTokenType != SPECIAL_TOKEN_NONE) {
boolean seenErr = false;
if (fTokenType == SPECIAL_TOKEN_NMTOKEN) {
// PATTERN "\\c+"
seenErr = !XMLChar.isValidNmtoken(nvalue);
}
else if (fTokenType == SPECIAL_TOKEN_NAME) {
// PATTERN "\\i\\c*"
seenErr = !XMLChar.isValidName(nvalue);
}
else if (fTokenType == SPECIAL_TOKEN_NCNAME) {
// PATTERN "[\\i-[:]][\\c-[:]]*"
// REVISIT: !!!NOT IMPLEMENTED in XMLChar
seenErr = !XMLChar.isValidNCName(nvalue);
}
if (seenErr) {
throw new InvalidDatatypeValueException("Value '"+nvalue+"' is not a valid " +
SPECIAL_TOKEN_STRING[fTokenType]);
}
}
if ( (fFacetsDefined & FACET_PATTERN ) != 0 ) {
RegularExpression regex;
for (int idx = fPattern.size()-1; idx >= 0; idx--) {
regex = (RegularExpression)fPattern.elementAt(idx);
if (!regex.matches(nvalue)){
throw new InvalidDatatypeValueException("Value '"+content+
"' does not match regular expression facet '" + regex + "'" );
}
}
}
Object avalue = fDVs[fValidationDV].getActualValue(nvalue, context);
validatedInfo.actualValue = avalue;
validatedInfo.normalizedValue = nvalue;
return avalue;
} else if (fVariety == VARIETY_LIST) {
String nvalue = normalize(content, fWhiteSpace);
StringTokenizer parsedList = new StringTokenizer(nvalue);
int countOfTokens = parsedList.countTokens() ;
Object[] avalue = new Object[countOfTokens];
XSSimpleTypeDecl[] memberTypes = new XSSimpleTypeDecl[countOfTokens];
for(int i = 0 ; i < countOfTokens ; i ++){
// we can't call fItemType.validate(), otherwise checkExtraRules()
// will be called twice: once in fItemType.validate, once in
// validate method of this type.
// so we take two steps to get the actual value:
// 1. fItemType.getActualValue()
// 2. fItemType.chekcFacets()
avalue[i] = fItemType.getActualValue(parsedList.nextToken(), context, validatedInfo);
if (context.needFacetChecking() &&
(fItemType.fFacetsDefined != 0 && fItemType.fFacetsDefined != FACET_WHITESPACE)) {
fItemType.checkFacets(validatedInfo);
}
memberTypes[i] = (XSSimpleTypeDecl)validatedInfo.memberType;
}
validatedInfo.actualValue = avalue;
validatedInfo.normalizedValue = nvalue;
validatedInfo.memberTypes = memberTypes;
return avalue;
} else { // (fVariety == VARIETY_UNION)
for(int i = 0 ; i < fMemberTypes.length; i++) {
try {
// we can't call fMemberType[i].validate(), otherwise checkExtraRules()
// will be called twice: once in fMemberType[i].validate, once in
// validate method of this type.
// so we take two steps to get the actual value:
// 1. fMemberType[i].getActualValue()
// 2. fMemberType[i].chekcFacets()
Object aValue = fMemberTypes[i].getActualValue(content, context, validatedInfo);
if (context.needFacetChecking() &&
(fMemberTypes[i].fFacetsDefined != 0 && fMemberTypes[i].fFacetsDefined != FACET_WHITESPACE)) {
fMemberTypes[i].checkFacets(validatedInfo);
}
validatedInfo.memberType = fMemberTypes[i];
return aValue;
} catch(InvalidDatatypeValueException invalidValue) {
}
}
String msg = " content = " + content + " doesnt't match any of the member types " ;
throw new InvalidDatatypeValueException(msg);
}
}//getActualValue()
public boolean isEqual(Object value1, Object value2) {
if (fVariety == VARIETY_ATOMIC)
return fDVs[fValidationDV].isEqual(value1,value2);
else if (fVariety == VARIETY_LIST) {
if (!(value1 instanceof Object[]) || !(value2 instanceof Object[]))
return false;
Object[] v1 = (Object[])value1;
Object[] v2 = (Object[])value2;
int count = v1.length;
if (count != v2.length)
return false;
for (int i = 0 ; i < count ; i++) {
if (!fItemType.isEqual(v1[i], v2[i]))
return false;
}//end of loop
//everything went fine.
return true;
} else if (fVariety == VARIETY_UNION) {
for (int i = fMemberTypes.length-1; i >= 0; i--) {
if (fMemberTypes[i].isEqual(value1,value2)){
return true;
}
}
return false;
}
return false;
}//isEqual()
// normalize the string according to the whiteSpace facet
public static String normalize(String content, short ws) {
int len = content == null ? 0 : content.length();
if (len == 0 || ws == WS_PRESERVE)
return content;
StringBuffer sb = new StringBuffer();
if (ws == WS_REPLACE) {
char ch;
// when it's replace, just replace #x9, #xa, #xd by #x20
for (int i = 0; i < len; i++) {
ch = content.charAt(i);
if (ch != 0x9 && ch != 0xa && ch != 0xd)
sb.append(ch);
else
sb.append((char)0x20);
}
} else {
char ch;
int i;
boolean isLeading = true;
// when it's collapse
for (i = 0; i < len; i++) {
ch = content.charAt(i);
// append real characters, so we passed leading ws
if (ch != 0x9 && ch != 0xa && ch != 0xd && ch != 0x20) {
sb.append(ch);
isLeading = false;
}
else {
// for whitespaces, we skip all following ws
for (; i < len-1; i++) {
ch = content.charAt(i+1);
if (ch != 0x9 && ch != 0xa && ch != 0xd && ch != 0x20)
break;
}
// if it's not a leading or tailing ws, then append a space
if (i < len - 1 && !isLeading)
sb.append((char)0x20);
}
}
}
return sb.toString();
}
void reportError(String msg) throws InvalidDatatypeFacetException {
throw new InvalidDatatypeFacetException(msg);
}
private String whiteSpaceValue(short ws){
return WS_FACET_STRING[ws];
}
public String getStringValue(Object value){
if(value != null) {
if (fDVs[fValidationDV] instanceof AbstractDateTimeDV)
return ((AbstractDateTimeDV)fDVs[fValidationDV]).dateToString((int[])value);
else
return value.toString();
} else {
return null;
}
}
public short getOrderedFacet() {
return fOrdered;
}
public boolean isBounded(){
return fBounded;
}
public short getCardinalityFacet(){
return fCardinality;
}
public boolean isNumeric(){
return fNumeric;
}
private void caclFundamentalFacets() {
setOrdered();
setNumeric();
setBounded();
setCardinality();
}
private void setOrdered(){
// When {variety} is atomic, {value} is inherited from {value} of {base type definition}. For all ·primitive· types {value} is as specified in the table in Fundamental Facets (C.1).
if(fVariety == VARIETY_ATOMIC){
this.fOrdered = fBase.fOrdered;
}
// When {variety} is list, {value} is false.
else if(fVariety == VARIETY_LIST){
this.fOrdered = ORDERED_FALSE;
}
// When {variety} is union, the {value} is partial unless one of the following:
// 1. If every member of {member type definitions} is derived from a common ancestor other than the simple ur-type, then {value} is the same as that ancestor's ordered facet.
// 2. If every member of {member type definitions} has a {value} of false for the ordered facet, then {value} is false.
else if(fVariety == VARIETY_UNION){
int length = fMemberTypes.length;
// REVISIT: is the length possible to be 0?
if (length == 0) {
this.fOrdered = ORDERED_PARTIAL;
return;
}
// we need to process the first member type before entering the loop
short ancestorId = getPrimitiveDV(fMemberTypes[0].fValidationDV);
boolean commonAnc = ancestorId != DV_ANYSIMPLETYPE;
boolean allFalse = fMemberTypes[0].fOrdered == ORDERED_FALSE;
// for the other member types, check whether the value is false
// and whether they have the same ancestor as the first one
for (int i = 1; i < fMemberTypes.length && (commonAnc || allFalse); i++) {
if (commonAnc)
commonAnc = ancestorId == getPrimitiveDV(fMemberTypes[i].fValidationDV);
if (allFalse)
allFalse = fMemberTypes[i].fOrdered == ORDERED_FALSE;
}
if (commonAnc) {
// REVISIT: all member types should have the same ordered value
// just use the first one. Can we assume this?
this.fOrdered = fMemberTypes[0].fOrdered;
} else if (allFalse) {
this.fOrdered = ORDERED_FALSE;
} else {
this.fOrdered = ORDERED_PARTIAL;
}
}
}//setOrdered
private void setNumeric(){
if(fVariety == VARIETY_ATOMIC){
this.fNumeric = fBase.fNumeric;
}
else if(fVariety == VARIETY_LIST){
this.fNumeric = false;
}
else if(fVariety == VARIETY_UNION){
XSSimpleType [] memberTypes = this.getMemberTypes();
for(int i = 0 ; i < memberTypes.length ; i++){
if( ! memberTypes[i].isNumeric() ){
this.fNumeric = false;
return;
}
}
this.fNumeric = true;
}
}//setNumeric
private void setBounded(){
if(fVariety == VARIETY_ATOMIC){
if( (((this.fFacetsDefined & FACET_MININCLUSIVE) != 0) || ((this.fFacetsDefined & FACET_MINEXCLUSIVE) != 0))
&& (((this.fFacetsDefined & FACET_MAXINCLUSIVE) != 0) || ((this.fFacetsDefined & FACET_MAXEXCLUSIVE) != 0)) ){
this.fBounded = true;
}
else{
this.fBounded = false;
}
}
else if(fVariety == VARIETY_LIST){
if( ((this.fFacetsDefined & FACET_LENGTH) != 0 ) || ( ((this.fFacetsDefined & FACET_MINLENGTH) != 0 )
&& ((this.fFacetsDefined & FACET_MAXLENGTH) != 0 )) ){
this.fBounded = true;
}
else{
this.fBounded = false;
}
}
else if(fVariety == VARIETY_UNION){
XSSimpleTypeDecl [] memberTypes = this.fMemberTypes;
short ancestorId = 0 ;
if(memberTypes.length > 0){
ancestorId = getPrimitiveDV(memberTypes[0].fValidationDV);
}
for(int i = 0 ; i < memberTypes.length ; i++){
if( ! memberTypes[i].isBounded() || (ancestorId != getPrimitiveDV(memberTypes[i].fValidationDV)) ){
this.fBounded = false;
return;
}
}
this.fBounded = true;
}
}//setBounded
private boolean specialCardinalityCheck(){
if( (fBase.fValidationDV == XSSimpleTypeDecl.DV_DATE) || (fBase.fValidationDV == XSSimpleTypeDecl.DV_GYEARMONTH)
|| (fBase.fValidationDV == XSSimpleTypeDecl.DV_GYEAR) || (fBase.fValidationDV == XSSimpleTypeDecl.DV_GMONTHDAY)
|| (fBase.fValidationDV == XSSimpleTypeDecl.DV_GDAY) || (fBase.fValidationDV == XSSimpleTypeDecl.DV_GMONTH) ){
return true;
}
return false;
} //specialCardinalityCheck()
private void setCardinality(){
if(fVariety == VARIETY_ATOMIC){
if(fBase.fCardinality == CARDINALITY_FINITE){
this.fCardinality = CARDINALITY_FINITE;
}
else {// (fBase.fCardinality == CARDINALITY_COUNTABLY_INFINITE)
if ( ((this.fFacetsDefined & FACET_LENGTH) != 0 ) || ((this.fFacetsDefined & FACET_MAXLENGTH) != 0 )
|| ((this.fFacetsDefined & FACET_TOTALDIGITS) != 0 ) ){
this.fCardinality = CARDINALITY_FINITE;
}
else if( (((this.fFacetsDefined & FACET_MININCLUSIVE) != 0 ) || ((this.fFacetsDefined & FACET_MINEXCLUSIVE) != 0 ))
&& (((this.fFacetsDefined & FACET_MAXINCLUSIVE) != 0 ) || ((this.fFacetsDefined & FACET_MAXEXCLUSIVE) != 0 )) ){
if( ((this.fFacetsDefined & FACET_FRACTIONDIGITS) != 0 ) || specialCardinalityCheck()){
this.fCardinality = CARDINALITY_FINITE;
}
else{
this.fCardinality = CARDINALITY_COUNTABLY_INFINITE;
}
}
else{
this.fCardinality = CARDINALITY_COUNTABLY_INFINITE;
}
}
}
else if(fVariety == VARIETY_LIST){
if( ((this.fFacetsDefined & FACET_LENGTH) != 0 ) || ( ((this.fFacetsDefined & FACET_MINLENGTH) != 0 )
&& ((this.fFacetsDefined & FACET_MAXLENGTH) != 0 )) ){
this.fCardinality = CARDINALITY_FINITE;
}
else{
this.fCardinality = CARDINALITY_COUNTABLY_INFINITE;
}
}
else if(fVariety == VARIETY_UNION){
XSSimpleType [] memberTypes = this.getMemberTypes();
for(int i = 0 ; i < memberTypes.length ; i++){
if( ! (memberTypes[i].getCardinalityFacet() == CARDINALITY_FINITE) ){
this.fCardinality = CARDINALITY_COUNTABLY_INFINITE;
return;
}
}
this.fCardinality = CARDINALITY_FINITE;
}
}//setCardinality
private short getPrimitiveDV(short validationDV){
if (validationDV == DV_ID || validationDV == DV_IDREF || validationDV == DV_ENTITY){
return DV_STRING;
}
else{
return validationDV;
}
}//getPrimitiveDV()
static final XSSimpleTypeDecl fAnySimpleType = new XSSimpleTypeDecl(null, "anySimpleType", DV_ANYSIMPLETYPE, ORDERED_FALSE, false, CARDINALITY_FINITE, false);
} // class XSComplexTypeDecl