001: /*
002: * The Apache Software License, Version 1.1
003: *
004: *
005: * Copyright (c) 1999, 2000, 2001 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.lang.reflect.*;
063: import org.apache.xerces.validators.datatype.*;
064: import org.apache.xerces.validators.schema.SchemaSymbols;
065: import org.apache.xerces.validators.datatype.DatatypeValidatorFactory;
066: import org.apache.xerces.validators.datatype.InvalidDatatypeFacetException;
067:
068: /**
069: *
070: * This class implements a factory of datatype validators. Internally the
071: * DatatypeValidators are kept in three registries:<BR>
072: * (i) DTDRegistry - stores DTD datatype validators
073: * <ii> SchemaRegistry - stores Schema datatype validators
074: * <iii> UserDefinedRegistry - stores Schema user defined datatypes.
075: * <BR>
076: * The above registries will be initialized on demand (for XML document with a DTD, only
077: * DTDRegistry will be initialized).
078: * <BR>
079: * <B>Note: </B>Between multiple parse() calls, only _user_defined_ registry will be reset.
080: * DTD registry and schema registry are initialized only once and are kept for the *life-time* of the parser .
081: * <BR>
082: * This implementation uses a Hahtable as a registry table but future implementation
083: * should use a lighter object, maybe a Map class ( not use a derived Map class
084: * because of JDK 1.1.8 no supporting Map).<BR>
085: * <BR>
086: * As the Parser parses an instance document it knows if validation needs
087: * to be checked. If no validation is necessary we should not instantiate a
088: * DatatypeValidatorFactoryImpl.<BR>
089: * <BR>
090: *
091: * @author Elena Litani
092: * @author Jeffrey Rodriguez
093: * @author Mark Swinkles - List Validation refactoring
094: * @version $Id: DatatypeValidatorFactoryImpl.java,v 1.33 2001/08/01 12:46:57 sandygao Exp $
095: */
096: public class DatatypeValidatorFactoryImpl implements
097: DatatypeValidatorFactory {
098:
099: private static final boolean fDebug = false;
100: private Hashtable fRegistry;
101: private Hashtable fDTDDatatypeRegistry;
102: private Hashtable fSchemaDatatypeRegistry;
103:
104: // 0 -> not expanded, 1-> dtd registry ready, 2 -> schema registry ready
105: private byte fRegistryExpanded = 0;
106:
107: // fSchemaValidation allows to determine between different parse() calls
108: // what registy can be accessable (e.g only DTDRegistry)
109: // 0 -> dtd validation, 1->schema validation
110: private byte fSchemaValidation = 0;
111:
112: public DatatypeValidatorFactoryImpl() {
113: // registry for user-defined datatypes
114: fRegistry = new Hashtable(30);
115:
116: // schema has total of 44 datatypes: primitive and derived
117: // note: for schema validation we always instantiate DTDDatatypes as well..
118: fSchemaDatatypeRegistry = new Hashtable(40);
119: // dtd has total of 9 datatypes
120: fDTDDatatypeRegistry = new Hashtable(10);
121: }
122:
123: /**
124: * Initializes fDTDRegistry with (9) DTD related datatypes .
125: */
126: public void initializeDTDRegistry() {
127:
128: //Register Primitive Datatypes
129:
130: if (fRegistryExpanded == 0) { //Core datatypes shared by DTD attributes and Schema
131: try {
132: fDTDDatatypeRegistry.put("string",
133: new StringDatatypeValidator());
134: fDTDDatatypeRegistry.put("ID",
135: new IDDatatypeValidator());
136: fDTDDatatypeRegistry.put("IDREF",
137: new IDREFDatatypeValidator());
138: fDTDDatatypeRegistry.put("ENTITY",
139: new ENTITYDatatypeValidator());
140: fDTDDatatypeRegistry.put("NOTATION",
141: new NOTATIONDatatypeValidator());
142:
143: createDTDDatatypeValidator("IDREFS",
144: new IDREFDatatypeValidator(), null, true);
145:
146: createDTDDatatypeValidator("ENTITIES",
147: new ENTITYDatatypeValidator(), null, true);
148:
149: Hashtable facets = new Hashtable(2);
150: facets.put(AbstractStringValidator.FACET_SPECIAL_TOKEN,
151: AbstractStringValidator.SPECIAL_TOKEN_NMTOKEN);
152: facets.put(SchemaSymbols.ELT_WHITESPACE,
153: SchemaSymbols.ATT_COLLAPSE);
154: createDTDDatatypeValidator("NMTOKEN",
155: new StringDatatypeValidator(), facets, false);
156:
157: createDTDDatatypeValidator("NMTOKENS",
158: getDatatypeValidator("NMTOKEN"), null, true);
159: fRegistryExpanded = 1;
160: } catch (InvalidDatatypeFacetException ex) {
161: ex.printStackTrace();
162: }
163: }
164: }
165:
166: /**
167: * Initializes fSchemaDatatypeRegistry with schema primitive and derived datatypes.
168: * See W3C Schema Datatype REC.
169: * If DTD registry is not initialized yet, this method will initialize it as well.
170: */
171: public void expandRegistryToFullSchemaSet() {
172: fSchemaValidation = 1;
173: //Register Primitive Datatypes
174: if (fRegistryExpanded != 2) {
175: DatatypeValidator v;
176: try {
177: //REVISIT: we want to create datatypes lazily
178: // esspecially for the types that are not often used
179: //
180: fSchemaDatatypeRegistry.put("anySimpleType",
181: new AnySimpleType());
182: fSchemaDatatypeRegistry.put("boolean",
183: new BooleanDatatypeValidator());
184: fSchemaDatatypeRegistry.put("float",
185: new FloatDatatypeValidator());
186: fSchemaDatatypeRegistry.put("double",
187: new DoubleDatatypeValidator());
188: fSchemaDatatypeRegistry.put("decimal",
189: new DecimalDatatypeValidator());
190: fSchemaDatatypeRegistry.put("hexBinary",
191: new HexBinaryDatatypeValidator());
192: fSchemaDatatypeRegistry.put("base64Binary",
193: new Base64BinaryDatatypeValidator());
194: fSchemaDatatypeRegistry.put("anyURI",
195: new AnyURIDatatypeValidator());
196: fSchemaDatatypeRegistry.put("QName",
197: new QNameDatatypeValidator());
198: fSchemaDatatypeRegistry.put("duration",
199: new DurationDatatypeValidator());
200: fSchemaDatatypeRegistry.put("gDay",
201: new DayDatatypeValidator());
202: fSchemaDatatypeRegistry.put("time",
203: new TimeDatatypeValidator());
204: fSchemaDatatypeRegistry.put("dateTime",
205: new DateTimeDatatypeValidator());
206: fSchemaDatatypeRegistry.put("date",
207: new DateDatatypeValidator());
208: fSchemaDatatypeRegistry.put("gMonthDay",
209: new MonthDayDatatypeValidator());
210: fSchemaDatatypeRegistry.put("gYearMonth",
211: new YearMonthDatatypeValidator());
212: fSchemaDatatypeRegistry.put("gYear",
213: new YearDatatypeValidator());
214: fSchemaDatatypeRegistry.put("gMonth",
215: new MonthDatatypeValidator());
216:
217: if (fRegistryExpanded == 0) {
218: initializeDTDRegistry(); //Initialize common Schema/DTD Datatype validator set if not already initialized
219: }
220:
221: Hashtable facets = new Hashtable(2);
222: facets.put(SchemaSymbols.ELT_WHITESPACE,
223: SchemaSymbols.ATT_REPLACE);
224: createSchemaDatatypeValidator("normalizedString",
225: getDatatypeValidator("string"), facets, false);
226:
227: facets.clear();
228: facets.put(SchemaSymbols.ELT_WHITESPACE,
229: SchemaSymbols.ATT_COLLAPSE);
230: createSchemaDatatypeValidator("token",
231: getDatatypeValidator("string"), facets, false);
232:
233: facets.clear();
234: facets.put(SchemaSymbols.ELT_WHITESPACE,
235: SchemaSymbols.ATT_COLLAPSE);
236: facets
237: .put(SchemaSymbols.ELT_PATTERN,
238: "([a-zA-Z]{2}|[iI]-[a-zA-Z]+|[xX]-[a-zA-Z]+)(-[a-zA-Z]+)*");
239: createSchemaDatatypeValidator("language",
240: getDatatypeValidator("string"), facets, false);
241:
242: facets.clear();
243: facets.put(SchemaSymbols.ELT_WHITESPACE,
244: SchemaSymbols.ATT_COLLAPSE);
245: facets.put(AbstractStringValidator.FACET_SPECIAL_TOKEN,
246: AbstractStringValidator.SPECIAL_TOKEN_NAME);
247: createSchemaDatatypeValidator("Name",
248: getDatatypeValidator("string"), facets, false);
249:
250: facets.clear();
251: facets.put(SchemaSymbols.ELT_WHITESPACE,
252: SchemaSymbols.ATT_COLLAPSE);
253: facets.put(AbstractStringValidator.FACET_SPECIAL_TOKEN,
254: AbstractStringValidator.SPECIAL_TOKEN_NCNAME);
255: createSchemaDatatypeValidator("NCName",
256: getDatatypeValidator("string"), facets, false);
257:
258: facets.clear();
259: facets.put(SchemaSymbols.ELT_FRACTIONDIGITS, "0");
260: createSchemaDatatypeValidator("integer",
261: getDatatypeValidator("decimal"), facets, false);
262:
263: facets.clear();
264: facets.put(SchemaSymbols.ELT_MAXINCLUSIVE, "0");
265: createSchemaDatatypeValidator("nonPositiveInteger",
266: getDatatypeValidator("integer"), facets, false);
267:
268: facets.clear();
269: facets.put(SchemaSymbols.ELT_MAXINCLUSIVE, "-1");
270: createSchemaDatatypeValidator("negativeInteger",
271: getDatatypeValidator("nonPositiveInteger"),
272: facets, false);
273:
274: facets.clear();
275: facets.put(SchemaSymbols.ELT_MAXINCLUSIVE,
276: "9223372036854775807");
277: facets.put(SchemaSymbols.ELT_MININCLUSIVE,
278: "-9223372036854775808");
279: createSchemaDatatypeValidator("long",
280: getDatatypeValidator("integer"), facets, false);
281:
282: facets.clear();
283: facets
284: .put(SchemaSymbols.ELT_MAXINCLUSIVE,
285: "2147483647");
286: facets.put(SchemaSymbols.ELT_MININCLUSIVE,
287: "-2147483648");
288: createSchemaDatatypeValidator("int",
289: getDatatypeValidator("long"), facets, false);
290:
291: facets.clear();
292: facets.put(SchemaSymbols.ELT_MAXINCLUSIVE, "32767");
293: facets.put(SchemaSymbols.ELT_MININCLUSIVE, "-32768");
294: createSchemaDatatypeValidator("short",
295: getDatatypeValidator("int"), facets, false);
296:
297: facets.clear();
298: facets.put(SchemaSymbols.ELT_MAXINCLUSIVE, "127");
299: facets.put(SchemaSymbols.ELT_MININCLUSIVE, "-128");
300: createSchemaDatatypeValidator("byte",
301: getDatatypeValidator("short"), facets, false);
302:
303: facets.clear();
304: facets.put(SchemaSymbols.ELT_MININCLUSIVE, "0");
305: createSchemaDatatypeValidator("nonNegativeInteger",
306: getDatatypeValidator("integer"), facets, false);
307:
308: facets.clear();
309: facets.put(SchemaSymbols.ELT_MAXINCLUSIVE,
310: "18446744073709551615");
311: createSchemaDatatypeValidator("unsignedLong",
312: getDatatypeValidator("nonNegativeInteger"),
313: facets, false);
314:
315: facets.clear();
316: facets
317: .put(SchemaSymbols.ELT_MAXINCLUSIVE,
318: "4294967295");
319: createSchemaDatatypeValidator("unsignedInt",
320: getDatatypeValidator("unsignedLong"), facets,
321: false);
322:
323: facets.clear();
324: facets.put(SchemaSymbols.ELT_MAXINCLUSIVE, "65535");
325: createSchemaDatatypeValidator("unsignedShort",
326: getDatatypeValidator("unsignedInt"), facets,
327: false);
328:
329: facets.clear();
330: facets.put(SchemaSymbols.ELT_MAXINCLUSIVE, "255");
331: createSchemaDatatypeValidator("unsignedByte",
332: getDatatypeValidator("unsignedShort"), facets,
333: false);
334:
335: facets.clear();
336: facets.put(SchemaSymbols.ELT_MININCLUSIVE, "1");
337: createSchemaDatatypeValidator("positiveInteger",
338: getDatatypeValidator("nonNegativeInteger"),
339: facets, false);
340:
341: // in the case of schema, ID/IDREF are of type NCNAME
342: ((IDDatatypeValidator) getDatatypeValidator("ID"))
343: .setTokenType(AbstractStringValidator.SPECIAL_TOKEN_IDNCNAME);
344: ((IDREFDatatypeValidator) getDatatypeValidator("IDREF"))
345: .setTokenType(AbstractStringValidator.SPECIAL_TOKEN_IDREFNCNAME);
346: // set the NCName validator into QName validator
347: QNameDatatypeValidator
348: .setNCNameValidator(getDatatypeValidator("NCName"));
349:
350: fRegistryExpanded = 2;
351: } catch (InvalidDatatypeFacetException ex) {
352: ex.printStackTrace();
353: }
354: }
355: }
356:
357: /**
358: * An optimization option that we should write in the future is to separate the static list
359: * of Datatype Validators from the dynamic part where anonymous, and user derived datatype are
360: * kept, then when we resetRegistry only the dynamic part of the registry should be cleared.
361: * So we don't end up clearing the static part of the table over and over every time that we
362: * do a parse cycle.
363: */
364: public void resetRegistry() {
365: fRegistry.clear();
366: fSchemaValidation = 0;
367: }
368:
369: public DatatypeValidator createDatatypeValidator(String typeName,
370: DatatypeValidator base, Hashtable facets, boolean list)
371: throws InvalidDatatypeFacetException {
372: if (base == null) {
373: return null;
374: }
375: DatatypeValidator simpleType = createSchemaValidator(typeName,
376: base, facets, list);
377: registerUserDefinedValidator(typeName, simpleType);
378: return simpleType;
379: }
380:
381: public DatatypeValidator createDatatypeValidator(String typeName,
382: Vector validators) {
383: DatatypeValidator simpleType = null;
384: if (validators != null) {
385: simpleType = new UnionDatatypeValidator(validators);
386: }
387: if (simpleType != null) {
388: registerUserDefinedValidator(typeName, simpleType);
389: }
390: return simpleType;
391: }
392:
393: /**
394: * Searches different datatype registries depending on validation mode (schema or dtd)
395: *
396: * @param type
397: * @return
398: */
399: public DatatypeValidator getDatatypeValidator(String type) {
400: AbstractDatatypeValidator simpleType = null;
401: if (type == null) {
402: return null;
403: }
404: simpleType = (AbstractDatatypeValidator) fDTDDatatypeRegistry
405: .get(type);
406: if (simpleType == null && fSchemaValidation == 1) {
407: simpleType = (AbstractDatatypeValidator) fSchemaDatatypeRegistry
408: .get(type);
409: if (simpleType == null) {
410: return (DatatypeValidator) fRegistry.get(type);
411: }
412:
413: }
414:
415: return (DatatypeValidator) simpleType;
416:
417: }
418:
419: private DatatypeValidator createSchemaDatatypeValidator(
420: String typeName, DatatypeValidator base, Hashtable facets,
421: boolean list) throws InvalidDatatypeFacetException {
422: DatatypeValidator primitive = createSchemaValidator(typeName,
423: base, facets, list);
424: registerSchemaValidator(typeName, primitive);
425: return primitive;
426: }
427:
428: private DatatypeValidator createDTDDatatypeValidator(
429: String typeName, DatatypeValidator base, Hashtable facets,
430: boolean list) throws InvalidDatatypeFacetException {
431: DatatypeValidator primitive = createSchemaValidator(typeName,
432: base, facets, list);
433: registerDTDValidator(typeName, primitive);
434: return primitive;
435: }
436:
437: private DatatypeValidator createSchemaValidator(String typeName,
438: DatatypeValidator base, Hashtable facets, boolean list)
439: throws InvalidDatatypeFacetException {
440:
441: DatatypeValidator simpleType = null;
442: if (list) {
443: simpleType = new ListDatatypeValidator(base, facets, list);
444: } else {
445: try {
446: String value = (String) facets
447: .get(SchemaSymbols.ELT_WHITESPACE);
448: //for all datatypes other than string, we don't pass WHITESPACE Facet
449: //its value is always 'collapse' and cannot be reset by user
450:
451: if (value != null
452: && !(base instanceof StringDatatypeValidator)) {
453: if (!value.equals(SchemaSymbols.ATT_COLLAPSE))
454: throw new InvalidDatatypeFacetException(
455: "whiteSpace value '"
456: + value
457: + "' for this type must be 'collapse'.");
458: facets.remove(SchemaSymbols.ELT_WHITESPACE);
459: }
460:
461: Class validatorDef = base.getClass();
462:
463: Class[] validatorArgsClass = new Class[] {
464: org.apache.xerces.validators.datatype.DatatypeValidator.class,
465: java.util.Hashtable.class, boolean.class };
466:
467: Object[] validatorArgs = new Object[] { base, facets,
468: Boolean.FALSE };
469: Constructor validatorConstructor = validatorDef
470: .getConstructor(validatorArgsClass);
471: simpleType = (DatatypeValidator) createDatatypeValidator(
472: validatorConstructor, validatorArgs);
473: } catch (NoSuchMethodException e) {
474: e.printStackTrace();
475: }
476:
477: }
478: return simpleType;
479: }
480:
481: private void registerUserDefinedValidator(String typeName,
482: DatatypeValidator simpleType) {
483: if (simpleType != null) {
484: fRegistry.put(typeName, simpleType);
485: }
486: }
487:
488: private void registerSchemaValidator(String typeName,
489: DatatypeValidator simpleType) {
490: if (simpleType != null) {
491: fSchemaDatatypeRegistry.put(typeName, simpleType);
492: }
493: }
494:
495: private void registerDTDValidator(String typeName,
496: DatatypeValidator simpleType) {
497: if (simpleType != null) {
498: fDTDDatatypeRegistry.put(typeName, simpleType);
499: }
500: }
501:
502: private static Object createDatatypeValidator(
503: Constructor validatorConstructor, Object[] arguments)
504: throws InvalidDatatypeFacetException {
505: Object validator = null;
506: try {
507: validator = validatorConstructor.newInstance(arguments);
508: } catch (InstantiationException e) {
509: if (fDebug) {
510: e.printStackTrace();
511: }
512: } catch (IllegalAccessException e) {
513: if (fDebug) {
514: e.printStackTrace();
515: }
516: } catch (IllegalArgumentException e) {
517: if (fDebug) {
518: e.printStackTrace();
519: }
520: } catch (InvocationTargetException e) {
521: if (fDebug) {
522: System.out.println("!! The original error message is: "
523: + e.getTargetException().getMessage());
524: e.getTargetException().printStackTrace();
525: } else {
526: throw new InvalidDatatypeFacetException(e
527: .getTargetException().getMessage());
528: }
529: }
530:
531: return validator;
532: }
533:
534: }
|