All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.xerces.impl.xs.XSValidatorHelper Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.xerces.impl.xs;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.Vector;

import org.apache.xerces.impl.Constants;
import org.apache.xerces.impl.XMLEntityManager;
import org.apache.xerces.impl.XMLErrorReporter;
import org.apache.xerces.impl.dv.ValidatedInfo;
import org.apache.xerces.impl.dv.XSSimpleType;
import org.apache.xerces.impl.dv.xs.EqualityHelper;
import org.apache.xerces.impl.validation.ValidationManager;
import org.apache.xerces.impl.validation.ValidationState;
import org.apache.xerces.impl.xs.identity.Field;
import org.apache.xerces.impl.xs.identity.FieldActivator;
import org.apache.xerces.impl.xs.identity.IdentityConstraint;
import org.apache.xerces.impl.xs.identity.KeyRef;
import org.apache.xerces.impl.xs.identity.Selector;
import org.apache.xerces.impl.xs.identity.UniqueOrKey;
import org.apache.xerces.impl.xs.identity.ValueStore;
import org.apache.xerces.impl.xs.identity.XPathMatcher;
import org.apache.xerces.impl.xs.models.CMBuilder;
import org.apache.xerces.impl.xs.models.CMNodeFactory;
import org.apache.xerces.impl.xs.models.XSCMValidator;
import org.apache.xerces.util.AugmentationsImpl;
import org.apache.xerces.util.IntStack;
import org.apache.xerces.util.SymbolTable;
import org.apache.xerces.util.XMLSymbols;
import org.apache.xerces.util.URI.MalformedURIException;
import org.apache.xerces.xni.NamespaceContext;
import org.apache.xerces.xni.QName;
import org.apache.xerces.xni.XMLAttributes;
import org.apache.xerces.xni.XMLDocumentHandler;
import org.apache.xerces.xni.XMLLocator;
import org.apache.xerces.xni.XMLString;
import org.apache.xerces.xni.XNIException;
import org.apache.xerces.xni.grammars.XMLGrammarPool;
import org.apache.xerces.xni.parser.XMLDocumentSource;
import org.apache.xerces.xni.parser.XMLEntityResolver;
import org.apache.xerces.xni.parser.XMLInputSource;
import org.apache.xerces.xs.ShortList;
import org.apache.xerces.xs.StringList;
import org.apache.xerces.xs.XSConstants;
import org.apache.xerces.xs.XSTypeAlternative;
import org.apache.xerces.xs.XSTypeDefinition;
import org.apache.xerces.xs.datatypes.ObjectList;

/**
 * 
 * A class providing functionalities and object state data to XML Schema validator. Important
 * functionalities provided by this class are IDC constraint primitives, schema error handling
 * routines and CTA/assertion interfaces with the XML Schema validator.
 * 
 * @xerces.internal
 * 
 * @author Sandy Gao IBM
 * @author Elena Litani IBM
 * @author Andy Clark IBM
 * @author Neeraj Bajaj, Sun Microsystems, inc.
 * @version $Id: XSValidatorHelper.java 1610123 2014-07-13 06:27:43Z mukulg $
 */
public class XSValidatorHelper implements XSElementDeclHelper, FieldActivator {
    
    protected XSValidatorHelper() {
       // NO OP  
    }
    
    //
    // Constants
    //
    protected static final boolean DEBUG = false;

    // feature identifiers

    /** Feature identifier: validation. */
    protected static final String VALIDATION =
        Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE;

    /** Feature identifier: validation. */
    protected static final String SCHEMA_VALIDATION =
        Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE;

    /** Feature identifier: schema full checking*/
    protected static final String SCHEMA_FULL_CHECKING =
        Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_FULL_CHECKING;

    /** Feature identifier: dynamic validation. */
    protected static final String DYNAMIC_VALIDATION =
        Constants.XERCES_FEATURE_PREFIX + Constants.DYNAMIC_VALIDATION_FEATURE;

    /** Feature identifier: expose schema normalized value */
    protected static final String NORMALIZE_DATA =
        Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_NORMALIZED_VALUE;

    /** Feature identifier: send element default value via characters() */
    protected static final String SCHEMA_ELEMENT_DEFAULT =
        Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_ELEMENT_DEFAULT;

    /** Feature identifier: augment PSVI */
    protected static final String SCHEMA_AUGMENT_PSVI =
        Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_AUGMENT_PSVI;

    /** Feature identifier: whether to recognize java encoding names */
    protected static final String ALLOW_JAVA_ENCODINGS =
        Constants.XERCES_FEATURE_PREFIX + Constants.ALLOW_JAVA_ENCODINGS_FEATURE;

    /** Feature identifier: standard uri conformant feature. */
    protected static final String STANDARD_URI_CONFORMANT_FEATURE =
        Constants.XERCES_FEATURE_PREFIX + Constants.STANDARD_URI_CONFORMANT_FEATURE;
    
    /** Feature: generate synthetic annotations */
    protected static final String GENERATE_SYNTHETIC_ANNOTATIONS = 
        Constants.XERCES_FEATURE_PREFIX + Constants.GENERATE_SYNTHETIC_ANNOTATIONS_FEATURE;
    
    /** Feature identifier: validate annotations. */
    protected static final String VALIDATE_ANNOTATIONS =
        Constants.XERCES_FEATURE_PREFIX + Constants.VALIDATE_ANNOTATIONS_FEATURE;
    
    /** Feature identifier: honour all schemaLocations */
    protected static final String HONOUR_ALL_SCHEMALOCATIONS = 
        Constants.XERCES_FEATURE_PREFIX + Constants.HONOUR_ALL_SCHEMALOCATIONS_FEATURE;

    /** Feature identifier: use grammar pool only */
    protected static final String USE_GRAMMAR_POOL_ONLY =
        Constants.XERCES_FEATURE_PREFIX + Constants.USE_GRAMMAR_POOL_ONLY_FEATURE;

    /** Feature identifier: whether to continue parsing a schema after a fatal error is encountered */
    protected static final String CONTINUE_AFTER_FATAL_ERROR =
        Constants.XERCES_FEATURE_PREFIX + Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE;

    protected static final String PARSER_SETTINGS =
            Constants.XERCES_FEATURE_PREFIX + Constants.PARSER_SETTINGS;
    
    /** Feature identifier: namespace growth */
    protected static final String NAMESPACE_GROWTH = 
        Constants.XERCES_FEATURE_PREFIX + Constants.NAMESPACE_GROWTH_FEATURE;

    /** Feature identifier: tolerate duplicates */
    protected static final String TOLERATE_DUPLICATES = 
        Constants.XERCES_FEATURE_PREFIX + Constants.TOLERATE_DUPLICATES_FEATURE;

    /** Feature identifier: whether to ignore xsi:type attributes until a global element declaration is encountered */
    protected static final String IGNORE_XSI_TYPE =
        Constants.XERCES_FEATURE_PREFIX + Constants.IGNORE_XSI_TYPE_FEATURE;
    
    /** Feature identifier: whether to ignore ID/IDREF errors */
    protected static final String ID_IDREF_CHECKING =
        Constants.XERCES_FEATURE_PREFIX + Constants.ID_IDREF_CHECKING_FEATURE;
    
    /** Feature identifier: whether to ignore unparsed entity errors */
    protected static final String UNPARSED_ENTITY_CHECKING =
        Constants.XERCES_FEATURE_PREFIX + Constants.UNPARSED_ENTITY_CHECKING_FEATURE;
    
    /** Feature identifier: whether to ignore identity constraint errors */
    protected static final String IDENTITY_CONSTRAINT_CHECKING =
        Constants.XERCES_FEATURE_PREFIX + Constants.IDC_CHECKING_FEATURE;

    /** Feature identifier: whether to ignore type alternatives */
    protected static final String TYPE_ALTERNATIVES_CHECKING =
        Constants.XERCES_FEATURE_PREFIX + Constants.TYPE_ALTERNATIVES_CHEKING_FEATURE;
    
    /** Feature identifier: whether to allow comment and PI nodes to be visible during  processing */
    protected static final String ASSERT_COMMENT_PI_CHECKING =
        Constants.XERCES_FEATURE_PREFIX + Constants.ASSERT_COMMENT_PI_CHECKING_FEATURE;

    // property identifiers

    /** Property identifier: symbol table. */
    public static final String SYMBOL_TABLE =
        Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;

    /** Property identifier: error reporter. */
    public static final String ERROR_REPORTER =
        Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY;

    /** Property identifier: entity resolver. */
    public static final String ENTITY_RESOLVER =
        Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY;

    /** Property identifier: grammar pool. */
    public static final String XMLGRAMMAR_POOL =
        Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY;

    protected static final String VALIDATION_MANAGER =
        Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY;

    protected static final String ENTITY_MANAGER =
        Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY;

    /** Property identifier: schema location. */
    protected static final String SCHEMA_LOCATION =
        Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_LOCATION;

    /** Property identifier: no namespace schema location. */
    protected static final String SCHEMA_NONS_LOCATION =
        Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_NONS_LOCATION;

    /** Property identifier: JAXP schema source. */
    protected static final String JAXP_SCHEMA_SOURCE =
        Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_SOURCE;

    /** Property identifier: JAXP schema language. */
    protected static final String JAXP_SCHEMA_LANGUAGE =
        Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_LANGUAGE;

    /** Property identifier: root type definition. */
    protected static final String ROOT_TYPE_DEF =
        Constants.XERCES_PROPERTY_PREFIX + Constants.ROOT_TYPE_DEFINITION_PROPERTY;
    
    /** Property identifier: root element declaration. */
    protected static final String ROOT_ELEMENT_DECL =
        Constants.XERCES_PROPERTY_PREFIX + Constants.ROOT_ELEMENT_DECLARATION_PROPERTY;

    /** Property identifier: Schema DV Factory */
    protected static final String SCHEMA_DV_FACTORY = 
        Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_DV_FACTORY_PROPERTY;

    /** Property identifier: xml schema version. */
    protected static final String XML_SCHEMA_VERSION =
        Constants.XERCES_PROPERTY_PREFIX + Constants.XML_SCHEMA_VERSION_PROPERTY;

    /** Property identifier: datatype xml version. */
    protected static final String DATATYPE_XML_VERSION = 
        Constants.XERCES_PROPERTY_PREFIX + Constants.DATATYPE_XML_VERSION_PROPERTY;

    // recognized features and properties

    /** Recognized features. */
    protected static final String[] RECOGNIZED_FEATURES =
        {
            VALIDATION,
            SCHEMA_VALIDATION,
            DYNAMIC_VALIDATION,
            SCHEMA_FULL_CHECKING,
            ALLOW_JAVA_ENCODINGS,
            CONTINUE_AFTER_FATAL_ERROR,
            STANDARD_URI_CONFORMANT_FEATURE,
            GENERATE_SYNTHETIC_ANNOTATIONS,
            VALIDATE_ANNOTATIONS,
            HONOUR_ALL_SCHEMALOCATIONS,
            USE_GRAMMAR_POOL_ONLY,
            IGNORE_XSI_TYPE,
            ID_IDREF_CHECKING,
            IDENTITY_CONSTRAINT_CHECKING,
            UNPARSED_ENTITY_CHECKING,
            NAMESPACE_GROWTH,
            TOLERATE_DUPLICATES,
            TYPE_ALTERNATIVES_CHECKING,
            ASSERT_COMMENT_PI_CHECKING
        };


    /** Feature defaults. */
    protected static final Boolean[] FEATURE_DEFAULTS = { null,
        // NOTE: The following defaults are nulled out on purpose.
        //       If they are set, then when the XML Schema validator
        //       is constructed dynamically, these values may override
        //       those set by the application. This goes against the
        //       whole purpose of XMLComponent#getFeatureDefault but
        //       it can't be helped in this case. -Ac
        // NOTE: Instead of adding default values here, add them (and
        //       the corresponding recognized features) to the objects
        //       that have an XMLSchemaValidator instance as a member,
        //       such as the parser configurations. -PM
        null, //Boolean.FALSE,
        null, //Boolean.FALSE,
        null, //Boolean.FALSE,
        null, //Boolean.FALSE,
        null, //Boolean.FALSE,
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        null
    };

    /** Recognized properties. */
    protected static final String[] RECOGNIZED_PROPERTIES =
        {
            SYMBOL_TABLE,
            ERROR_REPORTER,
            ENTITY_RESOLVER,
            VALIDATION_MANAGER,
            SCHEMA_LOCATION,
            SCHEMA_NONS_LOCATION,
            JAXP_SCHEMA_SOURCE,
            JAXP_SCHEMA_LANGUAGE,
            ROOT_TYPE_DEF,
            ROOT_ELEMENT_DECL,
            SCHEMA_DV_FACTORY,
            XML_SCHEMA_VERSION,
            DATATYPE_XML_VERSION
        };

    /** Property defaults. */
    protected static final Object[] PROPERTY_DEFAULTS =
        { null, null, null, null, null, null, null, null, null, null, null, null, null};

    // this is the number of valuestores of each kind
    // we expect an element to have.  It's almost
    // never > 1; so leave it at that.
    protected static final int ID_CONSTRAINT_NUM = 1;
    
    // xsi:* attribute declarations
    static final XSAttributeDecl XSI_TYPE = SchemaGrammar.SG_XSI.getGlobalAttributeDecl(SchemaSymbols.XSI_TYPE);
    static final XSAttributeDecl XSI_NIL = SchemaGrammar.SG_XSI.getGlobalAttributeDecl(SchemaSymbols.XSI_NIL);
    static final XSAttributeDecl XSI_SCHEMALOCATION = SchemaGrammar.SG_XSI.getGlobalAttributeDecl(SchemaSymbols.XSI_SCHEMALOCATION);
    static final XSAttributeDecl XSI_NONAMESPACESCHEMALOCATION = SchemaGrammar.SG_XSI.getGlobalAttributeDecl(SchemaSymbols.XSI_NONAMESPACESCHEMALOCATION);

    //
    protected static final Hashtable EMPTY_TABLE = new Hashtable();

    //
    // Data
    //

    /** current PSVI element info */
    protected ElementPSVImpl fCurrentPSVI = new ElementPSVImpl();

    // since it is the responsibility of each component to an
    // Augmentations parameter if one is null, to save ourselves from
    // having to create this object continually, it is created here.
    // If it is not present in calls that we're passing on, we *must*
    // clear this before we introduce it into the pipeline.
    protected final AugmentationsImpl fAugmentations = new AugmentationsImpl();

    // this is included for the convenience of handleEndElement
    protected XMLString fDefaultValue;

    // Validation features
    protected boolean fDynamicValidation = false;
    protected boolean fSchemaDynamicValidation = false;
    protected boolean fDoValidation = false;
    protected boolean fFullChecking = false;
    protected boolean fNormalizeData = true;
    protected boolean fSchemaElementDefault = true;
    protected boolean fAugPSVI = true;
    protected boolean fIdConstraint = false;
    protected boolean fUseGrammarPoolOnly = false;

    // Namespace growth feature
    protected boolean fNamespaceGrowth = false;
    
    /** Schema type: None, DTD, Schema */
    protected String fSchemaType = null;

    // to indicate whether we are in the scope of entity reference or CData
    protected boolean fEntityRef = false;
    protected boolean fInCDATA = false;

    // properties

    /** Symbol table. */
    protected SymbolTable fSymbolTable;

    /**
     * While parsing a document, keep the location of the document.
     */
    protected XMLLocator fLocator;

    protected ArrayList fXSITypeErrors = new ArrayList(4);

    protected IDContext fIDContext = null;
    
    protected String fDatatypeXMLVersion = null;
    
    protected NamespaceContext fNamespaceContext = null;
    
    /** Error reporter. */
    protected final XSIErrorReporter fXSIErrorReporter = new XSIErrorReporter();

    /** Entity resolver */
    protected XMLEntityResolver fEntityResolver;

    // updated during reset
    protected ValidationManager fValidationManager = null;
    protected XSValidationState fValidationState = new XSValidationState();
    protected XMLGrammarPool fGrammarPool;

    // schema location property values
    protected String fExternalSchemas = null;
    protected String fExternalNoNamespaceSchema = null;

    //JAXP Schema Source property
    protected Object fJaxpSchemaSource = null;

    /** Schema Grammar Description passed,  to give a chance to application to supply the Grammar */
    protected final XSDDescription fXSDDescription = new XSDDescription();
    protected final Hashtable fLocationPairs = new Hashtable();
    protected final Hashtable fExpandedLocationPairs = new Hashtable();
    protected final ArrayList fUnparsedLocations = new ArrayList();

    /** XML Schema 1.1 Support */
    short fSchemaVersion;

    /** XML Schema Constraints */
    XSConstraints fXSConstraints;

    // handlers

    /** Document handler. */
    protected XMLDocumentHandler fDocumentHandler;

    protected XMLDocumentSource fDocumentSource;
    
    // constants

    static final int INITIAL_STACK_SIZE = 8;
    static final int INC_STACK_SIZE = 8;

    //
    // Data
    //

    // Schema Normalization

    protected static final boolean DEBUG_NORMALIZATION = false;
    // temporary empty string buffer.
    protected final XMLString fEmptyXMLStr = new XMLString(null, 0, -1);
    // temporary character buffer, and empty string buffer.
    protected static final int BUFFER_SIZE = 20;
    protected final XMLString fNormalizedStr = new XMLString();
    protected boolean fFirstChunk = true;
    // got first chunk in characters() (SAX)
    protected boolean fTrailing = false; // Previous chunk had a trailing space
    protected short fWhiteSpace = -1; //whiteSpace: preserve/replace/collapse
    protected boolean fUnionType = false;

    /** Schema grammar resolver. */
    protected final XSGrammarBucket fGrammarBucket = new XSGrammarBucket();
    protected final SubstitutionGroupHandler fSubGroupHandler = new SubstitutionGroupHandler(this);

    /** the DV usd to convert xsi:type to a QName */
    // REVISIT: in new simple type design, make things in DVs static,
    //          so that we can QNameDV.getCompiledForm()
    //          using 1.0 xs:QName
    protected final XSSimpleType fQNameDV =
        (XSSimpleType) SchemaGrammar.getS4SGrammar(Constants.SCHEMA_VERSION_1_0).getGlobalTypeDecl(SchemaSymbols.ATTVAL_QNAME);

    protected final CMNodeFactory nodeFactory = new CMNodeFactory();
    /** used to build content models */
    // REVISIT: create decl pool, and pass it to each traversers
    protected final CMBuilder fCMBuilder = new CMBuilder(nodeFactory);
    
    // Schema grammar loader
    protected final XMLSchemaLoader fSchemaLoader =
        new XMLSchemaLoader(
                fXSIErrorReporter.fErrorReporter,
                fGrammarBucket,
                fSubGroupHandler,
                fCMBuilder);

    // state

    /** String representation of the validation root. */
    // REVISIT: what do we store here? QName, XPATH, some ID? use rawname now.
    protected String fValidationRoot;

    /** Skip validation: anything below this level should be skipped */
    protected int fSkipValidationDepth;

    /** anything above this level has validation_attempted != full */
    protected int fNFullValidationDepth;

    /** anything above this level has validation_attempted != none */
    protected int fNNoneValidationDepth;

    /** Element depth: -2: validator not in pipeline; >= -1 current depth. */
    protected int fElementDepth;

    /** Seen sub elements. */
    protected boolean fSubElement;

    /** Seen sub elements stack. */
    protected boolean[] fSubElementStack = new boolean[INITIAL_STACK_SIZE];

    /** Current element declaration. */
    protected XSElementDecl fCurrentElemDecl;

    /** Element decl stack. */
    protected XSElementDecl[] fElemDeclStack = new XSElementDecl[INITIAL_STACK_SIZE];

    /** nil value of the current element */
    protected boolean fNil;

    /** nil value stack */
    protected boolean[] fNilStack = new boolean[INITIAL_STACK_SIZE];

    /** notation value of the current element */
    protected XSNotationDecl fNotation;

    /** notation stack */
    protected XSNotationDecl[] fNotationStack = new XSNotationDecl[INITIAL_STACK_SIZE];

    /** Current type. */
    protected XSTypeDefinition fCurrentType;
    
    /** Failed assertions. */
    protected ObjectList fFailedAssertions;
    
    /** Type Alternative augmentation information. */
    protected XSTypeAlternative fTypeAlternative;

    /** type stack. */
    protected XSTypeDefinition[] fTypeStack = new XSTypeDefinition[INITIAL_STACK_SIZE];

    /** Current content model. */
    protected XSCMValidator fCurrentCM;

    /** Content model stack. */
    protected XSCMValidator[] fCMStack = new XSCMValidator[INITIAL_STACK_SIZE];

    /** the current state of the current content model */
    protected int[] fCurrCMState;

    /** stack to hold content model states */
    protected int[][] fCMStateStack = new int[INITIAL_STACK_SIZE][];

    /** whether the curret element is strictly assessed */
    protected boolean fStrictAssess = true;

    /** strict assess stack */
    protected boolean[] fStrictAssessStack = new boolean[INITIAL_STACK_SIZE];

    /** Temporary string buffers. */
    protected final StringBuffer fBuffer = new StringBuffer();

    /** Whether need to append characters to fBuffer */
    protected boolean fAppendBuffer = true;

    /** Did we see any character data? */
    protected boolean fSawText = false;

    /** stack to record if we saw character data */
    protected boolean[] fSawTextStack = new boolean[INITIAL_STACK_SIZE];

    /** Did we see non-whitespace character data? */
    protected boolean fSawCharacters = false;

    /** Stack to record if we saw character data outside of element content*/
    protected boolean[] fStringContent = new boolean[INITIAL_STACK_SIZE];

    /** temporary qname */
    protected final QName fTempQName = new QName();
    
    /** value of the "root-type-definition" property. */
    protected javax.xml.namespace.QName fRootTypeQName = null;
    protected XSTypeDefinition fRootTypeDefinition = null;
    
    /** value of the "root-element-declaration" property. */
    protected javax.xml.namespace.QName fRootElementDeclQName = null;
    protected XSElementDecl fRootElementDeclaration = null;
    
    protected int fIgnoreXSITypeDepth;
    
    protected boolean fIDCChecking;

    protected boolean fTypeAlternativesChecking;
    
    protected boolean fCommentsAndPIsForAssert;

    /** temporary validated info */
    protected ValidatedInfo fValidatedInfo = new ValidatedInfo();

    // used to validate default/fixed values against xsi:type
    // only need to check facets, so we set extraChecking to false (in reset)
    protected ValidationState fState4XsiType = new ValidationState();

    // used to apply default/fixed values
    // only need to check id/idref/entity, so we set checkFacets to false
    protected ValidationState fState4ApplyDefault = new ValidationState();

    // identity constraint information

    /**
     * Stack of active XPath matchers for identity constraints. All
     * active XPath matchers are notified of startElement
     * and endElement callbacks in order to perform their matches.
     * 

* For each element with identity constraints, the selector of * each identity constraint is activated. When the selector matches * its XPath, then all the fields of the identity constraint are * activated. *

* Note: Once the activation scope is left, the * XPath matchers are automatically removed from the stack of * active matchers and no longer receive callbacks. */ protected XPathMatcherStack fMatcherStack = new XPathMatcherStack(); /** Cache of value stores for identity constraint fields. */ protected ValueStoreCache fValueStoreCache = new ValueStoreCache(); // assertion validator subcomponent protected XSDAssertionValidator fAssertionValidator = null; // variable to track validity of element content for simpleType->union. if a member type of union in XSD namespace can // successfully validate an element instance value, we don't process assertions for such union types in downstream checks. i.e., // an element instance known to be valid doesn't require assertion evaluations. boolean fIsAssertProcessingNeededForSTUnionElem = true; // variable with similar semantics as fIsAssertProcessingNeededForSTUnionElem, but for attributes of an element instance (i.e., // all attributes of one element instance). List fIsAssertProcessingNeededForSTUnionAttrs = new ArrayList(); // 'type alternative' validator subcomponent protected XSDTypeAlternativeValidator fTypeAlternativeValidator = null; // a Vector list storing inheritable attributes Vector fInheritableAttrList = new Vector(); // a Stack storing inheritable attribute count for the elements protected IntStack fInhrAttrCountStack = new IntStack(); // Implements XSElementDeclHelper interface public XSElementDecl getGlobalElementDecl(QName element) { final SchemaGrammar sGrammar = findSchemaGrammar( XSDDescription.CONTEXT_ELEMENT, element.uri, null, element, null); if (sGrammar != null) { return sGrammar.getGlobalElementDecl(element.localpart); } return null; } /** * A wrapper of the standard error reporter. We'll store all schema errors * in this wrapper object, so that we can get all errors (error codes) of * a specific element. This is useful for PSVI. */ protected final class XSIErrorReporter { // the error reporter property XMLErrorReporter fErrorReporter; // store error codes; starting position of the errors for each element; // number of element (depth); and whether to record error Vector fErrors = new Vector(); int[] fContext = new int[INITIAL_STACK_SIZE]; int fContextCount; // set the external error reporter, clear errors public void reset(XMLErrorReporter errorReporter) { fErrorReporter = errorReporter; fErrors.removeAllElements(); fContextCount = 0; } // should be called when starting process an element or an attribute. // store the starting position for the current context public void pushContext() { if (!fAugPSVI) { return; } // resize array if necessary if (fContextCount == fContext.length) { int newSize = fContextCount + INC_STACK_SIZE; int[] newArray = new int[newSize]; System.arraycopy(fContext, 0, newArray, 0, fContextCount); fContext = newArray; } fContext[fContextCount++] = fErrors.size(); } // should be called on endElement: get all errors of the current element public String[] popContext() { if (!fAugPSVI) { return null; } // get starting position of the current element int contextPos = fContext[--fContextCount]; // number of errors of the current element int size = fErrors.size() - contextPos; // if no errors, return null if (size == 0) return null; // copy errors from the list to an string array String[] errors = new String[size]; for (int i = 0; i < size; i++) { errors[i] = (String) fErrors.elementAt(contextPos + i); } // remove errors of the current element fErrors.setSize(contextPos); return errors; } // should be called when an attribute is done: get all errors of // this attribute, but leave the errors to the containing element // also called after an element was strictly assessed. public String[] mergeContext() { if (!fAugPSVI) { return null; } // get starting position of the current element int contextPos = fContext[--fContextCount]; // number of errors of the current element int size = fErrors.size() - contextPos; // if no errors, return null if (size == 0) return null; // copy errors from the list to an string array String[] errors = new String[size]; for (int i = 0; i < size; i++) { errors[i] = (String) fErrors.elementAt(contextPos + i); } // don't resize the vector: leave the errors for this attribute // to the containing element return errors; } public void reportError(String domain, String key, Object[] arguments, short severity) throws XNIException { String message = fErrorReporter.reportError(domain, key, arguments, severity); if (fAugPSVI) { fErrors.addElement(key); fErrors.addElement(message); } } // reportError(String,String,Object[],short) public void reportError( XMLLocator location, String domain, String key, Object[] arguments, short severity) throws XNIException { String message = fErrorReporter.reportError(location, domain, key, arguments, severity); if (fAugPSVI) { fErrors.addElement(key); fErrors.addElement(message); } } // reportError(XMLLocator,String,String,Object[],short) } //this is the function where logic of retrieving grammar is written , parser first tries to get the grammar from //the local pool, if not in local pool, it gives chance to application to be able to retrieve the grammar, then it //tries to parse the grammar using location hints from the give namespace. SchemaGrammar findSchemaGrammar( short contextType, String namespace, QName enclosingElement, QName triggeringComponent, XMLAttributes attributes) { SchemaGrammar grammar = null; //get the grammar from local pool... grammar = fGrammarBucket.getGrammar(namespace); if (grammar == null) { fXSDDescription.setNamespace(namespace); if (fGrammarPool != null) { grammar = (SchemaGrammar) fGrammarPool.retrieveGrammar(fXSDDescription); if (grammar != null) { // put this grammar into the bucket, along with grammars // imported by it (directly or indirectly) if (!fGrammarBucket.putGrammar(grammar, true, fNamespaceGrowth)) { // REVISIT: a conflict between new grammar(s) and grammars // in the bucket. What to do? A warning? An exception? fXSIErrorReporter.fErrorReporter.reportError( XSMessageFormatter.SCHEMA_DOMAIN, "GrammarConflict", null, XMLErrorReporter.SEVERITY_WARNING); grammar = null; } } } } if (!fUseGrammarPoolOnly && (grammar == null || (fNamespaceGrowth && !hasSchemaComponent(grammar, contextType, triggeringComponent)))) { fXSDDescription.reset(); fXSDDescription.fContextType = contextType; fXSDDescription.setNamespace(namespace); fXSDDescription.fEnclosedElementName = enclosingElement; fXSDDescription.fTriggeringComponent = triggeringComponent; fXSDDescription.fAttributes = attributes; if (fLocator != null) { fXSDDescription.setBaseSystemId(fLocator.getExpandedSystemId()); } Hashtable locationPairs = fLocationPairs; Object locationArray = locationPairs.get(namespace == null ? XMLSymbols.EMPTY_STRING : namespace); if (locationArray != null) { String[] temp = ((XMLSchemaLoader.LocationArray) locationArray).getLocationArray(); if (temp.length != 0) { setLocationHints(fXSDDescription, temp, grammar); } } if (grammar == null || fXSDDescription.fLocationHints != null) { boolean toParseSchema = true; if (grammar != null) { // use location hints instead locationPairs = EMPTY_TABLE; } // try to parse the grammar using location hints from that namespace.. try { XMLInputSource xis = XMLSchemaLoader.resolveDocument( fXSDDescription, locationPairs, fEntityResolver); if (grammar != null && fNamespaceGrowth) { try { // if we are dealing with a different schema location, then include the new schema // into the existing grammar if (grammar.getDocumentLocations().contains(XMLEntityManager.expandSystemId(xis.getSystemId(), xis.getBaseSystemId(), false))) { toParseSchema = false; } } catch (MalformedURIException e) { } } if (toParseSchema) { grammar = fSchemaLoader.loadSchema(fXSDDescription, xis, fLocationPairs); } } catch (IOException ex) { final String [] locationHints = fXSDDescription.getLocationHints(); fXSIErrorReporter.fErrorReporter.reportError( XSMessageFormatter.SCHEMA_DOMAIN, "schema_reference.4", new Object[] { locationHints != null ? locationHints[0] : XMLSymbols.EMPTY_STRING }, XMLErrorReporter.SEVERITY_WARNING, ex); } } } return grammar; } //findSchemaGrammar private boolean hasSchemaComponent(SchemaGrammar grammar, short contextType, QName triggeringComponent) { if (grammar != null && triggeringComponent != null) { String localName = triggeringComponent.localpart; if (localName != null && localName.length() > 0) { switch (contextType) { case XSDDescription.CONTEXT_ELEMENT: return grammar.getElementDeclaration(localName) != null; case XSDDescription.CONTEXT_ATTRIBUTE: return grammar.getAttributeDeclaration(localName) != null; case XSDDescription.CONTEXT_XSITYPE: return grammar.getTypeDefinition(localName) != null; } } } return false; } private void setLocationHints(XSDDescription desc, String[] locations, SchemaGrammar grammar) { int length = locations.length; if (grammar == null) { fXSDDescription.fLocationHints = new String[length]; System.arraycopy(locations, 0, fXSDDescription.fLocationHints, 0, length); } else { setLocationHints(desc, locations, grammar.getDocumentLocations()); } } private void setLocationHints(XSDDescription desc, String[] locations, StringList docLocations) { int length = locations.length; String[] hints = new String[length]; int counter = 0; for (int i=0; i 0) { if (counter == length) { fXSDDescription.fLocationHints = hints; } else { fXSDDescription.fLocationHints = new String[counter]; System.arraycopy(hints, 0, fXSDDescription.fLocationHints, 0, counter); } } } void reportSchemaError(String key, Object[] arguments) { if (fDoValidation) fXSIErrorReporter.reportError( XSMessageFormatter.SCHEMA_DOMAIN, key, arguments, XMLErrorReporter.SEVERITY_ERROR); } // xpath matcher information /** * Stack of XPath matchers for identity constraints. */ protected static class XPathMatcherStack { // // Data // /** Active matchers. */ protected XPathMatcher[] fMatchers = new XPathMatcher[4]; /** Count of active matchers. */ protected int fMatchersCount; /** Offset stack for contexts. */ protected IntStack fContextStack = new IntStack(); // // Constructors // public XPathMatcherStack() { } // () // // Public methods // /** Resets the XPath matcher stack. */ public void clear() { for (int i = 0; i < fMatchersCount; i++) { fMatchers[i] = null; } fMatchersCount = 0; fContextStack.clear(); } // clear() /** Returns the size of the stack. */ public int size() { return fContextStack.size(); } // size():int /** Returns the count of XPath matchers. */ public int getMatcherCount() { return fMatchersCount; } // getMatcherCount():int /** Adds a matcher. */ public void addMatcher(XPathMatcher matcher) { ensureMatcherCapacity(); fMatchers[fMatchersCount++] = matcher; } // addMatcher(XPathMatcher) /** Returns the XPath matcher at the specified index. */ public XPathMatcher getMatcherAt(int index) { return fMatchers[index]; } // getMatcherAt(index):XPathMatcher /** Pushes a new context onto the stack. */ public void pushContext() { fContextStack.push(fMatchersCount); } // pushContext() /** Pops a context off of the stack. */ public void popContext() { fMatchersCount = fContextStack.pop(); } // popContext() // // Private methods // /** Ensures the size of the matchers array. */ private void ensureMatcherCapacity() { if (fMatchersCount == fMatchers.length) { XPathMatcher[] array = new XPathMatcher[fMatchers.length * 2]; System.arraycopy(fMatchers, 0, array, 0, fMatchers.length); fMatchers = array; } } // ensureMatcherCapacity() } // class XPathMatcherStack // the purpose of this class is to enable IdentityConstraint,int // pairs to be used easily as keys in Hashtables. protected static final class LocalIDKey { public IdentityConstraint fId; public int fDepth; public LocalIDKey() { } public LocalIDKey(IdentityConstraint id, int depth) { fId = id; fDepth = depth; } // init(IdentityConstraint, int) // object method public int hashCode() { return fId.hashCode() + fDepth; } public boolean equals(Object localIDKey) { if (localIDKey instanceof LocalIDKey) { LocalIDKey lIDKey = (LocalIDKey) localIDKey; return (lIDKey.fId == fId && lIDKey.fDepth == fDepth); } return false; } } // class LocalIDKey // value store implementations /** * Value store implementation base class. There are specific subclasses * for handling unique, key, and keyref. */ protected abstract class ValueStoreBase implements ValueStore { // // Data // /** Identity constraint. */ protected IdentityConstraint fIdentityConstraint; protected int fFieldCount = 0; protected Field[] fFields = null; protected String fElementName; /** current data */ protected Object[] fLocalValues = null; protected short[] fLocalValueTypes = null; protected ShortList[] fLocalItemValueTypes = null; /** Current data value count. */ protected int fValuesCount; /** global data */ public final Vector fValues = new Vector(); public ShortVector fValueTypes = null; public Vector fItemValueTypes = null; private boolean fUseValueTypeVector = false; private int fValueTypesLength = 0; private short fValueType = 0; private boolean fUseItemValueTypeVector = false; private int fItemValueTypesLength = 0; private ShortList fItemValueType = null; /** buffer for error messages */ final StringBuffer fTempBuffer = new StringBuffer(); // // Constructors // /** Constructs a value store for the specified identity constraint. */ protected ValueStoreBase(IdentityConstraint identityConstraint, String elementName) { fElementName = elementName; fIdentityConstraint = identityConstraint; fFieldCount = fIdentityConstraint.getFieldCount(); fFields = new Field[fFieldCount]; fLocalValues = new Object[fFieldCount]; fLocalValueTypes = new short[fFieldCount]; fLocalItemValueTypes = new ShortList[fFieldCount]; for (int i = 0; i < fFieldCount; i++) { fFields[i] = fIdentityConstraint.getFieldAt(i); } } // (IdentityConstraint) // // Public methods // // destroys this ValueStore; useful when, for instance, a // locally-scoped ID constraint is involved. public void clear() { fValuesCount = 0; fUseValueTypeVector = false; fValueTypesLength = 0; fValueType = 0; fUseItemValueTypeVector = false; fItemValueTypesLength = 0; fItemValueType = null; fValues.setSize(0); if (fValueTypes != null) { fValueTypes.clear(); } if (fItemValueTypes != null) { fItemValueTypes.setSize(0); } } // end clear():void // appends the contents of one ValueStore to those of us. public void append(ValueStoreBase newVal) { for (int i = 0; i < newVal.fValues.size(); i++) { fValues.addElement(newVal.fValues.elementAt(i)); // REVISIT: addValueType(newVal.getValueTypeAt(i)); addItemValueType(newVal.getItemValueTypeAt(i)); } } // append(ValueStoreBase) /** Start scope for value store. */ public void startValueScope() { fValuesCount = 0; for (int i = 0; i < fFieldCount; i++) { fLocalValues[i] = null; fLocalValueTypes[i] = 0; fLocalItemValueTypes[i] = null; } } // startValueScope() /** Ends scope for value store. */ public void endValueScope() { if (fValuesCount == 0) { if (fIdentityConstraint.getCategory() == IdentityConstraint.IC_KEY) { String code = "AbsentKeyValue"; String cName = fIdentityConstraint.getIdentityConstraintName(); reportSchemaError(code, new Object[] { fElementName, cName }); } return; } // Validation Rule: Identity-constraint Satisfied // 4.2 If the {identity-constraint category} is key, then all of the following must be true: // 4.2.1 The target node set and the qualified node set are equal, that is, every member of the // target node set is also a member of the qualified node set and vice versa. // // If the IDC is a key check whether we have all the fields. if (fValuesCount != fFieldCount) { if (fIdentityConstraint.getCategory() == IdentityConstraint.IC_KEY) { String code = "KeyNotEnoughValues"; UniqueOrKey key = (UniqueOrKey) fIdentityConstraint; String cName = key.getIdentityConstraintName(); reportSchemaError(code, new Object[] { fElementName, cName }); } return; } } // endValueScope() // This is needed to allow keyref's to look for matched keys // in the correct scope. Unique and Key may also need to // override this method for purposes of their own. // This method is called whenever the DocumentFragment // of an ID Constraint goes out of scope. public void endDocumentFragment() { } // endDocumentFragment():void /** * Signals the end of the document. This is where the specific * instances of value stores can verify the integrity of the * identity constraints. */ public void endDocument() { } // endDocument() // // ValueStore methods // /* reports an error if an element is matched * has nillable true and is matched by a key. */ public void reportError(String key, Object[] args) { reportSchemaError(key, args); } // reportError(String,Object[]) /** * Adds the specified value to the value store. * * @param field The field associated to the value. This reference * is used to ensure that each field only adds a value * once within a selection scope. * @param mayMatch a flag indiciating whether the field may be matched. * @param actualValue The value to add. * @param valueType Type of the value to add. * @param itemValueType If the value is a list, a list of types for each of the values in the list. */ public void addValue(Field field, boolean mayMatch, Object actualValue, short valueType, ShortList itemValueType) { int i; for (i = fFieldCount - 1; i > -1; i--) { if (fFields[i] == field) { break; } } // do we even know this field? if (i == -1) { String code = "UnknownField"; String cName = fIdentityConstraint.getIdentityConstraintName(); reportSchemaError(code, new Object[] { field.toString(), fElementName, cName }); return; } if (!mayMatch) { String code = "FieldMultipleMatch"; String cName = fIdentityConstraint.getIdentityConstraintName(); reportSchemaError(code, new Object[] { field.toString(), cName }); } else { fValuesCount++; } fLocalValues[i] = actualValue; fLocalValueTypes[i] = valueType; fLocalItemValueTypes[i] = itemValueType; if (fValuesCount == fFieldCount) { checkDuplicateValues(); // store values for (i = 0; i < fFieldCount; i++) { fValues.addElement(fLocalValues[i]); addValueType(fLocalValueTypes[i]); addItemValueType(fLocalItemValueTypes[i]); } } } // addValue(String,Field) /** * Sets the name of the element which holds the identity constraint * that is stored in this value store */ public void setElementName(String elementName) { fElementName = elementName; } /** * Returns the name of the element which holds the identity constraint * that is stored in this value store */ public String getElementName() { return fElementName; } // getElementName():String /** * Returns true if this value store contains the locally scoped value stores */ public boolean contains() { // REVISIT: we can improve performance by using hash codes, instead of // traversing global vector that could be quite large. int next = 0; final int size = fValues.size(); LOOP : for (int i = 0; i < size; i = next) { next = i + fFieldCount; for (int j = 0; j < fFieldCount; j++) { final Object value1 = fLocalValues[j]; final Object value2 = fValues.elementAt(i); final short valueType1 = fLocalValueTypes[j]; final short valueType2 = getValueTypeAt(i); final ShortList typeList1 = isListType(valueType1) ? fLocalItemValueTypes[j] : null; final ShortList typeList2 = isListType(valueType2) ? getItemValueTypeAt(i) : null; if (!EqualityHelper.isEqual(value1, value2, valueType1, valueType2, typeList1, typeList2, fSchemaVersion)) { continue LOOP; } i++; } // found it return true; } // didn't find it return false; } // contains():boolean /** * Returns -1 if this value store contains the specified * values, otherwise the index of the first field in the * key sequence. */ public int contains(ValueStoreBase vsb) { final Vector values = vsb.fValues; final int size1 = values.size(); if (fFieldCount <= 1) { LOOP: for (int i = 0; i < size1; ++i) { final Object value1 = values.elementAt(i); final short valueType1 = vsb.getValueTypeAt(i); final ShortList typeList1 = isListType(valueType1) ? vsb.getItemValueTypeAt(i) : null; for (int j=0; j < fValues.size(); ++j) { final Object value2 = fValues.elementAt(j); final short valueType2 = getValueTypeAt(j); final ShortList typeList2 = isListType(valueType2) ? getItemValueTypeAt(j) : null; if (EqualityHelper.isEqual(value1, value2, valueType1, valueType2, typeList1, typeList2, fSchemaVersion)) { continue LOOP; } } return i; } } /** Handle n-tuples. **/ else { final int size2 = fValues.size(); /** Iterate over each set of fields. **/ OUTER: for (int i = 0; i < size1; i += fFieldCount) { /** Check whether this set is contained in the value store. **/ INNER: for (int j = 0; j < size2; j += fFieldCount) { for (int k = 0; k < fFieldCount; ++k) { final Object value1 = values.elementAt(i+k); final Object value2 = fValues.elementAt(j+k); final short valueType1 = vsb.getValueTypeAt(i+k); final short valueType2 = getValueTypeAt(j+k); final ShortList typeList1 = isListType(valueType1) ? vsb.getItemValueTypeAt(i+k) : null; final ShortList typeList2 = isListType(valueType2) ? getItemValueTypeAt(j+k) : null; if (!EqualityHelper.isEqual(value1, value2, valueType1, valueType2, typeList1, typeList2, fSchemaVersion)) { continue INNER; } } continue OUTER; } return i; } } return -1; } // contains(Vector):Object // // Protected methods // protected void checkDuplicateValues() { // no-op } // duplicateValue(Hashtable) /** Returns a string of the specified values. */ protected String toString(Object[] values) { // no values int size = values.length; if (size == 0) { return ""; } fTempBuffer.setLength(0); // construct value string for (int i = 0; i < size; i++) { if (i > 0) { fTempBuffer.append(','); } fTempBuffer.append(values[i]); } return fTempBuffer.toString(); } // toString(Object[]):String /** Returns a string of the specified values. */ protected String toString(Vector values, int start, int length) { // no values if (length == 0) { return ""; } // one value if (length == 1) { return String.valueOf(values.elementAt(start)); } // construct value string StringBuffer str = new StringBuffer(); for (int i = 0; i < length; i++) { if (i > 0) { str.append(','); } str.append(values.elementAt(start + i)); } return str.toString(); } // toString(Vector,int,int):String // // Object methods // /** Returns a string representation of this object. */ public String toString() { String s = super.toString(); int index1 = s.lastIndexOf('$'); if (index1 != -1) { s = s.substring(index1 + 1); } int index2 = s.lastIndexOf('.'); if (index2 != -1) { s = s.substring(index2 + 1); } return s + '[' + fIdentityConstraint + ']'; } // toString():String // // Private methods // private boolean isListType(short type) { return type == XSConstants.LIST_DT || type == XSConstants.LISTOFUNION_DT; } private void addValueType(short type) { if (fUseValueTypeVector) { fValueTypes.add(type); } else if (fValueTypesLength++ == 0) { fValueType = type; } else if (fValueType != type) { fUseValueTypeVector = true; if (fValueTypes == null) { fValueTypes = new ShortVector(fValueTypesLength * 2); } for (int i = 1; i < fValueTypesLength; ++i) { fValueTypes.add(fValueType); } fValueTypes.add(type); } } private short getValueTypeAt(int index) { if (fUseValueTypeVector) { return fValueTypes.valueAt(index); } return fValueType; } private void addItemValueType(ShortList itemValueType) { if (fUseItemValueTypeVector) { fItemValueTypes.add(itemValueType); } else if (fItemValueTypesLength++ == 0) { fItemValueType = itemValueType; } else if (!(fItemValueType == itemValueType || (fItemValueType != null && fItemValueType.equals(itemValueType)))) { fUseItemValueTypeVector = true; if (fItemValueTypes == null) { fItemValueTypes = new Vector(fItemValueTypesLength * 2); } for (int i = 1; i < fItemValueTypesLength; ++i) { fItemValueTypes.add(fItemValueType); } fItemValueTypes.add(itemValueType); } } private ShortList getItemValueTypeAt(int index) { if (fUseItemValueTypeVector) { return (ShortList) fItemValueTypes.elementAt(index); } return fItemValueType; } } // class ValueStoreBase /** * Key value store. */ protected class KeyValueStore extends ValueStoreBase { // REVISIT: Implement a more efficient storage mechanism. -Ac // // Constructors // /** Constructs a key value store. */ public KeyValueStore(UniqueOrKey key, String elementName) { super(key, elementName); } // (Key) // // ValueStoreBase protected methods // /** * Called when a duplicate value is added. */ protected void checkDuplicateValues() { if (contains()) { String code = "DuplicateKey"; String value = toString(fLocalValues); String cName = fIdentityConstraint.getIdentityConstraintName(); reportSchemaError(code, new Object[] { value, fElementName, cName }); } } // duplicateValue(Hashtable) } // class KeyValueStore /** * Key reference value store. */ protected class KeyRefValueStore extends ValueStoreBase { // // Data // /** Key value store. */ protected ValueStoreBase fKeyValueStore; // // Constructors // /** Constructs a key value store. */ public KeyRefValueStore(KeyRef keyRef, KeyValueStore keyValueStore, String elementName) { super(keyRef, elementName); fKeyValueStore = keyValueStore; } // (KeyRef) // // ValueStoreBase methods // // end the value Scope; here's where we have to tie // up keyRef loose ends. public void endDocumentFragment() { // do all the necessary management... super.endDocumentFragment(); // verify references // get the key store corresponding (if it exists): fKeyValueStore = (ValueStoreBase) fValueStoreCache.fGlobalIDConstraintMap.get( ((KeyRef) fIdentityConstraint).getKey()); if (fKeyValueStore == null) { // report error String code = "KeyRefOutOfScope"; String value = fIdentityConstraint.getName(); reportSchemaError(code, new Object[] { value }); return; } int errorIndex = fKeyValueStore.contains(this); if (errorIndex != -1) { String code = "KeyNotFound"; String values = toString(fValues, errorIndex, fFieldCount); String name = fIdentityConstraint.getName(); reportSchemaError(code, new Object[] { name, values, fElementName }); } } // endDocumentFragment() /** End document. */ public void endDocument() { super.endDocument(); } // endDocument() } // class KeyRefValueStore // a utility method for Identity constraints private void activateSelectorFor(IdentityConstraint ic) { Selector selector = ic.getSelector(); FieldActivator activator = this; if (selector == null) return; XPathMatcher matcher = selector.createMatcher(activator, fElementDepth); if (fSchemaVersion == Constants.SCHEMA_VERSION_1_1) { matcher.setXPathDefaultNamespace(selector.getXPathDefaultNamespace()); } fMatcherStack.addMatcher(matcher); matcher.startDocumentFragment(); } // // FieldActivator methods // /** * Request to activate the specified field. This method returns the * matcher for the field. * * @param field The field to activate. */ public XPathMatcher activateField(Field field, int initialDepth) { ValueStore valueStore = fValueStoreCache.getValueStoreFor(field.getIdentityConstraint(), initialDepth); XPathMatcher matcher = field.createMatcher(valueStore); if (fSchemaVersion == Constants.SCHEMA_VERSION_1_1) { matcher.setXPathDefaultNamespace(field.getXPathDefaultNamespace()); } fMatcherStack.addMatcher(matcher); matcher.startDocumentFragment(); return matcher; } // activateField(Field):XPathMatcher /** * Start the value scope for the specified identity constraint. This * method is called when the selector matches in order to initialize * the value store. * * @param identityConstraint The identity constraint. */ public void startValueScopeFor(IdentityConstraint identityConstraint, int initialDepth) { ValueStoreBase valueStore = fValueStoreCache.getValueStoreFor(identityConstraint, initialDepth); valueStore.startValueScope(); } // startValueScopeFor(IdentityConstraint identityConstraint) /** * Ends the value scope for the specified identity constraint. * * @param identityConstraint The identity constraint. */ public void endValueScopeFor(IdentityConstraint identityConstraint, int initialDepth) { ValueStoreBase valueStore = fValueStoreCache.getValueStoreFor(identityConstraint, initialDepth); valueStore.endValueScope(); } // endValueScopeFor(IdentityConstraint) /** * Unique value store. */ protected class UniqueValueStore extends ValueStoreBase { // // Constructors // /** Constructs a unique value store. */ public UniqueValueStore(UniqueOrKey unique, String elementName) { super(unique, elementName); } // (Unique) // // ValueStoreBase protected methods // /** * Called when a duplicate value is added. */ protected void checkDuplicateValues() { // is this value as a group duplicated? if (contains()) { String code = "DuplicateUnique"; String value = toString(fLocalValues); String cName = fIdentityConstraint.getIdentityConstraintName(); reportSchemaError(code, new Object[] { value, fElementName, cName }); } } // duplicateValue(Hashtable) } // class UniqueValueStore // value store management /** * Value store cache. This class is used to store the values for * identity constraints. */ protected class ValueStoreCache { // // Data // final LocalIDKey fLocalId = new LocalIDKey(); // values stores /** stores all global Values stores. */ protected final ArrayList fValueStores = new ArrayList(); /** * Values stores associated to specific identity constraints. * This hashtable maps IdentityConstraints and * the 0-based element on which their selectors first matched to * a corresponding ValueStore. This should take care * of all cases, including where ID constraints with * descendant-or-self axes occur on recursively-defined * elements. */ protected final HashMap fIdentityConstraint2ValueStoreMap = new HashMap(); // sketch of algorithm: // - when a constraint is first encountered, its // values are stored in the (local) fIdentityConstraint2ValueStoreMap; // - Once it is validated (i.e., when it goes out of scope), // its values are merged into the fGlobalIDConstraintMap; // - as we encounter keyref's, we look at the global table to // validate them. // // The fGlobalIDMapStack has the following structure: // - validation always occurs against the fGlobalIDConstraintMap // (which comprises all the "eligible" id constraints); // When an endElement is found, this Hashtable is merged with the one // below in the stack. // When a start tag is encountered, we create a new // fGlobalIDConstraintMap. // i.e., the top of the fGlobalIDMapStack always contains // the preceding siblings' eligible id constraints; // the fGlobalIDConstraintMap contains descendants+self. // keyrefs can only match descendants+self. protected final Stack fGlobalMapStack = new Stack(); protected final HashMap fGlobalIDConstraintMap = new HashMap(); // // Constructors // /** Default constructor. */ public ValueStoreCache() { } // () // // Public methods // /** Resets the identity constraint cache. */ public void startDocument() { fValueStores.clear(); fIdentityConstraint2ValueStoreMap.clear(); fGlobalIDConstraintMap.clear(); fGlobalMapStack.removeAllElements(); } // startDocument() // startElement: pushes the current fGlobalIDConstraintMap // onto fGlobalMapStack and clears fGlobalIDConstraint map. public void startElement() { // only clone the map when there are elements if (fGlobalIDConstraintMap.size() > 0) fGlobalMapStack.push(fGlobalIDConstraintMap.clone()); else fGlobalMapStack.push(null); fGlobalIDConstraintMap.clear(); } // startElement(void) /** endElement(): merges contents of fGlobalIDConstraintMap with the * top of fGlobalMapStack into fGlobalIDConstraintMap. */ public void endElement() { if (fGlobalMapStack.isEmpty()) { return; // must be an invalid doc! } HashMap oldMap = (HashMap) fGlobalMapStack.pop(); // return if there is no element if (oldMap == null) { return; } Iterator entries = oldMap.entrySet().iterator(); while (entries.hasNext()) { Map.Entry entry = (Map.Entry) entries.next(); IdentityConstraint id = (IdentityConstraint) entry.getKey(); ValueStoreBase oldVal = (ValueStoreBase) entry.getValue(); if (oldVal != null) { ValueStoreBase currVal = (ValueStoreBase) fGlobalIDConstraintMap.get(id); if (currVal == null) { fGlobalIDConstraintMap.put(id, oldVal); } else if (currVal != oldVal) { currVal.append(oldVal); } } } } // endElement() /** * Initializes the value stores for the specified element * declaration. */ public void initValueStoresFor(XSElementDecl eDecl, FieldActivator activator) { // initialize value stores for unique fields IdentityConstraint[] icArray = eDecl.fIDConstraints; int icCount = eDecl.fIDCPos; for (int i = 0; i < icCount; i++) { switch (icArray[i].getCategory()) { case (IdentityConstraint.IC_UNIQUE) : // initialize value stores for unique fields UniqueOrKey unique = (UniqueOrKey) icArray[i]; LocalIDKey toHash = new LocalIDKey(unique, fElementDepth); UniqueValueStore uniqueValueStore = (UniqueValueStore) fIdentityConstraint2ValueStoreMap.get(toHash); if (uniqueValueStore == null) { uniqueValueStore = new UniqueValueStore(unique, eDecl.getName()); fIdentityConstraint2ValueStoreMap.put(toHash, uniqueValueStore); } else { uniqueValueStore.clear(); uniqueValueStore.setElementName(eDecl.getName()); } fValueStores.add(uniqueValueStore); activateSelectorFor(icArray[i]); break; case (IdentityConstraint.IC_KEY) : // initialize value stores for key fields UniqueOrKey key = (UniqueOrKey) icArray[i]; toHash = new LocalIDKey(key, fElementDepth); KeyValueStore keyValueStore = (KeyValueStore) fIdentityConstraint2ValueStoreMap.get(toHash); if (keyValueStore == null) { keyValueStore = new KeyValueStore(key, eDecl.getName()); fIdentityConstraint2ValueStoreMap.put(toHash, keyValueStore); } else { keyValueStore.clear(); keyValueStore.setElementName(eDecl.getName()); } fValueStores.add(keyValueStore); activateSelectorFor(icArray[i]); break; case (IdentityConstraint.IC_KEYREF) : // initialize value stores for keyRef fields KeyRef keyRef = (KeyRef) icArray[i]; toHash = new LocalIDKey(keyRef, fElementDepth); KeyRefValueStore keyRefValueStore = (KeyRefValueStore) fIdentityConstraint2ValueStoreMap.get(toHash); if (keyRefValueStore == null) { keyRefValueStore = new KeyRefValueStore(keyRef, null, eDecl.getName()); fIdentityConstraint2ValueStoreMap.put(toHash, keyRefValueStore); } else { keyRefValueStore.clear(); keyRefValueStore.setElementName(eDecl.getName()); } fValueStores.add(keyRefValueStore); activateSelectorFor(icArray[i]); break; } } } // initValueStoresFor(XSElementDecl) /** Returns the value store associated to the specified IdentityConstraint. */ public ValueStoreBase getValueStoreFor(IdentityConstraint id, int initialDepth) { fLocalId.fDepth = initialDepth; fLocalId.fId = id; return (ValueStoreBase) fIdentityConstraint2ValueStoreMap.get(fLocalId); } // getValueStoreFor(IdentityConstraint, int):ValueStoreBase /** Returns the global value store associated to the specified IdentityConstraint. */ public ValueStoreBase getGlobalValueStoreFor(IdentityConstraint id) { return (ValueStoreBase) fGlobalIDConstraintMap.get(id); } // getValueStoreFor(IdentityConstraint):ValueStoreBase // This method takes the contents of the (local) ValueStore // associated with id and moves them into the global // hashtable, if id is a or a . // If it's a , then we leave it for later. public void transplant(IdentityConstraint id, int initialDepth) { fLocalId.fDepth = initialDepth; fLocalId.fId = id; ValueStoreBase newVals = (ValueStoreBase) fIdentityConstraint2ValueStoreMap.get(fLocalId); if (id.getCategory() == IdentityConstraint.IC_KEYREF) return; ValueStoreBase currVals = (ValueStoreBase) fGlobalIDConstraintMap.get(id); if (currVals != null) { currVals.append(newVals); fGlobalIDConstraintMap.put(id, currVals); } else fGlobalIDConstraintMap.put(id, newVals); } // transplant(id) /** Check identity constraints. */ public void endDocument() { int count = fValueStores.size(); for (int i = 0; i < count; i++) { ValueStoreBase valueStore = (ValueStoreBase) fValueStores.get(i); valueStore.endDocument(); } } // endDocument() // // Object methods // /** Returns a string representation of this object. */ public String toString() { String s = super.toString(); int index1 = s.lastIndexOf('$'); if (index1 != -1) { return s.substring(index1 + 1); } int index2 = s.lastIndexOf('.'); if (index2 != -1) { return s.substring(index2 + 1); } return s; } // toString():String } // class ValueStoreCache /** * A simple vector for shorts. */ protected static final class ShortVector { // // Data // /** Current length. */ private int fLength; /** Data. */ private short[] fData; // // Constructors // public ShortVector() {} public ShortVector(int initialCapacity) { fData = new short[initialCapacity]; } // // Public methods // /** Returns the length of the vector. */ public int length() { return fLength; } /** Adds the value to the vector. */ public void add(short value) { ensureCapacity(fLength + 1); fData[fLength++] = value; } /** Returns the short value at the specified position in the vector. */ public short valueAt(int position) { return fData[position]; } /** Clears the vector. */ public void clear() { fLength = 0; } /** Returns whether the short is contained in the vector. */ public boolean contains(short value) { for (int i = 0; i < fLength; ++i) { if (fData[i] == value) { return true; } } return false; } // // Private methods // /** Ensures capacity. */ private void ensureCapacity(int size) { if (fData == null) { fData = new short[8]; } else if (fData.length <= size) { short[] newdata = new short[fData.length * 2]; System.arraycopy(fData, 0, newdata, 0, fData.length); fData = newdata; } } } // class ShortVector XSDAssertionValidator getAssertionValidator() { return fAssertionValidator; } void setIsAssertProcessingNeededForSTUnionElem(boolean isAssertProcessingNeededForSTUnionElem) { this.fIsAssertProcessingNeededForSTUnionElem = isAssertProcessingNeededForSTUnionElem; } List getIsAssertProcessingNeededForSTUnionAttrs() { return fIsAssertProcessingNeededForSTUnionAttrs; } Vector getInheritableAttrList() { return fInheritableAttrList; } } // XSValidatorHelper





© 2015 - 2024 Weber Informatics LLC | Privacy Policy