001:/*
002: * The Apache Software License, Version 1.1
003: *
004: *
005: * Copyright (c) 1999, 2000 The Apache Software Foundation. All rights
006: * reserved.
007: *
008: * Redistribution and use in source and binary forms, with or without
009: * modification, are permitted provided that the following conditions
010: * are met:
011: *
012: * 1. Redistributions of source code must retain the above copyright
013: * notice, this list of conditions and the following disclaimer.
014: *
015: * 2. Redistributions in binary form must reproduce the above copyright
016: * notice, this list of conditions and the following disclaimer in
017: * the documentation and/or other materials provided with the
018: * distribution.
019: *
020: * 3. The end-user documentation included with the redistribution,
021: * if any, must include the following acknowledgment:
022: * "This product includes software developed by the
023: * Apache Software Foundation (http://www.apache.org/)."
024: * Alternately, this acknowledgment may appear in the software itself,
025: * if and wherever such third-party acknowledgments normally appear.
026: *
027: * 4. The names "Xerces" and "Apache Software Foundation" must
028: * not be used to endorse or promote products derived from this
029: * software without prior written permission. For written
030: * permission, please contact apache@apache.org.
031: *
032: * 5. Products derived from this software may not be called "Apache",
033: * nor may "Apache" appear in their name, without prior written
034: * permission of the Apache Software Foundation.
035: *
036: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
037: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
038: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
039: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
040: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
041: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
042: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
043: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
044: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
045: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
046: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
047: * SUCH DAMAGE.
048: * ====================================================================
049: *
050: * This software consists of voluntary contributions made by many
051: * individuals on behalf of the Apache Software Foundation and was
052: * originally based on software copyright (c) 1999, International
053: * Business Machines, Inc., http://www.apache.org. For more
054: * information on the Apache Software Foundation, please see
055: * <http://www.apache.org/>.
056: */
057:
058:package org.apache.xerces.validators.datatype;
059:
060:import java.util.Hashtable;
061:import java.util.Vector;
062:import java.util.Enumeration;
063:import java.util.StringTokenizer;
064:import java.util.NoSuchElementException;
065:import org.apache.xerces.validators.schema.SchemaSymbols;
066:import org.apache.xerces.utils.regex.RegularExpression;
067:
068:
069:
070:/**
071: * @author Jeffrey Rodriguez
072: * @author Elena Litani
073: * UnionValidator validates that XML content is a W3C string type.
074: * Implements the September 22 XML Schema datatype Union Datatype type
075: */
076:public class UnionDatatypeValidator extends AbstractDatatypeValidator {
077:
078: private Vector fBaseValidators = null; // union collection of validators
079: private int fValidatorsSize = 0;
080: private Vector fEnumeration = null;
081: private StringBuffer errorMsg = null;
082:
083:
084: public UnionDatatypeValidator () throws InvalidDatatypeFacetException{
085: this ( null, null, false ); // Native, No Facets defined, Restriction
086:
087: }
088:
089:
090: public UnionDatatypeValidator ( DatatypeValidator base, Hashtable facets, boolean derivedBy ) throws InvalidDatatypeFacetException {
091: fBaseValidator = base;
092: //facets allowed are: pattern & enumeration
093: if ( facets != null ) {
094: for ( Enumeration e = facets.keys(); e.hasMoreElements(); ) {
095: String key = (String) e.nextElement();
096: if ( key.equals(SchemaSymbols.ELT_ENUMERATION) ) {
097: fFacetsDefined |= DatatypeValidator.FACET_ENUMERATION;
098: fEnumeration = (Vector)facets.get(key);
099: }
100: else if ( key.equals(SchemaSymbols.ELT_PATTERN) ) {
101: fFacetsDefined |= DatatypeValidator.FACET_PATTERN;
102: fPattern = (String)facets.get(key);
103: fRegex = new RegularExpression(fPattern, "X");
104:
105:
106: }
107: else {
108: throw new InvalidDatatypeFacetException( getErrorString(DatatypeMessageProvider.ILLEGAL_UNION_FACET,
109: DatatypeMessageProvider.MSG_NONE, new Object[] { key }));
110: }
111: } //end for
112:
113: // check 4.3.5.c0 must: enumeration values from the value space of base
114: if ( base != null &&
115: (fFacetsDefined & DatatypeValidator.FACET_ENUMERATION) != 0 &&
116: (fEnumeration != null) ) {
117: int i = 0;
118: try {
119: for (; i < fEnumeration.size(); i++) {
120: base.validate ((String)fEnumeration.elementAt(i), null);
121: }
122: } catch ( Exception idve ){
123: throw new InvalidDatatypeFacetException( "Value of enumeration = '" + fEnumeration.elementAt(i) +
124: "' must be from the value space of base.");
125: }
126: }
127: }// End of Facets Setting
128:
129: }
130:
131: public UnionDatatypeValidator ( Vector base) {
132:
133: if ( base !=null ) {
134: fValidatorsSize = base.size();
135: fBaseValidators = new Vector(fValidatorsSize);
136: fBaseValidators = base;
137:
138: }
139:
140: }
141:
142:
143:
144: /**
145: * validate that a string is a W3C string type
146: *
147: * @param content A string containing the content to be validated
148: * @param list
149: * @exception throws InvalidDatatypeException if the content is
150: * not a W3C string type
151: * @exception InvalidDatatypeValueException
152: */
153: public Object validate(String content, Object state) throws InvalidDatatypeValueException
154: {
155: if ( content == null && state != null ) {
156: this .fBaseValidator.validate( content, state );//Passthrough setup information
157: //for state validators
158: }
159: else {
160: checkContentEnum( content, state, false , null );
161: }
162: return(null);
163: }
164:
165:
166: /**
167: *
168: * @return A Hashtable containing the facets
169: * for this datatype.
170: */
171: public Hashtable getFacets(){
172: return(null);
173: }
174:
175: public int compare( String value1, String value2 ){
176: if (fBaseValidator != null) {
177: return this .fBaseValidator.compare(value1, value2);
178: }
179: //union datatype
180: int index=-1;
181: DatatypeValidator currentDV;
182: while ( ++index < fValidatorsSize ) {
183: currentDV = (DatatypeValidator)this .fBaseValidators.elementAt(index);
184: if (currentDV.compare(value1, value2) == 0) {
185: return 0;
186: }
187: }
188: //REVISIT: what does it mean for UNION1 to be <less than> or <greater than> UNION2 ?
189: return -1;
190: }
191:
192: /**
193: * Returns a copy of this object.
194: */
195: public Object clone() throws CloneNotSupportedException {
196: UnionDatatypeValidator newObj = null;
197: try {
198: newObj = new UnionDatatypeValidator();
199: newObj.fLocale = this .fLocale;
200: newObj.fBaseValidator = this .fBaseValidator;
201: newObj.fBaseValidators = (Vector)this .fBaseValidators.clone();
202: newObj.fPattern = this .fPattern;
203: newObj.fEnumeration = this .fEnumeration;
204: newObj.fFacetsDefined = this .fFacetsDefined;
205: }
206: catch ( InvalidDatatypeFacetException ex ) {
207: ex.printStackTrace();
208: }
209: return(newObj);
210:
211: }
212:
213: // returns the fBaseValidators Vector; added so that
214: // 2.2.4 of SchemaStructures spec section 3.14.6 can be implemented.
215: public Vector getBaseValidators() {
216: return fBaseValidators;
217: }
218:
219: /**
220: * check if enum is subset of fEnumeration
221: * enum 1: <enumeration value="1 2"/>
222: * enum 2: <enumeration value="1.0 2"/>
223: *
224: * @param enumeration facet
225: *
226: * @returns true if enumeration is subset of fEnumeration, false otherwise
227: */
228: private boolean verifyEnum (Vector enum){
229: /* REVISIT: won't work for list datatypes in some cases: */
230: if ((fFacetsDefined & DatatypeValidator.FACET_ENUMERATION ) != 0) {
231: for (Enumeration e = enum.elements() ; e.hasMoreElements() ;) {
232: if (fEnumeration.contains(e.nextElement()) == false) {
233: return false;
234: }
235: }
236: }
237: return true;
238: }
239:
240: /**
241: * validate if the content is valid against base datatype and facets (if any)
242: *
243: * @param content A string containing the content to be validated
244: * @param pattern: true if pattern facet was applied, false otherwise
245: * @param enumeration enumeration facet
246: * @exception throws InvalidDatatypeException if the content is not valid
247: */
248: private void checkContentEnum( String content, Object state, boolean pattern, Vector enumeration ) throws InvalidDatatypeValueException
249: {
250: // for UnionDatatype we have to wait till the union baseValidators are known, thus
251: // if the content is valid "against" ListDatatype, but pattern was applied - report an error. To do so we pass @param pattern;
252: // pass @param enumeration so that when base Datatype is known, we would validate enumeration/content
253: // against value space as well
254: int index = -1; //number of validators
255: boolean valid=false;
256: DatatypeValidator currentDV = null;
257: if (fBaseValidator !=null) { //restriction of union datatype
258: if ( (fFacetsDefined & DatatypeValidator.FACET_PATTERN ) != 0 ) {
259: if ( fRegex == null || fRegex.matches( content) == false )
260: throw new InvalidDatatypeValueException("Value '"+content+
261: "' does not match regular expression facet '" + fPattern + "'." );
262: pattern = true;
263: }
264:
265: if (enumeration!=null) {
266: if (!verifyEnum(enumeration)) {
267: throw new InvalidDatatypeValueException("Enumeration '" +enumeration+"' for value '" +content+
268: "' is based on enumeration '"+fEnumeration+"'");
269: }
270: }
271: else {
272: enumeration = (fEnumeration!=null) ? fEnumeration : null;
273: }
274: ((UnionDatatypeValidator)this .fBaseValidator).checkContentEnum( content, state, pattern, enumeration );
275: return;
276: }
277: // native union type
278: while ( ++index < fValidatorsSize) {
279: // check content against each base validator in Union
280: // report an error only in case content is not valid against all base datatypes.
281: currentDV = (DatatypeValidator)this .fBaseValidators.elementAt(index);
282: if ( valid ) break;
283: try {
284: if ( currentDV instanceof ListDatatypeValidator ) {
285: if ( pattern ) {
286: throw new InvalidDatatypeValueException("Facet \"Pattern\" can not be applied to a list datatype" );
287: }
288: ((ListDatatypeValidator)currentDV).checkContentEnum( content, state, enumeration );
289: }
290: else if ( currentDV instanceof UnionDatatypeValidator ) {
291: ((UnionDatatypeValidator)currentDV).checkContentEnum( content, state, pattern, enumeration );
292: }
293: else {
294: if (enumeration!=null) {
295: // check enumeration against value space of double, decimal and float
296: if (currentDV instanceof AbstractNumericValidator) {
297: ((AbstractNumericValidator)currentDV).checkContentEnum(content, state, enumeration);
298: }
299: else {
300: if (enumeration.contains( content ) == false) {
301: throw new InvalidDatatypeValueException("Value '"+content+ "' must be one of "+ enumeration);
302: }
303: ((DatatypeValidator)currentDV).validate( content, state );
304: }
305: }
306: else {
307: ((DatatypeValidator)currentDV).validate( content, state );
308: }
309: }
310: valid=true;
311:
312: }
313: catch ( InvalidDatatypeValueException e ) {
314: }
315: }
316: if ( !valid ) {
317: throw new InvalidDatatypeValueException( "Content '"+content+"' does not match any union types" );
318: }
319: }
320:
321:}
|