blob: fe1114a94d7a3682d491ea9186ba54f1a6cdc64f [file] [log] [blame]
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 2000 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) 1999, 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.dtd;
import java.util.Hashtable;
import java.util.Enumeration;
import java.lang.reflect.*;
import org.apache.xerces.impl.dtd.Grammar;
/**
*
* This class implements a factory of Datatype Validators. Internally the
* DatatypeValidators are kept in a registry.<BR>
* There is one instance of DatatypeValidatorFactoryImpl per Parser.<BR>
* There is one datatype Registry per instance of DatatypeValidatorFactoryImpl,
* such registry is first allocated with the number DatatypeValidators needed.<BR>
* e.g.
* If Parser finds an XML document with a DTD, a registry of DTD validators (only
* 9 validators) get initialized in the registry.
* The initialization process consist of instantiating the Datatype and
* facets and registering the Datatype into registry table.
* This implementatio uses a Hahtable as a registry table but future implementation
* should use a lighter object, maybe a Map class ( not use a derived Map class
* because of JDK 1.1.8 no supporting Map).<BR>
* <BR>
* As the Parser parses an instance document it knows if validation needs
* to be checked. If no validation is necesary we should not instantiate a
* DatatypeValidatorFactoryImpl.<BR>
* If validation is needed, we need to instantiate a DatatypeValidatorFactoryImpl.<BR>
*
* @author Jeffrey Rodriguez
* @version $Id$
*/
public class DatatypeValidatorFactoryImpl implements DatatypeValidatorFactory {
private static final boolean fDebug = false;
//private Hashtable fgBaseTypes = new Hashtable();
//private boolean fRegistryExpanded = false;
protected static final Hashtable fgBaseTypes = new Hashtable();
protected static boolean fgRegistryExpanded = false;
protected Hashtable fUserDefinedTypes = new Hashtable();
/***
private static DatatypeValidatorFactoryImpl fRegistryOfDatatypes =
new DatatypeValidatorFactoryImpl();//comment this in when switching to no Singleton
public DatatypeValidatorFactoryImpl() {
}
/***/
/* comment this out when change to no singleton.
public DatatypeValidatorFactoryImpl() {
}
*/
//Register Primitive Datatypes
/***
public void expandRegistryToFullSchemaSet() {
//Register Primitive Datatypes
if (fgRegistryExpanded == false) {
fgRegistryExpanded = true;
DatatypeValidator v;
try {
fgBaseTypes.put("string", new StringDatatypeValidator() );
fgBaseTypes.put("boolean", new BooleanDatatypeValidator() );
fgBaseTypes.put("float", new FloatDatatypeValidator());
fgBaseTypes.put("double", new DoubleDatatypeValidator());
fgBaseTypes.put("decimal", new DecimalDatatypeValidator());
fgBaseTypes.put("timeDuration", new TimeDurationDatatypeValidator());
fgBaseTypes.put("recurringDuration", new RecurringDurationDatatypeValidator());
fgBaseTypes.put("binary", new BinaryDatatypeValidator());
fgBaseTypes.put("uriReference", new URIReferenceDatatypeValidator());
fgBaseTypes.put("ID", new IDDatatypeValidator());
fgBaseTypes.put("IDREF", new IDREFDatatypeValidator());
fgBaseTypes.put("ENTITY", new ENTITYDatatypeValidator());
fgBaseTypes.put("NOTATION", new NOTATIONDatatypeValidator());
fgBaseTypes.put("QName", new QNameDatatypeValidator());
Hashtable facets = new Hashtable();
facets.put(SchemaSymbols.ELT_PATTERN , "([a-zA-Z]{2}|[iI]-[a-zA-Z]+|[xX]-[a-zA-Z]+)(-[a-zA-Z]+)*" );
createDatatypeValidator("language", new StringDatatypeValidator() , facets,
false );
createDatatypeValidator( "IDREFS", new IDREFDatatypeValidator(), null , true );
createDatatypeValidator( "ENTITIES", new ENTITYDatatypeValidator(), null, true );
facets = new Hashtable();
facets.put(SchemaSymbols.ELT_PATTERN , "\\c+" );
createDatatypeValidator("NMTOKEN", new StringDatatypeValidator(), facets, false );
createDatatypeValidator("NMTOKENS",
getDatatypeValidator( "NMTOKEN" ), null, true );
facets = new Hashtable();
facets.put(SchemaSymbols.ELT_PATTERN , "\\i\\c*" );
createDatatypeValidator("Name", new StringDatatypeValidator(), facets, false );
facets = new Hashtable();
facets.put(SchemaSymbols.ELT_PATTERN , "[\\i-[:]][\\c-[:]]*" );
createDatatypeValidator("NCName", new StringDatatypeValidator(), facets, false );
facets = new Hashtable();
facets.put(SchemaSymbols.ELT_SCALE, "0");
createDatatypeValidator("integer", new DecimalDatatypeValidator(), facets, false);
facets = new Hashtable();
facets.put(SchemaSymbols.ELT_MAXINCLUSIVE , "0" );
createDatatypeValidator("nonPositiveInteger",
getDatatypeValidator("integer"), facets, false );
facets = new Hashtable();
facets.put(SchemaSymbols.ELT_MAXINCLUSIVE , "-1" );
createDatatypeValidator("negativeInteger",
getDatatypeValidator( "nonPositiveInteger"), facets, false );
facets = new Hashtable();
facets.put(SchemaSymbols.ELT_MAXINCLUSIVE , "9223372036854775807");
facets.put(SchemaSymbols.ELT_MININCLUSIVE, "-9223372036854775808");
createDatatypeValidator("long", getDatatypeValidator( "integer"), facets, false );
facets = new Hashtable();
facets.put(SchemaSymbols.ELT_MAXINCLUSIVE , "2147483647");
facets.put(SchemaSymbols.ELT_MININCLUSIVE, "-2147483648");
createDatatypeValidator("int", getDatatypeValidator( "long"), facets,false );
facets = new Hashtable();
facets.put(SchemaSymbols.ELT_MAXINCLUSIVE , "32767");
facets.put(SchemaSymbols.ELT_MININCLUSIVE, "-32768");
createDatatypeValidator("short", getDatatypeValidator( "int"), facets, false );
facets = new Hashtable();
facets.put(SchemaSymbols.ELT_MAXINCLUSIVE , "127");
facets.put(SchemaSymbols.ELT_MININCLUSIVE, "-128");
createDatatypeValidator("byte",
getDatatypeValidator( "short"), facets, false );
facets = new Hashtable();
facets.put(SchemaSymbols.ELT_MININCLUSIVE, "0" );
createDatatypeValidator("nonNegativeInteger",
getDatatypeValidator( "integer"), facets, false );
facets = new Hashtable();
facets.put(SchemaSymbols.ELT_MAXINCLUSIVE, "18446744073709551615" );
createDatatypeValidator("unsignedLong",
getDatatypeValidator( "nonNegativeInteger"), facets, false );
facets = new Hashtable();
facets.put(SchemaSymbols.ELT_MAXINCLUSIVE, "4294967295" );
createDatatypeValidator("unsignedInt",
getDatatypeValidator( "unsignedLong"), facets, false );
facets = new Hashtable();
facets.put(SchemaSymbols.ELT_MAXINCLUSIVE, "65535" );
createDatatypeValidator("unsignedShort",
getDatatypeValidator( "unsignedInt"), facets, false );
facets = new Hashtable();
facets.put(SchemaSymbols.ELT_MAXINCLUSIVE, "255" );
createDatatypeValidator("unsignedByte",
getDatatypeValidator( "unsignedShort"), facets, false );
facets = new Hashtable();
facets.put(SchemaSymbols.ELT_MININCLUSIVE, "1" );
createDatatypeValidator("positiveInteger",
getDatatypeValidator( "nonNegativeInteger"), facets, false );
facets = new Hashtable();
facets.put(SchemaSymbols.ELT_DURATION, "P0Y" );
facets.put(SchemaSymbols.ELT_PERIOD, "P0Y" );
createDatatypeValidator("timeInstant",
getDatatypeValidator( "recurringDuration"),facets, false );
facets = new Hashtable();
facets.put(SchemaSymbols.ELT_DURATION, "P0Y" );
// facets.put(SchemaSymbols.ELT_PERIOD, "PY24H" ); Bug -- WORK TODO
createDatatypeValidator("time",
getDatatypeValidator( "recurringDuration"), facets, false );
facets = new Hashtable();
facets.put(SchemaSymbols.ELT_PERIOD, "P0Y" );
createDatatypeValidator("timePeriod",
getDatatypeValidator( "recurringDuration"), facets, false );
facets = new Hashtable();
facets.put(SchemaSymbols.ELT_DURATION, "PT24H" );
createDatatypeValidator("date",
getDatatypeValidator( "timePeriod"), facets, false );
facets = new Hashtable();
facets.put(SchemaSymbols.ELT_DURATION, "P1M" );
createDatatypeValidator("month",
getDatatypeValidator( "timePeriod"), facets, false );
facets = new Hashtable();
facets.put(SchemaSymbols.ELT_DURATION, "P1Y" );
createDatatypeValidator("year",
getDatatypeValidator( "timePeriod"), facets, false );
facets = new Hashtable();
facets.put(SchemaSymbols.ELT_DURATION, "P100Y" );
createDatatypeValidator("century",
getDatatypeValidator( "timePeriod"), facets, false );
facets = new Hashtable();
facets.put(SchemaSymbols.ELT_PERIOD, "P1Y" );
facets.put(SchemaSymbols.ELT_DURATION, "PT24H" );
createDatatypeValidator("recurringDate",
getDatatypeValidator( "recurringDuration"),facets, false );
} catch (InvalidDatatypeFacetException ex) {
ex.printStackTrace();
} catch (InvalidDatatypeValueException ex) {
ex.printStackTrace();
}
}
}
/***/
/**
* Initializes registry with primitive and derived
* Simple types.
*
* This method does not clear the registry to clear
* the registry you have to call resetRegistry.
*
* The net effect of this method is to start with
* a the smallest set of datatypes needed by the
* validator.
*
* If we start with DTD's then we initialize the
* table to only the 9 validators needed by DTD Validation.
*
* If we start with Schema's then we initialize to
* to full set of validators.
*
* @param registrySet
*/
public void initializeDTDRegistry() {
if (fgRegistryExpanded == false) { //Core datatypes shared by DTD attributes and Schema
try {
fgBaseTypes.put("string", new StringDatatypeValidator() );
fgBaseTypes.put("ID", new IDDatatypeValidator());
fgBaseTypes.put("IDREF", new IDREFDatatypeValidator());
fgBaseTypes.put("ENTITY", new ENTITYDatatypeValidator());
fgBaseTypes.put("NOTATION", new NOTATIONDatatypeValidator());
createDatatypeValidator( "IDREFS", new IDREFDatatypeValidator(), null , true );
createDatatypeValidator( "ENTITIES", new ENTITYDatatypeValidator(), null, true );
/***
Hashtable facets = new Hashtable();
facets.put(SchemaSymbols.ELT_PATTERN , "\\c+" );
createDatatypeValidator("NMTOKEN", new StringDatatypeValidator(), facets, false );
/***/
createDatatypeValidator("NMTOKEN", new NMTOKENDatatypeValidator(), null, false );
/***/
createDatatypeValidator("NMTOKENS",
getDatatypeValidator( "NMTOKEN" ), null, true );
} catch (InvalidDatatypeFacetException ex) {
ex.printStackTrace();
} catch (InvalidDatatypeValueException ex) {
ex.printStackTrace();
}
}
}
public void resetRegistry() {
if (fgBaseTypes != null) {
fgBaseTypes.clear();
fgRegistryExpanded = false;
//initializeDTDRegistry();
}
}
/**
* Create datatype validator.
*
* @param name Name of type.
* @param base The base type, or null if there is no base type.
* @param facets The facets.
* @param list True if this type is a list.
*
* @return The new datatype validator.
*/
public DatatypeValidator createDatatypeValidator(String name, DatatypeValidator base, Hashtable facets, boolean list)
throws InvalidDatatypeFacetException, InvalidDatatypeValueException {
DatatypeValidator simpleType = null;
if (this.fDebug == true) {
System.out.println("type name = " + name );
}
if (base == null) {
synchronized (DatatypeValidatorFactoryImpl.class) {
if (!fgBaseTypes.containsKey(name)) {
// lazily construct DTD base types
if (!fgBaseTypes.containsKey("NMTOKEN")) {
initializeDTDRegistry();
}
/***
if (!fgBaseTypes.containsKey(name)) {
// lazily construct Schema base types
if (!fgBaseTypes.containsKey("boolean")) {
expandRegistryToFullSchemaSet();
}
}
/***/
}
}
base = getDatatypeValidator(name);
}
if (base != null) {
if (list) {
simpleType = new ListDatatypeValidator(base, facets, list);
} else {
try {
Class validatorDef = base.getClass();
Class [] validatorArgsClass = new Class[] {
org.apache.xerces.impl.dv.dtd.DatatypeValidator.class,
java.util.Hashtable.class,
boolean.class};
Object [] validatorArgs = new Object[] {
base, facets, Boolean.FALSE};
Constructor validatorConstructor =
validatorDef.getConstructor( validatorArgsClass );
simpleType =
( DatatypeValidator ) createDatatypeValidator (
validatorConstructor, validatorArgs );
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
if (simpleType != null) {
addValidator( name, simpleType );//register validator
}
}
return simpleType;// return it
}
private static Object createDatatypeValidator(Constructor validatorConstructor,
Object[] arguments) throws InvalidDatatypeFacetException {
Object validator = null;
try {
validator = validatorConstructor.newInstance(arguments);
return validator;
} catch (InstantiationException e) {
if (fDebug) {
e.printStackTrace();
} else {
return null;
}
} catch (IllegalAccessException e) {
if (fDebug) {
e.printStackTrace();
} else {
return null;
}
} catch (IllegalArgumentException e) {
if (fDebug) {
e.printStackTrace();
} else {
return null;
}
} catch (InvocationTargetException e) {
if (fDebug) {
System.out.println("!! The original error message is: " + e.getTargetException().getMessage() );
e.getTargetException().printStackTrace();
} else {
throw new InvalidDatatypeFacetException( e.getTargetException().getMessage() );
//System.out.println("Exception: " + e.getTargetException
//validator = null;
}
}
return validator;
}
public DatatypeValidator getDatatypeValidator(String type) {
DatatypeValidator validator = (DatatypeValidator)fUserDefinedTypes.get(type);
if (validator == null) {
validator = (DatatypeValidator)fgBaseTypes.get(type);
}
return validator;
}
private void addValidator(String name, DatatypeValidator v) {
fUserDefinedTypes.put(name,v);
}
/***
static public DatatypeValidatorFactoryImpl getDatatypeRegistry() {
return fRegistryOfDatatypes;
}//this method needs to be deleted or commented in once we change to no Singleton
static public void main( String argv[] ) {
DatatypeValidatorFactoryImpl tstRegistry = DatatypeValidatorFactoryImpl.getDatatypeRegistry();//this needs to ne commented out or deleted once we go to no singleton
// This needs to be commented out
//DatatypeValidatorFactoryImpl tstRegistry = new DatatypeValidatorFactoryImpl();
System.out.println("tstRegistry = " + tstRegistry );
DatatypeValidator tstData1 = tstRegistry.getDatatypeValidator( "string" );
DatatypeValidator tstData2 = tstRegistry.getDatatypeValidator( "boolean" );
DatatypeValidator tstData3 = tstRegistry.getDatatypeValidator( "NOTATION" );
DatatypeValidator tstData4 = tstRegistry.getDatatypeValidator( "float" );
System.out.println( "string = " + tstData1 );
System.out.println( "boolean = " + tstData2 );
System.out.println( "NOTATION = " + tstData3 );
System.out.println( "registry = " + tstRegistry );
System.out.println( "basetypes registered are " );
Enumeration listOfDatatypes = tstRegistry.fBaseTypes.keys();
int index = 0;
while (listOfDatatypes.hasMoreElements()) {
System.out.println( "Datatype[ " + (index++) + "] =" + listOfDatatypes.nextElement() );
}
String value = "3.444";
try {
tstData4.validate( value, null );
} catch (Exception ex) {
ex.printStackTrace();
}
System.out.println("Value = " + value + " is valid " );
value = "b344.3";
try {
tstData4.validate( value, null );
} catch (Exception ex) {
System.out.println("float value = " + value + " is Not valid " );
}
DatatypeValidator idData = tstRegistry.getDatatypeValidator( "ID" );
if (idData != null) {
((IDDatatypeValidator) idData).initialize(null);
try {
idData.validate( "a1", null );
idData.validate( "a2", null );
} catch (Exception ex) {
ex.printStackTrace();
}
Hashtable tst = (Hashtable)((IDDatatypeValidator) idData).getInternalStateInformation();
if (tst != null) {
System.out.println("Table of ID = " + tst.toString());
}
//try {
// idData.validate( "a1", null );
//} catch ( Exception ex ) {
// ex.printStackTrace();// Should throw a unique exception
//}
}
DatatypeValidator idRefData = tstRegistry.getDatatypeValidator("IDREF" );
if (idRefData != null) {
IDREFDatatypeValidator refData = (IDREFDatatypeValidator) idRefData;
refData.initialize( ((IDDatatypeValidator) idData).getInternalStateInformation());
try {
refData.validate( "a1", null );
refData.validate( "a2", null );
//refData.validate( "a3", null );//Should throw exception at validate()
refData.validate();
} catch (Exception ex) {
ex.printStackTrace();
}
}
Grammar grammar = new Grammar();
if (grammar != null) {
ENTITYDatatypeValidator entityValidator
= (ENTITYDatatypeValidator) tstRegistry.getDatatypeValidator("ENTITY");
entityValidator.initialize( grammar );
try {
entityValidator.validate( "a1", null );//Should throw exception
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
/***/
}