1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * Copyright 1999-2005 The Apache Software Foundation.
   7  *
   8  * Licensed under the Apache License, Version 2.0 (the "License");
   9  * you may not use this file except in compliance with the License.
  10  * You may obtain a copy of the License at
  11  *
  12  *      http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 
  21 package com.sun.org.apache.xerces.internal.impl.xs;
  22 
  23 import java.io.IOException;
  24 import java.util.ArrayList;
  25 import java.util.HashMap;
  26 import java.util.Hashtable;
  27 import java.util.Iterator;
  28 import java.util.Map;
  29 import java.util.Stack;
  30 import java.util.Vector;
  31 import java.util.ArrayList;
  32 import javax.xml.XMLConstants;
  33 import com.sun.org.apache.xerces.internal.impl.Constants;
  34 import com.sun.org.apache.xerces.internal.impl.RevalidationHandler;
  35 import com.sun.org.apache.xerces.internal.impl.XMLEntityManager;
  36 import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter;
  37 import com.sun.org.apache.xerces.internal.impl.dv.DatatypeException;
  38 import com.sun.org.apache.xerces.internal.impl.dv.InvalidDatatypeValueException;
  39 import com.sun.org.apache.xerces.internal.impl.dv.ValidatedInfo;
  40 import com.sun.org.apache.xerces.internal.impl.dv.XSSimpleType;
  41 import com.sun.org.apache.xerces.internal.impl.validation.ValidationManager;
  42 import com.sun.org.apache.xerces.internal.impl.validation.ValidationState;
  43 import com.sun.org.apache.xerces.internal.impl.xs.identity.Field;
  44 import com.sun.org.apache.xerces.internal.impl.xs.identity.FieldActivator;
  45 import com.sun.org.apache.xerces.internal.impl.xs.identity.IdentityConstraint;
  46 import com.sun.org.apache.xerces.internal.impl.xs.identity.KeyRef;
  47 import com.sun.org.apache.xerces.internal.impl.xs.identity.Selector;
  48 import com.sun.org.apache.xerces.internal.impl.xs.identity.UniqueOrKey;
  49 import com.sun.org.apache.xerces.internal.impl.xs.identity.ValueStore;
  50 import com.sun.org.apache.xerces.internal.impl.xs.identity.XPathMatcher;
  51 import com.sun.org.apache.xerces.internal.impl.xs.models.CMBuilder;
  52 import com.sun.org.apache.xerces.internal.impl.xs.models.CMNodeFactory;
  53 import com.sun.org.apache.xerces.internal.impl.xs.models.XSCMValidator;
  54 import com.sun.org.apache.xerces.internal.util.AugmentationsImpl;
  55 import com.sun.org.apache.xerces.internal.util.IntStack;
  56 import com.sun.org.apache.xerces.internal.util.SymbolTable;
  57 import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl;
  58 import com.sun.org.apache.xerces.internal.util.XMLChar;
  59 import com.sun.org.apache.xerces.internal.util.XMLSymbols;
  60 import com.sun.org.apache.xerces.internal.util.URI.MalformedURIException;
  61 import com.sun.org.apache.xerces.internal.xni.Augmentations;
  62 import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
  63 import com.sun.org.apache.xerces.internal.xni.QName;
  64 import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
  65 import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler;
  66 import com.sun.org.apache.xerces.internal.xni.XMLLocator;
  67 import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
  68 import com.sun.org.apache.xerces.internal.xni.XMLString;
  69 import com.sun.org.apache.xerces.internal.xni.XNIException;
  70 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarDescription;
  71 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarPool;
  72 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent;
  73 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
  74 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
  75 import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentFilter;
  76 import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentSource;
  77 import com.sun.org.apache.xerces.internal.xni.parser.XMLEntityResolver;
  78 import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
  79 import com.sun.org.apache.xerces.internal.xs.AttributePSVI;
  80 import com.sun.org.apache.xerces.internal.xs.ElementPSVI;
  81 import com.sun.org.apache.xerces.internal.xs.ShortList;
  82 import com.sun.org.apache.xerces.internal.xs.StringList;
  83 import com.sun.org.apache.xerces.internal.xs.XSConstants;
  84 import com.sun.org.apache.xerces.internal.xs.XSObjectList;
  85 import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition;
  86 import com.sun.org.apache.xerces.internal.parsers.XMLParser;
  87 
  88 /**
  89  * The XML Schema validator. The validator implements a document
  90  * filter: receiving document events from the scanner; validating
  91  * the content and structure; augmenting the InfoSet, if applicable;
  92  * and notifying the parser of the information resulting from the
  93  * validation process.
  94  * <p>
  95  * This component requires the following features and properties from the
  96  * component manager that uses it:
  97  * <ul>
  98  *  <li>http://xml.org/sax/features/validation</li>
  99  *  <li>http://apache.org/xml/properties/internal/symbol-table</li>
 100  *  <li>http://apache.org/xml/properties/internal/error-reporter</li>
 101  *  <li>http://apache.org/xml/properties/internal/entity-resolver</li>
 102  * </ul>
 103  *
 104  * @xerces.internal
 105  *
 106  * @author Sandy Gao IBM
 107  * @author Elena Litani IBM
 108  * @author Andy Clark IBM
 109  * @author Neeraj Bajaj, Sun Microsystems, inc.
 110  * @version $Id: XMLSchemaValidator.java,v 1.16 2010-11-01 04:39:55 joehw Exp $
 111  */
 112 public class XMLSchemaValidator
 113     implements XMLComponent, XMLDocumentFilter, FieldActivator, RevalidationHandler {
 114 
 115     //
 116     // Constants
 117     //
 118     private static final boolean DEBUG = false;
 119 
 120     // feature identifiers
 121 
 122     /** Feature identifier: validation. */
 123     protected static final String VALIDATION =
 124         Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE;
 125 
 126     /** Feature identifier: validation. */
 127     protected static final String SCHEMA_VALIDATION =
 128         Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE;
 129 
 130     /** Feature identifier: schema full checking*/
 131     protected static final String SCHEMA_FULL_CHECKING =
 132         Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_FULL_CHECKING;
 133 
 134     /** Feature identifier: dynamic validation. */
 135     protected static final String DYNAMIC_VALIDATION =
 136         Constants.XERCES_FEATURE_PREFIX + Constants.DYNAMIC_VALIDATION_FEATURE;
 137 
 138     /** Feature identifier: expose schema normalized value */
 139     protected static final String NORMALIZE_DATA =
 140         Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_NORMALIZED_VALUE;
 141 
 142     /** Feature identifier: send element default value via characters() */
 143     protected static final String SCHEMA_ELEMENT_DEFAULT =
 144         Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_ELEMENT_DEFAULT;
 145 
 146     /** Feature identifier: augment PSVI */
 147     protected static final String SCHEMA_AUGMENT_PSVI =
 148         Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_AUGMENT_PSVI;
 149 
 150     /** Feature identifier: whether to recognize java encoding names */
 151     protected static final String ALLOW_JAVA_ENCODINGS =
 152         Constants.XERCES_FEATURE_PREFIX + Constants.ALLOW_JAVA_ENCODINGS_FEATURE;
 153 
 154     /** Feature identifier: standard uri conformant feature. */
 155     protected static final String STANDARD_URI_CONFORMANT_FEATURE =
 156         Constants.XERCES_FEATURE_PREFIX + Constants.STANDARD_URI_CONFORMANT_FEATURE;
 157 
 158     /** Feature: generate synthetic annotations */
 159     protected static final String GENERATE_SYNTHETIC_ANNOTATIONS =
 160         Constants.XERCES_FEATURE_PREFIX + Constants.GENERATE_SYNTHETIC_ANNOTATIONS_FEATURE;
 161 
 162     /** Feature identifier: validate annotations. */
 163     protected static final String VALIDATE_ANNOTATIONS =
 164         Constants.XERCES_FEATURE_PREFIX + Constants.VALIDATE_ANNOTATIONS_FEATURE;
 165 
 166     /** Feature identifier: honour all schemaLocations */
 167     protected static final String HONOUR_ALL_SCHEMALOCATIONS =
 168         Constants.XERCES_FEATURE_PREFIX + Constants.HONOUR_ALL_SCHEMALOCATIONS_FEATURE;
 169 
 170     /** Feature identifier: use grammar pool only */
 171     protected static final String USE_GRAMMAR_POOL_ONLY =
 172         Constants.XERCES_FEATURE_PREFIX + Constants.USE_GRAMMAR_POOL_ONLY_FEATURE;
 173 
 174     /** Feature identifier: whether to continue parsing a schema after a fatal error is encountered */
 175     protected static final String CONTINUE_AFTER_FATAL_ERROR =
 176         Constants.XERCES_FEATURE_PREFIX + Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE;
 177 
 178     protected static final String PARSER_SETTINGS =
 179             Constants.XERCES_FEATURE_PREFIX + Constants.PARSER_SETTINGS;
 180 
 181     /** Feature identifier: namespace growth */
 182     protected static final String NAMESPACE_GROWTH =
 183         Constants.XERCES_FEATURE_PREFIX + Constants.NAMESPACE_GROWTH_FEATURE;
 184 
 185     /** Feature identifier: tolerate duplicates */
 186     protected static final String TOLERATE_DUPLICATES =
 187         Constants.XERCES_FEATURE_PREFIX + Constants.TOLERATE_DUPLICATES_FEATURE;
 188 
 189     protected static final String REPORT_WHITESPACE =
 190             Constants.SUN_SCHEMA_FEATURE_PREFIX + Constants.SUN_REPORT_IGNORED_ELEMENT_CONTENT_WHITESPACE;
 191 
 192     // property identifiers
 193 
 194     /** Property identifier: symbol table. */
 195     public static final String SYMBOL_TABLE =
 196         Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
 197 
 198     /** Property identifier: error reporter. */
 199     public static final String ERROR_REPORTER =
 200         Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY;
 201 
 202     /** Property identifier: entity resolver. */
 203     public static final String ENTITY_RESOLVER =
 204         Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY;
 205 
 206     /** Property identifier: grammar pool. */
 207     public static final String XMLGRAMMAR_POOL =
 208         Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY;
 209 
 210     protected static final String VALIDATION_MANAGER =
 211         Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY;
 212 
 213     protected static final String ENTITY_MANAGER =
 214         Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY;
 215 
 216     /** Property identifier: schema location. */
 217     protected static final String SCHEMA_LOCATION =
 218         Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_LOCATION;
 219 
 220     /** Property identifier: no namespace schema location. */
 221     protected static final String SCHEMA_NONS_LOCATION =
 222         Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_NONS_LOCATION;
 223 
 224     /** Property identifier: JAXP schema source. */
 225     protected static final String JAXP_SCHEMA_SOURCE =
 226         Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_SOURCE;
 227 
 228     /** Property identifier: JAXP schema language. */
 229     protected static final String JAXP_SCHEMA_LANGUAGE =
 230         Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_LANGUAGE;
 231 
 232     /** Property identifier: Schema DV Factory */
 233     protected static final String SCHEMA_DV_FACTORY =
 234         Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_DV_FACTORY_PROPERTY;
 235 
 236     /** Property identifier: Security property manager. */
 237     private static final String XML_SECURITY_PROPERTY_MANAGER =
 238             Constants.XML_SECURITY_PROPERTY_MANAGER;
 239 
 240     protected static final String USE_SERVICE_MECHANISM = Constants.ORACLE_FEATURE_SERVICE_MECHANISM;
 241 
 242     // recognized features and properties
 243 
 244     /** Recognized features. */
 245     private static final String[] RECOGNIZED_FEATURES =
 246         {
 247             VALIDATION,
 248             SCHEMA_VALIDATION,
 249             DYNAMIC_VALIDATION,
 250             SCHEMA_FULL_CHECKING,
 251             ALLOW_JAVA_ENCODINGS,
 252             CONTINUE_AFTER_FATAL_ERROR,
 253             STANDARD_URI_CONFORMANT_FEATURE,
 254             GENERATE_SYNTHETIC_ANNOTATIONS,
 255             VALIDATE_ANNOTATIONS,
 256             HONOUR_ALL_SCHEMALOCATIONS,
 257             USE_GRAMMAR_POOL_ONLY,
 258             NAMESPACE_GROWTH,
 259             TOLERATE_DUPLICATES,
 260             USE_SERVICE_MECHANISM
 261     };
 262 
 263     /** Feature defaults. */
 264     private static final Boolean[] FEATURE_DEFAULTS = { null,
 265         // NOTE: The following defaults are nulled out on purpose.
 266         //       If they are set, then when the XML Schema validator
 267         //       is constructed dynamically, these values may override
 268         //       those set by the application. This goes against the
 269         //       whole purpose of XMLComponent#getFeatureDefault but
 270         //       it can't be helped in this case. -Ac
 271         null, //Boolean.FALSE,
 272         null, //Boolean.FALSE,
 273         null, //Boolean.FALSE,
 274         null, //Boolean.FALSE,
 275         null, //Boolean.FALSE,
 276         null,
 277         null,
 278         null,
 279         null,
 280         null,
 281         null,
 282         null,
 283         Boolean.TRUE
 284     };
 285 
 286     /** Recognized properties. */
 287     private static final String[] RECOGNIZED_PROPERTIES =
 288         {
 289             SYMBOL_TABLE,
 290             ERROR_REPORTER,
 291             ENTITY_RESOLVER,
 292             VALIDATION_MANAGER,
 293             SCHEMA_LOCATION,
 294             SCHEMA_NONS_LOCATION,
 295             JAXP_SCHEMA_SOURCE,
 296             JAXP_SCHEMA_LANGUAGE,
 297             SCHEMA_DV_FACTORY,
 298             XML_SECURITY_PROPERTY_MANAGER 
 299             };
 300 
 301     /** Property defaults. */
 302     private static final Object[] PROPERTY_DEFAULTS =
 303         { null, null, null, null, null, null, null, null, null, null, null, null, null};
 304 
 305     // this is the number of valuestores of each kind
 306     // we expect an element to have.  It's almost
 307     // never > 1; so leave it at that.
 308     protected static final int ID_CONSTRAINT_NUM = 1;
 309 
 310     //
 311     private static final Hashtable EMPTY_TABLE = new Hashtable();
 312 
 313     //
 314     // Data
 315     //
 316 
 317     /** current PSVI element info */
 318     protected ElementPSVImpl fCurrentPSVI = new ElementPSVImpl();
 319 
 320     // since it is the responsibility of each component to an
 321     // Augmentations parameter if one is null, to save ourselves from
 322     // having to create this object continually, it is created here.
 323     // If it is not present in calls that we're passing on, we *must*
 324     // clear this before we introduce it into the pipeline.
 325     protected final AugmentationsImpl fAugmentations = new AugmentationsImpl();
 326 
 327     /**
 328      * Map which is used to catch instance documents that try
 329      * and match a field several times in the same scope.
 330      */
 331     protected final HashMap fMayMatchFieldMap = new HashMap();
 332 
 333     // this is included for the convenience of handleEndElement
 334     protected XMLString fDefaultValue;
 335 
 336     // Validation features
 337     protected boolean fDynamicValidation = false;
 338     protected boolean fSchemaDynamicValidation = false;
 339     protected boolean fDoValidation = false;
 340     protected boolean fFullChecking = false;
 341     protected boolean fNormalizeData = true;
 342     protected boolean fSchemaElementDefault = true;
 343     protected boolean fAugPSVI = true;
 344     protected boolean fIdConstraint = false;
 345     protected boolean fUseGrammarPoolOnly = false;
 346 
 347     // Namespace growth feature
 348     protected boolean fNamespaceGrowth = false;
 349 
 350     /** Schema type: None, DTD, Schema */
 351     private String fSchemaType = null;
 352 
 353     // to indicate whether we are in the scope of entity reference or CData
 354     protected boolean fEntityRef = false;
 355     protected boolean fInCDATA = false;
 356 
 357     // Did we see only whitespace in element content?
 358     protected boolean fSawOnlyWhitespaceInElementContent = false;
 359 
 360     // properties
 361 
 362     /** Symbol table. */
 363     protected SymbolTable fSymbolTable;
 364 
 365     /**
 366      * While parsing a document, keep the location of the document.
 367      */
 368     private XMLLocator fLocator;
 369 
 370     /**
 371      * A wrapper of the standard error reporter. We'll store all schema errors
 372      * in this wrapper object, so that we can get all errors (error codes) of
 373      * a specific element. This is useful for PSVI.
 374      */
 375     protected final class XSIErrorReporter {
 376 
 377         // the error reporter property
 378         XMLErrorReporter fErrorReporter;
 379 
 380         // store error codes; starting position of the errors for each element;
 381         // number of element (depth); and whether to record error
 382         Vector fErrors = new Vector();
 383         int[] fContext = new int[INITIAL_STACK_SIZE];
 384         int fContextCount;
 385 
 386         // set the external error reporter, clear errors
 387         public void reset(XMLErrorReporter errorReporter) {
 388             fErrorReporter = errorReporter;
 389             fErrors.removeAllElements();
 390             fContextCount = 0;
 391         }
 392 
 393         // should be called when starting process an element or an attribute.
 394         // store the starting position for the current context
 395         public void pushContext() {
 396             if (!fAugPSVI) {
 397                 return;
 398             }
 399             // resize array if necessary
 400             if (fContextCount == fContext.length) {
 401                 int newSize = fContextCount + INC_STACK_SIZE;
 402                 int[] newArray = new int[newSize];
 403                 System.arraycopy(fContext, 0, newArray, 0, fContextCount);
 404                 fContext = newArray;
 405             }
 406 
 407             fContext[fContextCount++] = fErrors.size();
 408         }
 409 
 410         // should be called on endElement: get all errors of the current element
 411         public String[] popContext() {
 412             if (!fAugPSVI) {
 413                 return null;
 414             }
 415             // get starting position of the current element
 416             int contextPos = fContext[--fContextCount];
 417             // number of errors of the current element
 418             int size = fErrors.size() - contextPos;
 419             // if no errors, return null
 420             if (size == 0)
 421                 return null;
 422             // copy errors from the list to an string array
 423             String[] errors = new String[size];
 424             for (int i = 0; i < size; i++) {
 425                 errors[i] = (String) fErrors.elementAt(contextPos + i);
 426             }
 427             // remove errors of the current element
 428             fErrors.setSize(contextPos);
 429             return errors;
 430         }
 431 
 432         // should be called when an attribute is done: get all errors of
 433         // this attribute, but leave the errors to the containing element
 434         // also called after an element was strictly assessed.
 435         public String[] mergeContext() {
 436             if (!fAugPSVI) {
 437                 return null;
 438             }
 439             // get starting position of the current element
 440             int contextPos = fContext[--fContextCount];
 441             // number of errors of the current element
 442             int size = fErrors.size() - contextPos;
 443             // if no errors, return null
 444             if (size == 0)
 445                 return null;
 446             // copy errors from the list to an string array
 447             String[] errors = new String[size];
 448             for (int i = 0; i < size; i++) {
 449                 errors[i] = (String) fErrors.elementAt(contextPos + i);
 450             }
 451             // don't resize the vector: leave the errors for this attribute
 452             // to the containing element
 453             return errors;
 454         }
 455 
 456         public void reportError(String domain, String key, Object[] arguments, short severity)
 457             throws XNIException {
 458             fErrorReporter.reportError(domain, key, arguments, severity);
 459             if (fAugPSVI) {
 460                 fErrors.addElement(key);
 461             }
 462         } // reportError(String,String,Object[],short)
 463 
 464         public void reportError(
 465             XMLLocator location,
 466             String domain,
 467             String key,
 468             Object[] arguments,
 469             short severity)
 470             throws XNIException {
 471             fErrorReporter.reportError(location, domain, key, arguments, severity);
 472             if (fAugPSVI) {
 473                 fErrors.addElement(key);
 474             }
 475         } // reportError(XMLLocator,String,String,Object[],short)
 476     }
 477 
 478     /** Error reporter. */
 479     protected final XSIErrorReporter fXSIErrorReporter = new XSIErrorReporter();
 480 
 481     /** Entity resolver */
 482     protected XMLEntityResolver fEntityResolver;
 483 
 484     // updated during reset
 485     protected ValidationManager fValidationManager = null;
 486     protected ValidationState fValidationState = new ValidationState();
 487     protected XMLGrammarPool fGrammarPool;
 488 
 489     // schema location property values
 490     protected String fExternalSchemas = null;
 491     protected String fExternalNoNamespaceSchema = null;
 492 
 493     //JAXP Schema Source property
 494     protected Object fJaxpSchemaSource = null;
 495 
 496     /** Schema Grammar Description passed,  to give a chance to application to supply the Grammar */
 497     protected final XSDDescription fXSDDescription = new XSDDescription();
 498     protected final Hashtable fLocationPairs = new Hashtable();
 499 
 500 
 501     // handlers
 502 
 503     /** Document handler. */
 504     protected XMLDocumentHandler fDocumentHandler;
 505 
 506     protected XMLDocumentSource fDocumentSource;
 507 
 508     boolean reportWhitespace = false;
 509 
 510     //
 511     // XMLComponent methods
 512     //
 513 
 514     /**
 515      * Returns a list of feature identifiers that are recognized by
 516      * this component. This method may return null if no features
 517      * are recognized by this component.
 518      */
 519     public String[] getRecognizedFeatures() {
 520         return (String[]) (RECOGNIZED_FEATURES.clone());
 521     } // getRecognizedFeatures():String[]
 522 
 523     /**
 524      * Sets the state of a feature. This method is called by the component
 525      * manager any time after reset when a feature changes state.
 526      * <p>
 527      * <strong>Note:</strong> Components should silently ignore features
 528      * that do not affect the operation of the component.
 529      *
 530      * @param featureId The feature identifier.
 531      * @param state     The state of the feature.
 532      *
 533      * @throws SAXNotRecognizedException The component should not throw
 534      *                                   this exception.
 535      * @throws SAXNotSupportedException The component should not throw
 536      *                                  this exception.
 537      */
 538     public void setFeature(String featureId, boolean state) throws XMLConfigurationException {
 539     } // setFeature(String,boolean)
 540 
 541     /**
 542      * Returns a list of property identifiers that are recognized by
 543      * this component. This method may return null if no properties
 544      * are recognized by this component.
 545      */
 546     public String[] getRecognizedProperties() {
 547         return (String[]) (RECOGNIZED_PROPERTIES.clone());
 548     } // getRecognizedProperties():String[]
 549 
 550     /**
 551      * Sets the value of a property. This method is called by the component
 552      * manager any time after reset when a property changes value.
 553      * <p>
 554      * <strong>Note:</strong> Components should silently ignore properties
 555      * that do not affect the operation of the component.
 556      *
 557      * @param propertyId The property identifier.
 558      * @param value      The value of the property.
 559      *
 560      * @throws SAXNotRecognizedException The component should not throw
 561      *                                   this exception.
 562      * @throws SAXNotSupportedException The component should not throw
 563      *                                  this exception.
 564      */
 565     public void setProperty(String propertyId, Object value) throws XMLConfigurationException {
 566     } // setProperty(String,Object)
 567 
 568     /**
 569      * Returns the default state for a feature, or null if this
 570      * component does not want to report a default value for this
 571      * feature.
 572      *
 573      * @param featureId The feature identifier.
 574      *
 575      * @since Xerces 2.2.0
 576      */
 577     public Boolean getFeatureDefault(String featureId) {
 578         for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) {
 579             if (RECOGNIZED_FEATURES[i].equals(featureId)) {
 580                 return FEATURE_DEFAULTS[i];
 581             }
 582         }
 583         return null;
 584     } // getFeatureDefault(String):Boolean
 585 
 586     /**
 587      * Returns the default state for a property, or null if this
 588      * component does not want to report a default value for this
 589      * property.
 590      *
 591      * @param propertyId The property identifier.
 592      *
 593      * @since Xerces 2.2.0
 594      */
 595     public Object getPropertyDefault(String propertyId) {
 596         for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) {
 597             if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) {
 598                 return PROPERTY_DEFAULTS[i];
 599             }
 600         }
 601         return null;
 602     } // getPropertyDefault(String):Object
 603 
 604     //
 605     // XMLDocumentSource methods
 606     //
 607 
 608     /** Sets the document handler to receive information about the document. */
 609     public void setDocumentHandler(XMLDocumentHandler documentHandler) {
 610         fDocumentHandler = documentHandler;
 611 
 612         // Init reportWhitespace for this handler
 613         if (documentHandler instanceof XMLParser) {
 614             try {
 615                 reportWhitespace =
 616                     ((XMLParser) documentHandler).getFeature(REPORT_WHITESPACE);
 617             }
 618             catch (Exception e) {
 619                 reportWhitespace = false;
 620             }
 621         }
 622     } // setDocumentHandler(XMLDocumentHandler)
 623 
 624     /** Returns the document handler */
 625     public XMLDocumentHandler getDocumentHandler() {
 626         return fDocumentHandler;
 627     } // setDocumentHandler(XMLDocumentHandler)
 628 
 629     //
 630     // XMLDocumentHandler methods
 631     //
 632 
 633     /** Sets the document source */
 634     public void setDocumentSource(XMLDocumentSource source) {
 635         fDocumentSource = source;
 636     } // setDocumentSource
 637 
 638     /** Returns the document source */
 639     public XMLDocumentSource getDocumentSource() {
 640         return fDocumentSource;
 641     } // getDocumentSource
 642 
 643     /**
 644      * The start of the document.
 645      *
 646      * @param locator The system identifier of the entity if the entity
 647      *                 is external, null otherwise.
 648      * @param encoding The auto-detected IANA encoding name of the entity
 649      *                 stream. This value will be null in those situations
 650      *                 where the entity encoding is not auto-detected (e.g.
 651      *                 internal entities or a document entity that is
 652      *                 parsed from a java.io.Reader).
 653      * @param namespaceContext
 654      *                 The namespace context in effect at the
 655      *                 start of this document.
 656      *                 This object represents the current context.
 657      *                 Implementors of this class are responsible
 658      *                 for copying the namespace bindings from the
 659      *                 the current context (and its parent contexts)
 660      *                 if that information is important.
 661      * @param augs     Additional information that may include infoset augmentations
 662      *
 663      * @throws XNIException Thrown by handler to signal an error.
 664      */
 665     public void startDocument(
 666         XMLLocator locator,
 667         String encoding,
 668         NamespaceContext namespaceContext,
 669         Augmentations augs)
 670         throws XNIException {
 671 
 672         fValidationState.setNamespaceSupport(namespaceContext);
 673         fState4XsiType.setNamespaceSupport(namespaceContext);
 674         fState4ApplyDefault.setNamespaceSupport(namespaceContext);
 675         fLocator = locator;
 676 
 677         handleStartDocument(locator, encoding);
 678         // call handlers
 679         if (fDocumentHandler != null) {
 680             fDocumentHandler.startDocument(locator, encoding, namespaceContext, augs);
 681         }
 682 
 683     } // startDocument(XMLLocator,String)
 684 
 685     /**
 686      * Notifies of the presence of an XMLDecl line in the document. If
 687      * present, this method will be called immediately following the
 688      * startDocument call.
 689      *
 690      * @param version    The XML version.
 691      * @param encoding   The IANA encoding name of the document, or null if
 692      *                   not specified.
 693      * @param standalone The standalone value, or null if not specified.
 694      * @param augs     Additional information that may include infoset augmentations
 695      *
 696      * @throws XNIException Thrown by handler to signal an error.
 697      */
 698     public void xmlDecl(String version, String encoding, String standalone, Augmentations augs)
 699         throws XNIException {
 700 
 701         // call handlers
 702         if (fDocumentHandler != null) {
 703             fDocumentHandler.xmlDecl(version, encoding, standalone, augs);
 704         }
 705 
 706     } // xmlDecl(String,String,String)
 707 
 708     /**
 709      * Notifies of the presence of the DOCTYPE line in the document.
 710      *
 711      * @param rootElement The name of the root element.
 712      * @param publicId    The public identifier if an external DTD or null
 713      *                    if the external DTD is specified using SYSTEM.
 714      * @param systemId    The system identifier if an external DTD, null
 715      *                    otherwise.
 716      * @param augs     Additional information that may include infoset augmentations
 717      *
 718      * @throws XNIException Thrown by handler to signal an error.
 719      */
 720     public void doctypeDecl(
 721         String rootElement,
 722         String publicId,
 723         String systemId,
 724         Augmentations augs)
 725         throws XNIException {
 726 
 727         // call handlers
 728         if (fDocumentHandler != null) {
 729             fDocumentHandler.doctypeDecl(rootElement, publicId, systemId, augs);
 730         }
 731 
 732     } // doctypeDecl(String,String,String)
 733 
 734     /**
 735      * The start of an element.
 736      *
 737      * @param element    The name of the element.
 738      * @param attributes The element attributes.
 739      * @param augs     Additional information that may include infoset augmentations
 740      *
 741      * @throws XNIException Thrown by handler to signal an error.
 742      */
 743     public void startElement(QName element, XMLAttributes attributes, Augmentations augs)
 744         throws XNIException {
 745 
 746         Augmentations modifiedAugs = handleStartElement(element, attributes, augs);
 747         // call handlers
 748         if (fDocumentHandler != null) {
 749             fDocumentHandler.startElement(element, attributes, modifiedAugs);
 750         }
 751 
 752     } // startElement(QName,XMLAttributes, Augmentations)
 753 
 754     /**
 755      * An empty element.
 756      *
 757      * @param element    The name of the element.
 758      * @param attributes The element attributes.
 759      * @param augs     Additional information that may include infoset augmentations
 760      *
 761      * @throws XNIException Thrown by handler to signal an error.
 762      */
 763     public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs)
 764         throws XNIException {
 765 
 766         Augmentations modifiedAugs = handleStartElement(element, attributes, augs);
 767 
 768         // in the case where there is a {value constraint}, and the element
 769         // doesn't have any text content, change emptyElement call to
 770         // start + characters + end
 771         fDefaultValue = null;
 772         // fElementDepth == -2 indicates that the schema validator was removed
 773         // from the pipeline. then we don't need to call handleEndElement.
 774         if (fElementDepth != -2)
 775             modifiedAugs = handleEndElement(element, modifiedAugs);
 776 
 777         // call handlers
 778         if (fDocumentHandler != null) {
 779             if (!fSchemaElementDefault || fDefaultValue == null) {
 780                 fDocumentHandler.emptyElement(element, attributes, modifiedAugs);
 781             } else {
 782                 fDocumentHandler.startElement(element, attributes, modifiedAugs);
 783                 fDocumentHandler.characters(fDefaultValue, null);
 784                 fDocumentHandler.endElement(element, modifiedAugs);
 785             }
 786         }
 787     } // emptyElement(QName,XMLAttributes, Augmentations)
 788 
 789     /**
 790      * Character content.
 791      *
 792      * @param text The content.
 793      * @param augs     Additional information that may include infoset augmentations
 794      *
 795      * @throws XNIException Thrown by handler to signal an error.
 796      */
 797     public void characters(XMLString text, Augmentations augs) throws XNIException {
 798         text = handleCharacters(text);
 799 
 800         if (fSawOnlyWhitespaceInElementContent) {
 801             fSawOnlyWhitespaceInElementContent = false;
 802             if (!reportWhitespace) {
 803                 ignorableWhitespace(text, augs);
 804                 return;
 805             }
 806         }
 807 
 808         // call handlers
 809         if (fDocumentHandler != null) {
 810             if (fNormalizeData && fUnionType) {
 811                 // for union types we can't normalize data
 812                 // thus we only need to send augs information if any;
 813                 // the normalized data for union will be send
 814                 // after normalization is performed (at the endElement())
 815                 if (augs != null)
 816                     fDocumentHandler.characters(fEmptyXMLStr, augs);
 817             } else {
 818                 fDocumentHandler.characters(text, augs);
 819             }
 820         }
 821 
 822     } // characters(XMLString)
 823 
 824     /**
 825      * Ignorable whitespace. For this method to be called, the document
 826      * source must have some way of determining that the text containing
 827      * only whitespace characters should be considered ignorable. For
 828      * example, the validator can determine if a length of whitespace
 829      * characters in the document are ignorable based on the element
 830      * content model.
 831      *
 832      * @param text The ignorable whitespace.
 833      * @param augs     Additional information that may include infoset augmentations
 834      *
 835      * @throws XNIException Thrown by handler to signal an error.
 836      */
 837     public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException {
 838         handleIgnorableWhitespace(text);
 839         // call handlers
 840         if (fDocumentHandler != null) {
 841             fDocumentHandler.ignorableWhitespace(text, augs);
 842         }
 843 
 844     } // ignorableWhitespace(XMLString)
 845 
 846     /**
 847      * The end of an element.
 848      *
 849      * @param element The name of the element.
 850      * @param augs     Additional information that may include infoset augmentations
 851      *
 852      * @throws XNIException Thrown by handler to signal an error.
 853      */
 854     public void endElement(QName element, Augmentations augs) throws XNIException {
 855 
 856         // in the case where there is a {value constraint}, and the element
 857         // doesn't have any text content, add a characters call.
 858         fDefaultValue = null;
 859         Augmentations modifiedAugs = handleEndElement(element, augs);
 860         // call handlers
 861         if (fDocumentHandler != null) {
 862             if (!fSchemaElementDefault || fDefaultValue == null) {
 863                 fDocumentHandler.endElement(element, modifiedAugs);
 864             } else {
 865                 fDocumentHandler.characters(fDefaultValue, null);
 866                 fDocumentHandler.endElement(element, modifiedAugs);
 867             }
 868         }
 869     } // endElement(QName, Augmentations)
 870 
 871     /**
 872     * The start of a CDATA section.
 873     *
 874     * @param augs     Additional information that may include infoset augmentations
 875     *
 876     * @throws XNIException Thrown by handler to signal an error.
 877     */
 878     public void startCDATA(Augmentations augs) throws XNIException {
 879 
 880         // REVISIT: what should we do here if schema normalization is on??
 881         fInCDATA = true;
 882         // call handlers
 883         if (fDocumentHandler != null) {
 884             fDocumentHandler.startCDATA(augs);
 885         }
 886 
 887     } // startCDATA()
 888 
 889     /**
 890      * The end of a CDATA section.
 891      *
 892      * @param augs     Additional information that may include infoset augmentations
 893      *
 894      * @throws XNIException Thrown by handler to signal an error.
 895      */
 896     public void endCDATA(Augmentations augs) throws XNIException {
 897 
 898         // call handlers
 899         fInCDATA = false;
 900         if (fDocumentHandler != null) {
 901             fDocumentHandler.endCDATA(augs);
 902         }
 903 
 904     } // endCDATA()
 905 
 906     /**
 907      * The end of the document.
 908      *
 909      * @param augs     Additional information that may include infoset augmentations
 910      *
 911      * @throws XNIException Thrown by handler to signal an error.
 912      */
 913     public void endDocument(Augmentations augs) throws XNIException {
 914 
 915         handleEndDocument();
 916 
 917         // call handlers
 918         if (fDocumentHandler != null) {
 919             fDocumentHandler.endDocument(augs);
 920         }
 921         fLocator = null;
 922 
 923     } // endDocument(Augmentations)
 924 
 925     //
 926     // DOMRevalidationHandler methods
 927     //
 928 
 929 
 930 
 931 
 932 
 933     public boolean characterData(String data, Augmentations augs) {
 934 
 935         fSawText = fSawText || data.length() > 0;
 936 
 937         // REVISIT: this methods basically duplicates implementation of
 938         //          handleCharacters(). We should be able to reuse some code
 939 
 940         // if whitespace == -1 skip normalization, because it is a complexType
 941         // or a union type.
 942         if (fNormalizeData && fWhiteSpace != -1 && fWhiteSpace != XSSimpleType.WS_PRESERVE) {
 943             // normalize data
 944             normalizeWhitespace(data, fWhiteSpace == XSSimpleType.WS_COLLAPSE);
 945             fBuffer.append(fNormalizedStr.ch, fNormalizedStr.offset, fNormalizedStr.length);
 946         } else {
 947             if (fAppendBuffer)
 948                 fBuffer.append(data);
 949         }
 950 
 951         // When it's a complex type with element-only content, we need to
 952         // find out whether the content contains any non-whitespace character.
 953         boolean allWhiteSpace = true;
 954         if (fCurrentType != null
 955             && fCurrentType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) {
 956             XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType;
 957             if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_ELEMENT) {
 958                 // data outside of element content
 959                 for (int i = 0; i < data.length(); i++) {
 960                     if (!XMLChar.isSpace(data.charAt(i))) {
 961                         allWhiteSpace = false;
 962                         fSawCharacters = true;
 963                         break;
 964                     }
 965                 }
 966             }
 967         }
 968 
 969         return allWhiteSpace;
 970     }
 971 
 972     public void elementDefault(String data) {
 973         // no-op
 974     }
 975 
 976     //
 977     // XMLDocumentHandler and XMLDTDHandler methods
 978     //
 979 
 980     /**
 981      * This method notifies the start of a general entity.
 982      * <p>
 983      * <strong>Note:</strong> This method is not called for entity references
 984      * appearing as part of attribute values.
 985      *
 986      * @param name     The name of the general entity.
 987      * @param identifier The resource identifier.
 988      * @param encoding The auto-detected IANA encoding name of the entity
 989      *                 stream. This value will be null in those situations
 990      *                 where the entity encoding is not auto-detected (e.g.
 991      *                 internal entities or a document entity that is
 992      *                 parsed from a java.io.Reader).
 993      * @param augs     Additional information that may include infoset augmentations
 994      *
 995      * @exception XNIException Thrown by handler to signal an error.
 996      */
 997     public void startGeneralEntity(
 998         String name,
 999         XMLResourceIdentifier identifier,
1000         String encoding,
1001         Augmentations augs)
1002         throws XNIException {
1003 
1004         // REVISIT: what should happen if normalize_data_ is on??
1005         fEntityRef = true;
1006         // call handlers
1007         if (fDocumentHandler != null) {
1008             fDocumentHandler.startGeneralEntity(name, identifier, encoding, augs);
1009         }
1010 
1011     } // startEntity(String,String,String,String,String)
1012 
1013     /**
1014      * Notifies of the presence of a TextDecl line in an entity. If present,
1015      * this method will be called immediately following the startEntity call.
1016      * <p>
1017      * <strong>Note:</strong> This method will never be called for the
1018      * document entity; it is only called for external general entities
1019      * referenced in document content.
1020      * <p>
1021      * <strong>Note:</strong> This method is not called for entity references
1022      * appearing as part of attribute values.
1023      *
1024      * @param version  The XML version, or null if not specified.
1025      * @param encoding The IANA encoding name of the entity.
1026      * @param augs     Additional information that may include infoset augmentations
1027      *
1028      * @throws XNIException Thrown by handler to signal an error.
1029      */
1030     public void textDecl(String version, String encoding, Augmentations augs) throws XNIException {
1031 
1032         // call handlers
1033         if (fDocumentHandler != null) {
1034             fDocumentHandler.textDecl(version, encoding, augs);
1035         }
1036 
1037     } // textDecl(String,String)
1038 
1039     /**
1040      * A comment.
1041      *
1042      * @param text The text in the comment.
1043      * @param augs     Additional information that may include infoset augmentations
1044      *
1045      * @throws XNIException Thrown by application to signal an error.
1046      */
1047     public void comment(XMLString text, Augmentations augs) throws XNIException {
1048 
1049         // call handlers
1050         if (fDocumentHandler != null) {
1051             fDocumentHandler.comment(text, augs);
1052         }
1053 
1054     } // comment(XMLString)
1055 
1056     /**
1057      * A processing instruction. Processing instructions consist of a
1058      * target name and, optionally, text data. The data is only meaningful
1059      * to the application.
1060      * <p>
1061      * Typically, a processing instruction's data will contain a series
1062      * of pseudo-attributes. These pseudo-attributes follow the form of
1063      * element attributes but are <strong>not</strong> parsed or presented
1064      * to the application as anything other than text. The application is
1065      * responsible for parsing the data.
1066      *
1067      * @param target The target.
1068      * @param data   The data or null if none specified.
1069      * @param augs     Additional information that may include infoset augmentations
1070      *
1071      * @throws XNIException Thrown by handler to signal an error.
1072      */
1073     public void processingInstruction(String target, XMLString data, Augmentations augs)
1074         throws XNIException {
1075 
1076         // call handlers
1077         if (fDocumentHandler != null) {
1078             fDocumentHandler.processingInstruction(target, data, augs);
1079         }
1080 
1081     } // processingInstruction(String,XMLString)
1082 
1083     /**
1084      * This method notifies the end of a general entity.
1085      * <p>
1086      * <strong>Note:</strong> This method is not called for entity references
1087      * appearing as part of attribute values.
1088      *
1089      * @param name   The name of the entity.
1090      * @param augs   Additional information that may include infoset augmentations
1091      *
1092      * @exception XNIException
1093      *                   Thrown by handler to signal an error.
1094      */
1095     public void endGeneralEntity(String name, Augmentations augs) throws XNIException {
1096 
1097         // call handlers
1098         fEntityRef = false;
1099         if (fDocumentHandler != null) {
1100             fDocumentHandler.endGeneralEntity(name, augs);
1101         }
1102 
1103     } // endEntity(String)
1104 
1105     // constants
1106 
1107     static final int INITIAL_STACK_SIZE = 8;
1108     static final int INC_STACK_SIZE = 8;
1109 
1110     //
1111     // Data
1112     //
1113 
1114     // Schema Normalization
1115 
1116     private static final boolean DEBUG_NORMALIZATION = false;
1117     // temporary empty string buffer.
1118     private final XMLString fEmptyXMLStr = new XMLString(null, 0, -1);
1119     // temporary character buffer, and empty string buffer.
1120     private static final int BUFFER_SIZE = 20;
1121     private final XMLString fNormalizedStr = new XMLString();
1122     private boolean fFirstChunk = true;
1123     // got first chunk in characters() (SAX)
1124     private boolean fTrailing = false; // Previous chunk had a trailing space
1125     private short fWhiteSpace = -1; //whiteSpace: preserve/replace/collapse
1126     private boolean fUnionType = false;
1127 
1128     /** Schema grammar resolver. */
1129     private final XSGrammarBucket fGrammarBucket = new XSGrammarBucket();
1130     private final SubstitutionGroupHandler fSubGroupHandler = new SubstitutionGroupHandler(fGrammarBucket);
1131 
1132     /** the DV usd to convert xsi:type to a QName */
1133     // REVISIT: in new simple type design, make things in DVs static,
1134     //          so that we can QNameDV.getCompiledForm()
1135     private final XSSimpleType fQNameDV =
1136         (XSSimpleType) SchemaGrammar.SG_SchemaNS.getGlobalTypeDecl(SchemaSymbols.ATTVAL_QNAME);
1137 
1138     private final CMNodeFactory nodeFactory = new CMNodeFactory();
1139     /** used to build content models */
1140     // REVISIT: create decl pool, and pass it to each traversers
1141     private final CMBuilder fCMBuilder = new CMBuilder(nodeFactory);
1142 
1143     // Schema grammar loader
1144     private final XMLSchemaLoader fSchemaLoader =
1145         new XMLSchemaLoader(
1146                 fXSIErrorReporter.fErrorReporter,
1147                 fGrammarBucket,
1148                 fSubGroupHandler,
1149                 fCMBuilder);
1150 
1151     // state
1152 
1153     /** String representation of the validation root. */
1154     // REVISIT: what do we store here? QName, XPATH, some ID? use rawname now.
1155     private String fValidationRoot;
1156 
1157     /** Skip validation: anything below this level should be skipped */
1158     private int fSkipValidationDepth;
1159 
1160     /** anything above this level has validation_attempted != full */
1161     private int fNFullValidationDepth;
1162 
1163     /** anything above this level has validation_attempted != none */
1164     private int fNNoneValidationDepth;
1165 
1166     /** Element depth: -2: validator not in pipeline; >= -1 current depth. */
1167     private int fElementDepth;
1168 
1169     /** Seen sub elements. */
1170     private boolean fSubElement;
1171 
1172     /** Seen sub elements stack. */
1173     private boolean[] fSubElementStack = new boolean[INITIAL_STACK_SIZE];
1174 
1175     /** Current element declaration. */
1176     private XSElementDecl fCurrentElemDecl;
1177 
1178     /** Element decl stack. */
1179     private XSElementDecl[] fElemDeclStack = new XSElementDecl[INITIAL_STACK_SIZE];
1180 
1181     /** nil value of the current element */
1182     private boolean fNil;
1183 
1184     /** nil value stack */
1185     private boolean[] fNilStack = new boolean[INITIAL_STACK_SIZE];
1186 
1187     /** notation value of the current element */
1188     private XSNotationDecl fNotation;
1189 
1190     /** notation stack */
1191     private XSNotationDecl[] fNotationStack = new XSNotationDecl[INITIAL_STACK_SIZE];
1192 
1193     /** Current type. */
1194     private XSTypeDefinition fCurrentType;
1195 
1196     /** type stack. */
1197     private XSTypeDefinition[] fTypeStack = new XSTypeDefinition[INITIAL_STACK_SIZE];
1198 
1199     /** Current content model. */
1200     private XSCMValidator fCurrentCM;
1201 
1202     /** Content model stack. */
1203     private XSCMValidator[] fCMStack = new XSCMValidator[INITIAL_STACK_SIZE];
1204 
1205     /** the current state of the current content model */
1206     private int[] fCurrCMState;
1207 
1208     /** stack to hold content model states */
1209     private int[][] fCMStateStack = new int[INITIAL_STACK_SIZE][];
1210 
1211     /** whether the curret element is strictly assessed */
1212     private boolean fStrictAssess = true;
1213 
1214     /** strict assess stack */
1215     private boolean[] fStrictAssessStack = new boolean[INITIAL_STACK_SIZE];
1216 
1217     /** Temporary string buffers. */
1218     private final StringBuffer fBuffer = new StringBuffer();
1219 
1220     /** Whether need to append characters to fBuffer */
1221     private boolean fAppendBuffer = true;
1222 
1223     /** Did we see any character data? */
1224     private boolean fSawText = false;
1225 
1226     /** stack to record if we saw character data */
1227     private boolean[] fSawTextStack = new boolean[INITIAL_STACK_SIZE];
1228 
1229     /** Did we see non-whitespace character data? */
1230     private boolean fSawCharacters = false;
1231 
1232     /** Stack to record if we saw character data outside of element content*/
1233     private boolean[] fStringContent = new boolean[INITIAL_STACK_SIZE];
1234 
1235     /** temporary qname */
1236     private final QName fTempQName = new QName();
1237 
1238     /** temporary validated info */
1239     private ValidatedInfo fValidatedInfo = new ValidatedInfo();
1240 
1241     // used to validate default/fixed values against xsi:type
1242     // only need to check facets, so we set extraChecking to false (in reset)
1243     private ValidationState fState4XsiType = new ValidationState();
1244 
1245     // used to apply default/fixed values
1246     // only need to check id/idref/entity, so we set checkFacets to false
1247     private ValidationState fState4ApplyDefault = new ValidationState();
1248 
1249     // identity constraint information
1250 
1251     /**
1252      * Stack of active XPath matchers for identity constraints. All
1253      * active XPath matchers are notified of startElement
1254      * and endElement callbacks in order to perform their matches.
1255      * <p>
1256      * For each element with identity constraints, the selector of
1257      * each identity constraint is activated. When the selector matches
1258      * its XPath, then all the fields of the identity constraint are
1259      * activated.
1260      * <p>
1261      * <strong>Note:</strong> Once the activation scope is left, the
1262      * XPath matchers are automatically removed from the stack of
1263      * active matchers and no longer receive callbacks.
1264      */
1265     protected XPathMatcherStack fMatcherStack = new XPathMatcherStack();
1266 
1267     /** Cache of value stores for identity constraint fields. */
1268     protected ValueStoreCache fValueStoreCache = new ValueStoreCache();
1269 
1270     //
1271     // Constructors
1272     //
1273 
1274     /** Default constructor. */
1275     public XMLSchemaValidator() {
1276         fState4XsiType.setExtraChecking(false);
1277         fState4ApplyDefault.setFacetChecking(false);
1278 
1279     } // <init>()
1280 
1281     /*
1282      * Resets the component. The component can query the component manager
1283      * about any features and properties that affect the operation of the
1284      * component.
1285      *
1286      * @param componentManager The component manager.
1287      *
1288      * @throws SAXException Thrown by component on finitialization error.
1289      *                      For example, if a feature or property is
1290      *                      required for the operation of the component, the
1291      *                      component manager may throw a
1292      *                      SAXNotRecognizedException or a
1293      *                      SAXNotSupportedException.
1294      */
1295     public void reset(XMLComponentManager componentManager) throws XMLConfigurationException {
1296 
1297 
1298         fIdConstraint = false;
1299         //reset XSDDescription
1300         fLocationPairs.clear();
1301 
1302         // cleanup id table
1303         fValidationState.resetIDTables();
1304 
1305         //pass the component manager to the factory..
1306         nodeFactory.reset(componentManager);
1307 
1308         // reset schema loader
1309         fSchemaLoader.reset(componentManager);
1310 
1311         // initialize state
1312         fCurrentElemDecl = null;
1313         fCurrentCM = null;
1314         fCurrCMState = null;
1315         fSkipValidationDepth = -1;
1316         fNFullValidationDepth = -1;
1317         fNNoneValidationDepth = -1;
1318         fElementDepth = -1;
1319         fSubElement = false;
1320         fSchemaDynamicValidation = false;
1321 
1322         // datatype normalization
1323         fEntityRef = false;
1324         fInCDATA = false;
1325 
1326         fMatcherStack.clear();
1327 
1328         if (!fMayMatchFieldMap.isEmpty()) {
1329             // should only clear this if the last schema had identity constraints.
1330             fMayMatchFieldMap.clear();
1331         }
1332 
1333         // get error reporter
1334         fXSIErrorReporter.reset((XMLErrorReporter) componentManager.getProperty(ERROR_REPORTER));
1335 
1336         boolean parser_settings = componentManager.getFeature(PARSER_SETTINGS, true);
1337 
1338         if (!parser_settings){
1339             // parser settings have not been changed
1340             fValidationManager.addValidationState(fValidationState);
1341             // Re-parse external schema location properties.
1342             XMLSchemaLoader.processExternalHints(
1343                 fExternalSchemas,
1344                 fExternalNoNamespaceSchema,
1345                 fLocationPairs,
1346                 fXSIErrorReporter.fErrorReporter);
1347             return;
1348         }
1349 
1350 
1351         // get symbol table. if it's a new one, add symbols to it.
1352         SymbolTable symbolTable = (SymbolTable) componentManager.getProperty(SYMBOL_TABLE);
1353         if (symbolTable != fSymbolTable) {
1354             fSymbolTable = symbolTable;
1355         }
1356 
1357         fNamespaceGrowth = componentManager.getFeature(NAMESPACE_GROWTH, false);
1358         fDynamicValidation = componentManager.getFeature(DYNAMIC_VALIDATION, false);
1359 
1360         if (fDynamicValidation) {
1361             fDoValidation = true;
1362         } else {
1363             fDoValidation = componentManager.getFeature(VALIDATION, false);
1364         }
1365 
1366         if (fDoValidation) {
1367             fDoValidation |= componentManager.getFeature(XMLSchemaValidator.SCHEMA_VALIDATION, false);
1368         }
1369 
1370         fFullChecking = componentManager.getFeature(SCHEMA_FULL_CHECKING, false);
1371         fNormalizeData = componentManager.getFeature(NORMALIZE_DATA, false);
1372         fSchemaElementDefault = componentManager.getFeature(SCHEMA_ELEMENT_DEFAULT, false);
1373 
1374         fAugPSVI = componentManager.getFeature(SCHEMA_AUGMENT_PSVI, true);
1375 
1376         fSchemaType =
1377                 (String) componentManager.getProperty(
1378                     Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_LANGUAGE, null);
1379 
1380         fUseGrammarPoolOnly = componentManager.getFeature(USE_GRAMMAR_POOL_ONLY, false);
1381 
1382         fEntityResolver = (XMLEntityResolver) componentManager.getProperty(ENTITY_MANAGER);
1383 
1384         fValidationManager = (ValidationManager) componentManager.getProperty(VALIDATION_MANAGER);
1385         fValidationManager.addValidationState(fValidationState);
1386         fValidationState.setSymbolTable(fSymbolTable);
1387 
1388 
1389         // get schema location properties
1390         try {
1391             fExternalSchemas = (String) componentManager.getProperty(SCHEMA_LOCATION);
1392             fExternalNoNamespaceSchema =
1393                 (String) componentManager.getProperty(SCHEMA_NONS_LOCATION);
1394         } catch (XMLConfigurationException e) {
1395             fExternalSchemas = null;
1396             fExternalNoNamespaceSchema = null;
1397         }
1398 
1399         // store the external schema locations. they are set when reset is called,
1400         // so any other schemaLocation declaration for the same namespace will be
1401         // effectively ignored. becuase we choose to take first location hint
1402         // available for a particular namespace.
1403         XMLSchemaLoader.processExternalHints(
1404             fExternalSchemas,
1405             fExternalNoNamespaceSchema,
1406             fLocationPairs,
1407             fXSIErrorReporter.fErrorReporter);
1408 
1409         fJaxpSchemaSource = componentManager.getProperty(JAXP_SCHEMA_SOURCE, null);
1410 
1411         // clear grammars, and put the one for schema namespace there
1412         fGrammarPool = (XMLGrammarPool) componentManager.getProperty(XMLGRAMMAR_POOL, null);
1413 
1414         fState4XsiType.setSymbolTable(symbolTable);
1415         fState4ApplyDefault.setSymbolTable(symbolTable);
1416 
1417     } // reset(XMLComponentManager)
1418 
1419     //
1420     // FieldActivator methods
1421     //
1422 
1423     /**
1424      * Start the value scope for the specified identity constraint. This
1425      * method is called when the selector matches in order to initialize
1426      * the value store.
1427      *
1428      * @param identityConstraint The identity constraint.
1429      */
1430     public void startValueScopeFor(IdentityConstraint identityConstraint, int initialDepth) {
1431 
1432         ValueStoreBase valueStore =
1433             fValueStoreCache.getValueStoreFor(identityConstraint, initialDepth);
1434         valueStore.startValueScope();
1435 
1436     } // startValueScopeFor(IdentityConstraint identityConstraint)
1437 
1438     /**
1439      * Request to activate the specified field. This method returns the
1440      * matcher for the field.
1441      *
1442      * @param field The field to activate.
1443      */
1444     public XPathMatcher activateField(Field field, int initialDepth) {
1445         ValueStore valueStore =
1446             fValueStoreCache.getValueStoreFor(field.getIdentityConstraint(), initialDepth);
1447         setMayMatch(field, Boolean.TRUE);
1448         XPathMatcher matcher = field.createMatcher(this, valueStore);
1449         fMatcherStack.addMatcher(matcher);
1450         matcher.startDocumentFragment();
1451         return matcher;
1452     } // activateField(Field):XPathMatcher
1453 
1454     /**
1455      * Ends the value scope for the specified identity constraint.
1456      *
1457      * @param identityConstraint The identity constraint.
1458      */
1459     public void endValueScopeFor(IdentityConstraint identityConstraint, int initialDepth) {
1460 
1461         ValueStoreBase valueStore =
1462             fValueStoreCache.getValueStoreFor(identityConstraint, initialDepth);
1463         valueStore.endValueScope();
1464 
1465     } // endValueScopeFor(IdentityConstraint)
1466 
1467     /**
1468      * Sets whether the given field is permitted to match a value.
1469      * This should be used to catch instance documents that try
1470      * and match a field several times in the same scope.
1471      *
1472      * @param field The field that may be permitted to be matched.
1473      * @param state Boolean indiciating whether the field may be matched.
1474      */
1475     public void setMayMatch(Field field, Boolean state) {
1476         fMayMatchFieldMap.put(field, state);
1477     } // setMayMatch(Field, Boolean)
1478 
1479     /**
1480      * Returns whether the given field is permitted to match a value.
1481      *
1482      * @param field The field that may be permitted to be matched.
1483      * @return Boolean indicating whether the field may be matched.
1484      */
1485     public Boolean mayMatch(Field field) {
1486         return (Boolean) fMayMatchFieldMap.get(field);
1487     } // mayMatch(Field):Boolean
1488 
1489     // a utility method for Identity constraints
1490     private void activateSelectorFor(IdentityConstraint ic) {
1491         Selector selector = ic.getSelector();
1492         FieldActivator activator = this;
1493         if (selector == null)
1494             return;
1495         XPathMatcher matcher = selector.createMatcher(activator, fElementDepth);
1496         fMatcherStack.addMatcher(matcher);
1497         matcher.startDocumentFragment();
1498     }
1499 
1500     //
1501     // Protected methods
1502     //
1503 
1504     /** ensure element stack capacity */
1505     void ensureStackCapacity() {
1506 
1507         if (fElementDepth == fElemDeclStack.length) {
1508             int newSize = fElementDepth + INC_STACK_SIZE;
1509             boolean[] newArrayB = new boolean[newSize];
1510             System.arraycopy(fSubElementStack, 0, newArrayB, 0, fElementDepth);
1511             fSubElementStack = newArrayB;
1512 
1513             XSElementDecl[] newArrayE = new XSElementDecl[newSize];
1514             System.arraycopy(fElemDeclStack, 0, newArrayE, 0, fElementDepth);
1515             fElemDeclStack = newArrayE;
1516 
1517             newArrayB = new boolean[newSize];
1518             System.arraycopy(fNilStack, 0, newArrayB, 0, fElementDepth);
1519             fNilStack = newArrayB;
1520 
1521             XSNotationDecl[] newArrayN = new XSNotationDecl[newSize];
1522             System.arraycopy(fNotationStack, 0, newArrayN, 0, fElementDepth);
1523             fNotationStack = newArrayN;
1524 
1525             XSTypeDefinition[] newArrayT = new XSTypeDefinition[newSize];
1526             System.arraycopy(fTypeStack, 0, newArrayT, 0, fElementDepth);
1527             fTypeStack = newArrayT;
1528 
1529             XSCMValidator[] newArrayC = new XSCMValidator[newSize];
1530             System.arraycopy(fCMStack, 0, newArrayC, 0, fElementDepth);
1531             fCMStack = newArrayC;
1532 
1533             newArrayB = new boolean[newSize];
1534             System.arraycopy(fSawTextStack, 0, newArrayB, 0, fElementDepth);
1535             fSawTextStack = newArrayB;
1536 
1537             newArrayB = new boolean[newSize];
1538             System.arraycopy(fStringContent, 0, newArrayB, 0, fElementDepth);
1539             fStringContent = newArrayB;
1540 
1541             newArrayB = new boolean[newSize];
1542             System.arraycopy(fStrictAssessStack, 0, newArrayB, 0, fElementDepth);
1543             fStrictAssessStack = newArrayB;
1544 
1545             int[][] newArrayIA = new int[newSize][];
1546             System.arraycopy(fCMStateStack, 0, newArrayIA, 0, fElementDepth);
1547             fCMStateStack = newArrayIA;
1548         }
1549 
1550     } // ensureStackCapacity
1551 
1552     // handle start document
1553     void handleStartDocument(XMLLocator locator, String encoding) {
1554         fValueStoreCache.startDocument();
1555         if (fAugPSVI) {
1556             fCurrentPSVI.fGrammars = null;
1557             fCurrentPSVI.fSchemaInformation = null;
1558         }
1559     } // handleStartDocument(XMLLocator,String)
1560 
1561     void handleEndDocument() {
1562         fValueStoreCache.endDocument();
1563     } // handleEndDocument()
1564 
1565     // handle character contents
1566     // returns the normalized string if possible, otherwise the original string
1567     XMLString handleCharacters(XMLString text) {
1568 
1569         if (fSkipValidationDepth >= 0)
1570             return text;
1571 
1572         fSawText = fSawText || text.length > 0;
1573 
1574         // Note: data in EntityRef and CDATA is normalized as well
1575         // if whitespace == -1 skip normalization, because it is a complexType
1576         // or a union type.
1577         if (fNormalizeData && fWhiteSpace != -1 && fWhiteSpace != XSSimpleType.WS_PRESERVE) {
1578             // normalize data
1579             normalizeWhitespace(text, fWhiteSpace == XSSimpleType.WS_COLLAPSE);
1580             text = fNormalizedStr;
1581         }
1582         if (fAppendBuffer)
1583             fBuffer.append(text.ch, text.offset, text.length);
1584 
1585         // When it's a complex type with element-only content, we need to
1586         // find out whether the content contains any non-whitespace character.
1587         fSawOnlyWhitespaceInElementContent = false;
1588         if (fCurrentType != null
1589             && fCurrentType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) {
1590             XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType;
1591             if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_ELEMENT) {
1592                 // data outside of element content
1593                 for (int i = text.offset; i < text.offset + text.length; i++) {
1594                     if (!XMLChar.isSpace(text.ch[i])) {
1595                         fSawCharacters = true;
1596                         break;
1597                     }
1598                     fSawOnlyWhitespaceInElementContent = !fSawCharacters;
1599                 }
1600             }
1601         }
1602 
1603         return text;
1604     } // handleCharacters(XMLString)
1605 
1606     /**
1607      * Normalize whitespace in an XMLString according to the rules defined
1608      * in XML Schema specifications.
1609      * @param value    The string to normalize.
1610      * @param collapse replace or collapse
1611      */
1612     private void normalizeWhitespace(XMLString value, boolean collapse) {
1613         boolean skipSpace = collapse;
1614         boolean sawNonWS = false;
1615         boolean leading = false;
1616         boolean trailing = false;
1617         char c;
1618         int size = value.offset + value.length;
1619 
1620         // ensure the ch array is big enough
1621         if (fNormalizedStr.ch == null || fNormalizedStr.ch.length < value.length + 1) {
1622             fNormalizedStr.ch = new char[value.length + 1];
1623         }
1624         // don't include the leading ' ' for now. might include it later.
1625         fNormalizedStr.offset = 1;
1626         fNormalizedStr.length = 1;
1627 
1628         for (int i = value.offset; i < size; i++) {
1629             c = value.ch[i];
1630             if (XMLChar.isSpace(c)) {
1631                 if (!skipSpace) {
1632                     // take the first whitespace as a space and skip the others
1633                     fNormalizedStr.ch[fNormalizedStr.length++] = ' ';
1634                     skipSpace = collapse;
1635                 }
1636                 if (!sawNonWS) {
1637                     // this is a leading whitespace, record it
1638                     leading = true;
1639                 }
1640             } else {
1641                 fNormalizedStr.ch[fNormalizedStr.length++] = c;
1642                 skipSpace = false;
1643                 sawNonWS = true;
1644             }
1645         }
1646         if (skipSpace) {
1647             if (fNormalizedStr.length > 1) {
1648                 // if we finished on a space trim it but also record it
1649                 fNormalizedStr.length--;
1650                 trailing = true;
1651             } else if (leading && !fFirstChunk) {
1652                 // if all we had was whitespace we skipped record it as
1653                 // trailing whitespace as well
1654                 trailing = true;
1655             }
1656         }
1657 
1658         if (fNormalizedStr.length > 1) {
1659             if (!fFirstChunk && (fWhiteSpace == XSSimpleType.WS_COLLAPSE)) {
1660                 if (fTrailing) {
1661                     // previous chunk ended on whitespace
1662                     // insert whitespace
1663                     fNormalizedStr.offset = 0;
1664                     fNormalizedStr.ch[0] = ' ';
1665                 } else if (leading) {
1666                     // previous chunk ended on character,
1667                     // this chunk starts with whitespace
1668                     fNormalizedStr.offset = 0;
1669                     fNormalizedStr.ch[0] = ' ';
1670                 }
1671             }
1672         }
1673 
1674         // The length includes the leading ' '. Now removing it.
1675         fNormalizedStr.length -= fNormalizedStr.offset;
1676 
1677         fTrailing = trailing;
1678 
1679         if (trailing || sawNonWS)
1680             fFirstChunk = false;
1681     }
1682 
1683     private void normalizeWhitespace(String value, boolean collapse) {
1684         boolean skipSpace = collapse;
1685         char c;
1686         int size = value.length();
1687 
1688         // ensure the ch array is big enough
1689         if (fNormalizedStr.ch == null || fNormalizedStr.ch.length < size) {
1690             fNormalizedStr.ch = new char[size];
1691         }
1692         fNormalizedStr.offset = 0;
1693         fNormalizedStr.length = 0;
1694 
1695         for (int i = 0; i < size; i++) {
1696             c = value.charAt(i);
1697             if (XMLChar.isSpace(c)) {
1698                 if (!skipSpace) {
1699                     // take the first whitespace as a space and skip the others
1700                     fNormalizedStr.ch[fNormalizedStr.length++] = ' ';
1701                     skipSpace = collapse;
1702                 }
1703             } else {
1704                 fNormalizedStr.ch[fNormalizedStr.length++] = c;
1705                 skipSpace = false;
1706             }
1707         }
1708         if (skipSpace) {
1709             if (fNormalizedStr.length != 0)
1710                 // if we finished on a space trim it but also record it
1711                 fNormalizedStr.length--;
1712         }
1713     }
1714 
1715     // handle ignorable whitespace
1716     void handleIgnorableWhitespace(XMLString text) {
1717 
1718         if (fSkipValidationDepth >= 0)
1719             return;
1720 
1721         // REVISIT: the same process needs to be performed as handleCharacters.
1722         // only it's simpler here: we know all characters are whitespaces.
1723 
1724     } // handleIgnorableWhitespace(XMLString)
1725 
1726     /** Handle element. */
1727     Augmentations handleStartElement(QName element, XMLAttributes attributes, Augmentations augs) {
1728 
1729         if (DEBUG) {
1730             System.out.println("==>handleStartElement: " + element);
1731         }
1732 
1733         // root element
1734         if (fElementDepth == -1 && fValidationManager.isGrammarFound()) {
1735             if (fSchemaType == null) {
1736                 // schemaType is not specified
1737                 // if a DTD grammar is found, we do the same thing as Dynamic:
1738                 // if a schema grammar is found, validation is performed;
1739                 // otherwise, skip the whole document.
1740                 fSchemaDynamicValidation = true;
1741             } else {
1742                 // [1] Either schemaType is DTD, and in this case validate/schema is turned off
1743                 // [2] Validating against XML Schemas only
1744                 //   [a] dynamic validation is false: report error if SchemaGrammar is not found
1745                 //   [b] dynamic validation is true: if grammar is not found ignore.
1746             }
1747 
1748         }
1749 
1750         // get xsi:schemaLocation and xsi:noNamespaceSchemaLocation attributes,
1751         // parse them to get the grammars
1752 
1753         String sLocation =
1754             attributes.getValue(SchemaSymbols.URI_XSI, SchemaSymbols.XSI_SCHEMALOCATION);
1755         String nsLocation =
1756             attributes.getValue(SchemaSymbols.URI_XSI, SchemaSymbols.XSI_NONAMESPACESCHEMALOCATION);
1757         //store the location hints..  we need to do it so that we can defer the loading of grammar until
1758         //there is a reference to a component from that namespace. To provide location hints to the
1759         //application for a namespace
1760         storeLocations(sLocation, nsLocation);
1761 
1762         // if we are in the content of "skip", then just skip this element
1763         // REVISIT:  is this the correct behaviour for ID constraints?  -NG
1764         if (fSkipValidationDepth >= 0) {
1765             fElementDepth++;
1766             if (fAugPSVI)
1767                 augs = getEmptyAugs(augs);
1768             return augs;
1769         }
1770 
1771         //try to find schema grammar by different means..
1772         SchemaGrammar sGrammar =
1773             findSchemaGrammar(
1774                 XSDDescription.CONTEXT_ELEMENT,
1775                 element.uri,
1776                 null,
1777                 element,
1778                 attributes);
1779 
1780         // if we are not skipping this element, and there is a content model,
1781         // we try to find the corresponding decl object for this element.
1782         // the reason we move this part of code here is to make sure the
1783         // error reported here (if any) is stored within the parent element's
1784         // context, instead of that of the current element.
1785         Object decl = null;
1786         if (fCurrentCM != null) {
1787             decl = fCurrentCM.oneTransition(element, fCurrCMState, fSubGroupHandler);
1788             // it could be an element decl or a wildcard decl
1789             if (fCurrCMState[0] == XSCMValidator.FIRST_ERROR) {
1790                 XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType;
1791                 //REVISIT: is it the only case we will have particle = null?
1792                 Vector next;
1793                 if (ctype.fParticle != null
1794                     && (next = fCurrentCM.whatCanGoHere(fCurrCMState)).size() > 0) {
1795                     String expected = expectedStr(next);
1796                     reportSchemaError(
1797                         "cvc-complex-type.2.4.a",
1798                         new Object[] { element.rawname, expected });
1799                 } else {
1800                     reportSchemaError("cvc-complex-type.2.4.d", new Object[] { element.rawname });
1801                 }
1802             }
1803         }
1804 
1805         // if it's not the root element, we push the current states in the stacks
1806         if (fElementDepth != -1) {
1807             ensureStackCapacity();
1808             fSubElementStack[fElementDepth] = true;
1809             fSubElement = false;
1810             fElemDeclStack[fElementDepth] = fCurrentElemDecl;
1811             fNilStack[fElementDepth] = fNil;
1812             fNotationStack[fElementDepth] = fNotation;
1813             fTypeStack[fElementDepth] = fCurrentType;
1814             fStrictAssessStack[fElementDepth] = fStrictAssess;
1815             fCMStack[fElementDepth] = fCurrentCM;
1816             fCMStateStack[fElementDepth] = fCurrCMState;
1817             fSawTextStack[fElementDepth] = fSawText;
1818             fStringContent[fElementDepth] = fSawCharacters;
1819         }
1820 
1821         // increase the element depth after we've saved
1822         // all states for the parent element
1823         fElementDepth++;
1824         fCurrentElemDecl = null;
1825         XSWildcardDecl wildcard = null;
1826         fCurrentType = null;
1827         fStrictAssess = true;
1828         fNil = false;
1829         fNotation = null;
1830 
1831         // and the buffer to hold the value of the element
1832         fBuffer.setLength(0);
1833         fSawText = false;
1834         fSawCharacters = false;
1835 
1836         // check what kind of declaration the "decl" from
1837         // oneTransition() maps to
1838         if (decl != null) {
1839             if (decl instanceof XSElementDecl) {
1840                 fCurrentElemDecl = (XSElementDecl) decl;
1841             } else {
1842                 wildcard = (XSWildcardDecl) decl;
1843             }
1844         }
1845 
1846         // if the wildcard is skip, then return
1847         if (wildcard != null && wildcard.fProcessContents == XSWildcardDecl.PC_SKIP) {
1848             fSkipValidationDepth = fElementDepth;
1849             if (fAugPSVI)
1850                 augs = getEmptyAugs(augs);
1851             return augs;
1852         }
1853 
1854         // try again to get the element decl:
1855         // case 1: find declaration for root element
1856         // case 2: find declaration for element from another namespace
1857         if (fCurrentElemDecl == null) {
1858             if (sGrammar != null) {
1859                 fCurrentElemDecl = sGrammar.getGlobalElementDecl(element.localpart);
1860             }
1861         }
1862 
1863         if (fCurrentElemDecl != null) {
1864             // then get the type
1865             fCurrentType = fCurrentElemDecl.fType;
1866         }
1867 
1868         // get type from xsi:type
1869         String xsiType = attributes.getValue(SchemaSymbols.URI_XSI, SchemaSymbols.XSI_TYPE);
1870 
1871         // if no decl/type found for the current element
1872         if (fCurrentType == null && xsiType == null) {
1873             // if this is the validation root, report an error, because
1874             // we can't find eith decl or type for this element
1875             // REVISIT: should we report error, or warning?
1876             if (fElementDepth == 0) {
1877                 // for dynamic validation, skip the whole content,
1878                 // because no grammar was found.
1879                 if (fDynamicValidation || fSchemaDynamicValidation) {
1880                     // no schema grammar was found, but it's either dynamic
1881                     // validation, or another kind of grammar was found (DTD,
1882                     // for example). The intended behavior here is to skip
1883                     // the whole document. To improve performance, we try to
1884                     // remove the validator from the pipeline, since it's not
1885                     // supposed to do anything.
1886                     if (fDocumentSource != null) {
1887                         fDocumentSource.setDocumentHandler(fDocumentHandler);
1888                         if (fDocumentHandler != null)
1889                             fDocumentHandler.setDocumentSource(fDocumentSource);
1890                         // indicate that the validator was removed.
1891                         fElementDepth = -2;
1892                         return augs;
1893                     }
1894 
1895                     fSkipValidationDepth = fElementDepth;
1896                     if (fAugPSVI)
1897                         augs = getEmptyAugs(augs);
1898                     return augs;
1899                 }
1900                 // We don't call reportSchemaError here, because the spec
1901                 // doesn't think it's invalid not to be able to find a
1902                 // declaration or type definition for an element. Xerces is
1903                 // reporting it as an error for historical reasons, but in
1904                 // PSVI, we shouldn't mark this element as invalid because
1905                 // of this. - SG
1906                 fXSIErrorReporter.fErrorReporter.reportError(
1907                     XSMessageFormatter.SCHEMA_DOMAIN,
1908                     "cvc-elt.1",
1909                     new Object[] { element.rawname },
1910                     XMLErrorReporter.SEVERITY_ERROR);
1911             }
1912             // if wildcard = strict, report error.
1913             // needs to be called before fXSIErrorReporter.pushContext()
1914             // so that the error belongs to the parent element.
1915             else if (wildcard != null && wildcard.fProcessContents == XSWildcardDecl.PC_STRICT) {
1916                 // report error, because wilcard = strict
1917                 reportSchemaError("cvc-complex-type.2.4.c", new Object[] { element.rawname });
1918             }
1919             // no element decl or type found for this element.
1920             // Allowed by the spec, we can choose to either laxly assess this
1921             // element, or to skip it. Now we choose lax assessment.
1922             fCurrentType = SchemaGrammar.fAnyType;
1923             fStrictAssess = false;
1924             fNFullValidationDepth = fElementDepth;
1925             // any type has mixed content, so we don't need to append buffer
1926             fAppendBuffer = false;
1927 
1928             // push error reporter context: record the current position
1929             // This has to happen after we process skip contents,
1930             // otherwise push and pop won't be correctly paired.
1931             fXSIErrorReporter.pushContext();
1932         } else {
1933             // push error reporter context: record the current position
1934             // This has to happen after we process skip contents,
1935             // otherwise push and pop won't be correctly paired.
1936             fXSIErrorReporter.pushContext();
1937 
1938             // get xsi:type
1939             if (xsiType != null) {
1940                 XSTypeDefinition oldType = fCurrentType;
1941                 fCurrentType = getAndCheckXsiType(element, xsiType, attributes);
1942                 // If it fails, use the old type. Use anyType if ther is no old type.
1943                 if (fCurrentType == null) {
1944                     if (oldType == null)
1945                         fCurrentType = SchemaGrammar.fAnyType;
1946                     else
1947                         fCurrentType = oldType;
1948                 }
1949             }
1950 
1951             fNNoneValidationDepth = fElementDepth;
1952             // if the element has a fixed value constraint, we need to append
1953             if (fCurrentElemDecl != null
1954                 && fCurrentElemDecl.getConstraintType() == XSConstants.VC_FIXED) {
1955                 fAppendBuffer = true;
1956             }
1957             // if the type is simple, we need to append
1958             else if (fCurrentType.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) {
1959                 fAppendBuffer = true;
1960             } else {
1961                 // if the type is simple content complex type, we need to append
1962                 XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType;
1963                 fAppendBuffer = (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_SIMPLE);
1964             }
1965         }
1966 
1967         // Element Locally Valid (Element)
1968         // 2 Its {abstract} must be false.
1969         if (fCurrentElemDecl != null && fCurrentElemDecl.getAbstract())
1970             reportSchemaError("cvc-elt.2", new Object[] { element.rawname });
1971 
1972         // make the current element validation root
1973         if (fElementDepth == 0) {
1974             fValidationRoot = element.rawname;
1975         }
1976 
1977         // update normalization flags
1978         if (fNormalizeData) {
1979             // reset values
1980             fFirstChunk = true;
1981             fTrailing = false;
1982             fUnionType = false;
1983             fWhiteSpace = -1;
1984         }
1985 
1986         // Element Locally Valid (Type)
1987         // 2 Its {abstract} must be false.
1988         if (fCurrentType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) {
1989             XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType;
1990             if (ctype.getAbstract()) {
1991                 reportSchemaError("cvc-type.2", new Object[] { element.rawname });
1992             }
1993             if (fNormalizeData) {
1994                 // find out if the content type is simple and if variety is union
1995                 // to be able to do character normalization
1996                 if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_SIMPLE) {
1997                     if (ctype.fXSSimpleType.getVariety() == XSSimpleType.VARIETY_UNION) {
1998                         fUnionType = true;
1999                     } else {
2000                         try {
2001                             fWhiteSpace = ctype.fXSSimpleType.getWhitespace();
2002                         } catch (DatatypeException e) {
2003                             // do nothing
2004                         }
2005                     }
2006                 }
2007             }
2008         }
2009         // normalization: simple type
2010         else if (fNormalizeData) {
2011             // if !union type
2012             XSSimpleType dv = (XSSimpleType) fCurrentType;
2013             if (dv.getVariety() == XSSimpleType.VARIETY_UNION) {
2014                 fUnionType = true;
2015             } else {
2016                 try {
2017                     fWhiteSpace = dv.getWhitespace();
2018                 } catch (DatatypeException e) {
2019                     // do nothing
2020                 }
2021             }
2022         }
2023 
2024         // then try to get the content model
2025         fCurrentCM = null;
2026         if (fCurrentType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) {
2027             fCurrentCM = ((XSComplexTypeDecl) fCurrentType).getContentModel(fCMBuilder);
2028         }
2029 
2030         // and get the initial content model state
2031         fCurrCMState = null;
2032         if (fCurrentCM != null)
2033             fCurrCMState = fCurrentCM.startContentModel();
2034 
2035         // get information about xsi:nil
2036         String xsiNil = attributes.getValue(SchemaSymbols.URI_XSI, SchemaSymbols.XSI_NIL);
2037         // only deal with xsi:nil when there is an element declaration
2038         if (xsiNil != null && fCurrentElemDecl != null)
2039             fNil = getXsiNil(element, xsiNil);
2040 
2041         // now validate everything related with the attributes
2042         // first, get the attribute group
2043         XSAttributeGroupDecl attrGrp = null;
2044         if (fCurrentType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) {
2045             XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType;
2046             attrGrp = ctype.getAttrGrp();
2047         }
2048         // activate identity constraints
2049         fValueStoreCache.startElement();
2050         fMatcherStack.pushContext();
2051         if (fCurrentElemDecl != null && fCurrentElemDecl.fIDCPos > 0) {
2052             fIdConstraint = true;
2053             // initialize when identity constrains are defined for the elem
2054             fValueStoreCache.initValueStoresFor(fCurrentElemDecl, this);
2055         }
2056         processAttributes(element, attributes, attrGrp);
2057 
2058         // add default attributes
2059         if (attrGrp != null) {
2060             addDefaultAttributes(element, attributes, attrGrp);
2061         }
2062 
2063         // call all active identity constraints
2064         int count = fMatcherStack.getMatcherCount();
2065         for (int i = 0; i < count; i++) {
2066             XPathMatcher matcher = fMatcherStack.getMatcherAt(i);
2067             matcher.startElement( element, attributes);
2068         }
2069 
2070         if (fAugPSVI) {
2071             augs = getEmptyAugs(augs);
2072 
2073             // PSVI: add validation context
2074             fCurrentPSVI.fValidationContext = fValidationRoot;
2075             // PSVI: add element declaration
2076             fCurrentPSVI.fDeclaration = fCurrentElemDecl;
2077             // PSVI: add element type
2078             fCurrentPSVI.fTypeDecl = fCurrentType;
2079             // PSVI: add notation attribute
2080             fCurrentPSVI.fNotation = fNotation;
2081         }
2082 
2083         return augs;
2084 
2085     } // handleStartElement(QName,XMLAttributes,boolean)
2086 
2087     /**
2088      *  Handle end element. If there is not text content, and there is a
2089      *  {value constraint} on the corresponding element decl, then
2090      * set the fDefaultValue XMLString representing the default value.
2091      */
2092     Augmentations handleEndElement(QName element, Augmentations augs) {
2093 
2094         if (DEBUG) {
2095             System.out.println("==>handleEndElement:" + element);
2096         }
2097         // if we are skipping, return
2098         if (fSkipValidationDepth >= 0) {
2099             // but if this is the top element that we are skipping,
2100             // restore the states.
2101             if (fSkipValidationDepth == fElementDepth && fSkipValidationDepth > 0) {
2102                 // set the partial validation depth to the depth of parent
2103                 fNFullValidationDepth = fSkipValidationDepth - 1;
2104                 fSkipValidationDepth = -1;
2105                 fElementDepth--;
2106                 fSubElement = fSubElementStack[fElementDepth];
2107                 fCurrentElemDecl = fElemDeclStack[fElementDepth];
2108                 fNil = fNilStack[fElementDepth];
2109                 fNotation = fNotationStack[fElementDepth];
2110                 fCurrentType = fTypeStack[fElementDepth];
2111                 fCurrentCM = fCMStack[fElementDepth];
2112                 fStrictAssess = fStrictAssessStack[fElementDepth];
2113                 fCurrCMState = fCMStateStack[fElementDepth];
2114                 fSawText = fSawTextStack[fElementDepth];
2115                 fSawCharacters = fStringContent[fElementDepth];
2116             }
2117             else {
2118                 fElementDepth--;
2119             }
2120 
2121             // PSVI: validation attempted:
2122             // use default values in psvi item for
2123             // validation attempted, validity, and error codes
2124 
2125             // check extra schema constraints on root element
2126             if (fElementDepth == -1 && fFullChecking) {
2127                 XSConstraints.fullSchemaChecking(
2128                     fGrammarBucket,
2129                     fSubGroupHandler,
2130                     fCMBuilder,
2131                     fXSIErrorReporter.fErrorReporter);
2132             }
2133 
2134             if (fAugPSVI)
2135                 augs = getEmptyAugs(augs);
2136             return augs;
2137         }
2138 
2139         // now validate the content of the element
2140         processElementContent(element);
2141 
2142         // Element Locally Valid (Element)
2143         // 6 The element information item must be valid with respect to each of the {identity-constraint definitions} as per Identity-constraint Satisfied (3.11.4).
2144 
2145         // call matchers and de-activate context
2146         int oldCount = fMatcherStack.getMatcherCount();
2147         for (int i = oldCount - 1; i >= 0; i--) {
2148             XPathMatcher matcher = fMatcherStack.getMatcherAt(i);
2149             if (fCurrentElemDecl == null)
2150                 matcher.endElement(element, null, false, fValidatedInfo.actualValue, fValidatedInfo.actualValueType, fValidatedInfo.itemValueTypes);
2151 
2152             else
2153                 matcher.endElement(
2154                     element,
2155                     fCurrentType,
2156                     fCurrentElemDecl.getNillable(),
2157                     fDefaultValue == null
2158                         ? fValidatedInfo.actualValue
2159                         : fCurrentElemDecl.fDefault.actualValue,
2160                     fDefaultValue == null
2161                         ? fValidatedInfo.actualValueType
2162                         : fCurrentElemDecl.fDefault.actualValueType,
2163                     fDefaultValue == null
2164                         ? fValidatedInfo.itemValueTypes
2165                         : fCurrentElemDecl.fDefault.itemValueTypes);
2166         }
2167 
2168         if (fMatcherStack.size() > 0) {
2169             fMatcherStack.popContext();
2170         }
2171 
2172         int newCount = fMatcherStack.getMatcherCount();
2173         // handle everything *but* keyref's.
2174         for (int i = oldCount - 1; i >= newCount; i--) {
2175             XPathMatcher matcher = fMatcherStack.getMatcherAt(i);
2176             if (matcher instanceof Selector.Matcher) {
2177                 Selector.Matcher selMatcher = (Selector.Matcher) matcher;
2178                 IdentityConstraint id;
2179                 if ((id = selMatcher.getIdentityConstraint()) != null
2180                     && id.getCategory() != IdentityConstraint.IC_KEYREF) {
2181                     fValueStoreCache.transplant(id, selMatcher.getInitialDepth());
2182                 }
2183             }
2184         }
2185 
2186         // now handle keyref's/...
2187         for (int i = oldCount - 1; i >= newCount; i--) {
2188             XPathMatcher matcher = fMatcherStack.getMatcherAt(i);
2189             if (matcher instanceof Selector.Matcher) {
2190                 Selector.Matcher selMatcher = (Selector.Matcher) matcher;
2191                 IdentityConstraint id;
2192                 if ((id = selMatcher.getIdentityConstraint()) != null
2193                     && id.getCategory() == IdentityConstraint.IC_KEYREF) {
2194                     ValueStoreBase values =
2195                         fValueStoreCache.getValueStoreFor(id, selMatcher.getInitialDepth());
2196                     if (values != null) // nothing to do if nothing matched!
2197                         values.endDocumentFragment();
2198                 }
2199             }
2200         }
2201         fValueStoreCache.endElement();
2202 
2203         SchemaGrammar[] grammars = null;
2204         // have we reached the end tag of the validation root?
2205         if (fElementDepth == 0) {
2206             // 7 If the element information item is the validation root, it must be valid per Validation Root Valid (ID/IDREF) (3.3.4).
2207             String invIdRef = fValidationState.checkIDRefID();
2208             fValidationState.resetIDTables();
2209             if (invIdRef != null) {
2210                 reportSchemaError("cvc-id.1", new Object[] { invIdRef });
2211             }
2212             // check extra schema constraints
2213             if (fFullChecking) {
2214                 XSConstraints.fullSchemaChecking(
2215                     fGrammarBucket,
2216                     fSubGroupHandler,
2217                     fCMBuilder,
2218                     fXSIErrorReporter.fErrorReporter);
2219             }
2220 
2221             grammars = fGrammarBucket.getGrammars();
2222             // return the final set of grammars validator ended up with
2223             if (fGrammarPool != null) {
2224                 // Set grammars as immutable
2225                 for (int k=0; k < grammars.length; k++) {
2226                     grammars[k].setImmutable(true);
2227                 }
2228                 fGrammarPool.cacheGrammars(XMLGrammarDescription.XML_SCHEMA, grammars);
2229             }
2230             augs = endElementPSVI(true, grammars, augs);
2231         } else {
2232             augs = endElementPSVI(false, grammars, augs);
2233 
2234             // decrease element depth and restore states
2235             fElementDepth--;
2236 
2237             // get the states for the parent element.
2238             fSubElement = fSubElementStack[fElementDepth];
2239             fCurrentElemDecl = fElemDeclStack[fElementDepth];
2240             fNil = fNilStack[fElementDepth];
2241             fNotation = fNotationStack[fElementDepth];
2242             fCurrentType = fTypeStack[fElementDepth];
2243             fCurrentCM = fCMStack[fElementDepth];
2244             fStrictAssess = fStrictAssessStack[fElementDepth];
2245             fCurrCMState = fCMStateStack[fElementDepth];
2246             fSawText = fSawTextStack[fElementDepth];
2247             fSawCharacters = fStringContent[fElementDepth];
2248 
2249             // We should have a stack for whitespace value, and pop it up here.
2250             // But when fWhiteSpace != -1, and we see a sub-element, it must be
2251             // an error (at least for Schema 1.0). So for valid documents, the
2252             // only value we are going to push/pop in the stack is -1.
2253             // Here we just mimic the effect of popping -1. -SG
2254             fWhiteSpace = -1;
2255             // Same for append buffer. Simple types and elements with fixed
2256             // value constraint don't allow sub-elements. -SG
2257             fAppendBuffer = false;
2258             // same here.
2259             fUnionType = false;
2260         }
2261 
2262         return augs;
2263     } // handleEndElement(QName,boolean)*/
2264 
2265     final Augmentations endElementPSVI(
2266         boolean root,
2267         SchemaGrammar[] grammars,
2268         Augmentations augs) {
2269 
2270         if (fAugPSVI) {
2271             augs = getEmptyAugs(augs);
2272 
2273             // the 4 properties sent on startElement calls
2274             fCurrentPSVI.fDeclaration = this.fCurrentElemDecl;
2275             fCurrentPSVI.fTypeDecl = this.fCurrentType;
2276             fCurrentPSVI.fNotation = this.fNotation;
2277             fCurrentPSVI.fValidationContext = this.fValidationRoot;
2278             // PSVI: validation attempted
2279             // nothing below or at the same level has none or partial
2280             // (which means this level is strictly assessed, and all chidren
2281             // are full), so this one has full
2282             if (fElementDepth > fNFullValidationDepth) {
2283                 fCurrentPSVI.fValidationAttempted = ElementPSVI.VALIDATION_FULL;
2284             }
2285             // nothing below or at the same level has full or partial
2286             // (which means this level is not strictly assessed, and all chidren
2287             // are none), so this one has none
2288             else if (fElementDepth > fNNoneValidationDepth) {
2289                 fCurrentPSVI.fValidationAttempted = ElementPSVI.VALIDATION_NONE;
2290             }
2291             // otherwise partial, and anything above this level will be partial
2292             else {
2293                 fCurrentPSVI.fValidationAttempted = ElementPSVI.VALIDATION_PARTIAL;
2294                 fNFullValidationDepth = fNNoneValidationDepth = fElementDepth - 1;
2295             }
2296 
2297             if (fDefaultValue != null)
2298                 fCurrentPSVI.fSpecified = true;
2299             fCurrentPSVI.fNil = fNil;
2300             fCurrentPSVI.fMemberType = fValidatedInfo.memberType;
2301             fCurrentPSVI.fNormalizedValue = fValidatedInfo.normalizedValue;
2302             fCurrentPSVI.fActualValue = fValidatedInfo.actualValue;
2303             fCurrentPSVI.fActualValueType = fValidatedInfo.actualValueType;
2304             fCurrentPSVI.fItemValueTypes = fValidatedInfo.itemValueTypes;
2305 
2306             if (fStrictAssess) {
2307                 // get all errors for the current element, its attribute,
2308                 // and subelements (if they were strictly assessed).
2309                 // any error would make this element invalid.
2310                 // and we merge these errors to the parent element.
2311                 String[] errors = fXSIErrorReporter.mergeContext();
2312 
2313                 // PSVI: error codes
2314                 fCurrentPSVI.fErrorCodes = errors;
2315                 // PSVI: validity
2316                 fCurrentPSVI.fValidity =
2317                     (errors == null) ? ElementPSVI.VALIDITY_VALID : ElementPSVI.VALIDITY_INVALID;
2318             } else {
2319                 // PSVI: validity
2320                 fCurrentPSVI.fValidity = ElementPSVI.VALIDITY_NOTKNOWN;
2321                 // Discard the current context: ignore any error happened within
2322                 // the sub-elements/attributes of this element, because those
2323                 // errors won't affect the validity of the parent elements.
2324                 fXSIErrorReporter.popContext();
2325             }
2326 
2327             if (root) {
2328                 // store [schema information] in the PSVI
2329                 fCurrentPSVI.fGrammars = grammars;
2330                 fCurrentPSVI.fSchemaInformation = null;
2331             }
2332         }
2333 
2334         return augs;
2335 
2336     }
2337 
2338     Augmentations getEmptyAugs(Augmentations augs) {
2339         if (augs == null) {
2340             augs = fAugmentations;
2341             augs.removeAllItems();
2342         }
2343         augs.putItem(Constants.ELEMENT_PSVI, fCurrentPSVI);
2344         fCurrentPSVI.reset();
2345 
2346         return augs;
2347     }
2348 
2349     void storeLocations(String sLocation, String nsLocation) {
2350         if (sLocation != null) {
2351             if (!XMLSchemaLoader.tokenizeSchemaLocationStr(sLocation, fLocationPairs)) {
2352                 // error!
2353                 fXSIErrorReporter.reportError(
2354                     XSMessageFormatter.SCHEMA_DOMAIN,
2355                     "SchemaLocation",
2356                     new Object[] { sLocation },
2357                     XMLErrorReporter.SEVERITY_WARNING);
2358             }
2359         }
2360         if (nsLocation != null) {
2361             XMLSchemaLoader.LocationArray la =
2362                 ((XMLSchemaLoader.LocationArray) fLocationPairs.get(XMLSymbols.EMPTY_STRING));
2363             if (la == null) {
2364                 la = new XMLSchemaLoader.LocationArray();
2365                 fLocationPairs.put(XMLSymbols.EMPTY_STRING, la);
2366             }
2367             la.addLocation(nsLocation);
2368         }
2369 
2370     } //storeLocations
2371 
2372     //this is the function where logic of retrieving grammar is written , parser first tries to get the grammar from
2373     //the local pool, if not in local pool, it gives chance to application to be able to retrieve the grammar, then it
2374     //tries to parse the grammar using location hints from the give namespace.
2375     SchemaGrammar findSchemaGrammar(
2376         short contextType,
2377         String namespace,
2378         QName enclosingElement,
2379         QName triggeringComponet,
2380         XMLAttributes attributes) {
2381         SchemaGrammar grammar = null;
2382         //get the grammar from local pool...
2383         grammar = fGrammarBucket.getGrammar(namespace);
2384 
2385         if (grammar == null) {
2386             fXSDDescription.setNamespace(namespace);
2387             // give a chance to application to be able to retreive the grammar.
2388             if (fGrammarPool != null) {
2389                 grammar = (SchemaGrammar) fGrammarPool.retrieveGrammar(fXSDDescription);
2390                 if (grammar != null) {
2391                     // put this grammar into the bucket, along with grammars
2392                     // imported by it (directly or indirectly)
2393                     if (!fGrammarBucket.putGrammar(grammar, true, fNamespaceGrowth)) {
2394                         // REVISIT: a conflict between new grammar(s) and grammars
2395                         // in the bucket. What to do? A warning? An exception?
2396                         fXSIErrorReporter.fErrorReporter.reportError(
2397                             XSMessageFormatter.SCHEMA_DOMAIN,
2398                             "GrammarConflict",
2399                             null,
2400                             XMLErrorReporter.SEVERITY_WARNING);
2401                         grammar = null;
2402                     }
2403                 }
2404             }
2405         }
2406         if ((grammar == null && !fUseGrammarPoolOnly) || fNamespaceGrowth) {
2407             fXSDDescription.reset();
2408             fXSDDescription.fContextType = contextType;
2409             fXSDDescription.setNamespace(namespace);
2410             fXSDDescription.fEnclosedElementName = enclosingElement;
2411             fXSDDescription.fTriggeringComponent = triggeringComponet;
2412             fXSDDescription.fAttributes = attributes;
2413             if (fLocator != null) {
2414                 fXSDDescription.setBaseSystemId(fLocator.getExpandedSystemId());
2415             }
2416 
2417             Hashtable locationPairs = fLocationPairs;
2418             Object locationArray =
2419                 locationPairs.get(namespace == null ? XMLSymbols.EMPTY_STRING : namespace);
2420             if (locationArray != null) {
2421                 String[] temp = ((XMLSchemaLoader.LocationArray) locationArray).getLocationArray();
2422                 if (temp.length != 0) {
2423                     setLocationHints(fXSDDescription, temp, grammar);
2424                 }
2425             }
2426 
2427             if (grammar == null || fXSDDescription.fLocationHints != null) {
2428                 boolean toParseSchema = true;
2429                 if (grammar != null) {
2430                      // use location hints instead
2431                     locationPairs = EMPTY_TABLE;
2432                 }
2433 
2434                 // try to parse the grammar using location hints from that namespace..
2435                 try {
2436                     XMLInputSource xis =
2437                         XMLSchemaLoader.resolveDocument(
2438                             fXSDDescription,
2439                             locationPairs,
2440                             fEntityResolver);
2441                     if (grammar != null && fNamespaceGrowth) {
2442                         try {
2443                             // if we are dealing with a different schema location, then include the new schema
2444                             // into the existing grammar
2445                             if (grammar.getDocumentLocations().contains(XMLEntityManager.expandSystemId(xis.getSystemId(), xis.getBaseSystemId(), false))) {
2446                                 toParseSchema = false;
2447                             }
2448                         }
2449                         catch (MalformedURIException e) {
2450                         }
2451                     }
2452                     if (toParseSchema) {
2453                         grammar = fSchemaLoader.loadSchema(fXSDDescription, xis, fLocationPairs);
2454                     }
2455                 } catch (IOException ex) {
2456                     final String [] locationHints = fXSDDescription.getLocationHints();
2457                     fXSIErrorReporter.fErrorReporter.reportError(
2458                         XSMessageFormatter.SCHEMA_DOMAIN,
2459                         "schema_reference.4",
2460                         new Object[] { locationHints != null ? locationHints[0] : XMLSymbols.EMPTY_STRING },
2461                         XMLErrorReporter.SEVERITY_WARNING);
2462                 }
2463             }
2464         }
2465 
2466         return grammar;
2467 
2468     } //findSchemaGrammar
2469     private void setLocationHints(XSDDescription desc, String[] locations, SchemaGrammar grammar) {
2470         int length = locations.length;
2471         if (grammar == null) {
2472             fXSDDescription.fLocationHints = new String[length];
2473             System.arraycopy(locations, 0, fXSDDescription.fLocationHints, 0, length);
2474         }
2475         else {
2476             setLocationHints(desc, locations, grammar.getDocumentLocations());
2477         }
2478     }
2479 
2480     private void setLocationHints(XSDDescription desc, String[] locations, StringList docLocations) {
2481         int length = locations.length;
2482         String[] hints = new String[length];
2483         int counter = 0;
2484 
2485         for (int i=0; i<length; i++) {
2486             try {
2487                 String id = XMLEntityManager.expandSystemId(locations[i], desc.getBaseSystemId(), false);
2488                 if (!docLocations.contains(id)) {
2489                     hints[counter++] = locations[i];
2490                 }
2491             }
2492             catch (MalformedURIException e) {
2493             }
2494         }
2495 
2496         if (counter > 0) {
2497             if (counter == length) {
2498                 fXSDDescription.fLocationHints = hints;
2499             }
2500             else {
2501                 fXSDDescription.fLocationHints = new String[counter];
2502                 System.arraycopy(hints, 0, fXSDDescription.fLocationHints, 0, counter);
2503             }
2504         }
2505     }
2506 
2507 
2508     XSTypeDefinition getAndCheckXsiType(QName element, String xsiType, XMLAttributes attributes) {
2509         // This method also deals with clause 1.2.1.2 of the constraint
2510         // Validation Rule: Schema-Validity Assessment (Element)
2511 
2512         // Element Locally Valid (Element)
2513         // 4 If there is an attribute information item among the element information item's [attributes] whose [namespace name] is identical to http://www.w3.org/2001/XMLSchema-instance and whose [local name] is type, then all of the following must be true:
2514         // 4.1 The normalized value of that attribute information item must be valid with respect to the built-in QName simple type, as defined by String Valid (3.14.4);
2515         QName typeName = null;
2516         try {
2517             typeName = (QName) fQNameDV.validate(xsiType, fValidationState, null);
2518         } catch (InvalidDatatypeValueException e) {
2519             reportSchemaError(e.getKey(), e.getArgs());
2520             reportSchemaError(
2521                 "cvc-elt.4.1",
2522                 new Object[] {
2523                     element.rawname,
2524                     SchemaSymbols.URI_XSI + "," + SchemaSymbols.XSI_TYPE,
2525                     xsiType });
2526             return null;
2527         }
2528 
2529         // 4.2 The local name and namespace name (as defined in QName Interpretation (3.15.3)), of the actual value of that attribute information item must resolve to a type definition, as defined in QName resolution (Instance) (3.15.4)
2530         XSTypeDefinition type = null;
2531         // if the namespace is schema namespace, first try built-in types
2532         if (typeName.uri == SchemaSymbols.URI_SCHEMAFORSCHEMA) {
2533             type = SchemaGrammar.SG_SchemaNS.getGlobalTypeDecl(typeName.localpart);
2534         }
2535         // if it's not schema built-in types, then try to get a grammar
2536         if (type == null) {
2537             //try to find schema grammar by different means....
2538             SchemaGrammar grammar =
2539                 findSchemaGrammar(
2540                     XSDDescription.CONTEXT_XSITYPE,
2541                     typeName.uri,
2542                     element,
2543                     typeName,
2544                     attributes);
2545 
2546             if (grammar != null)
2547                 type = grammar.getGlobalTypeDecl(typeName.localpart);
2548         }
2549         // still couldn't find the type, report an error
2550         if (type == null) {
2551             reportSchemaError("cvc-elt.4.2", new Object[] { element.rawname, xsiType });
2552             return null;
2553         }
2554 
2555         // if there is no current type, set this one as current.
2556         // and we don't need to do extra checking
2557         if (fCurrentType != null) {
2558             // 4.3 The local type definition must be validly derived from the {type definition} given the union of the {disallowed substitutions} and the {type definition}'s {prohibited substitutions}, as defined in Type Derivation OK (Complex) (3.4.6) (if it is a complex type definition), or given {disallowed substitutions} as defined in Type Derivation OK (Simple) (3.14.6) (if it is a simple type definition).
2559             short block = fCurrentElemDecl.fBlock;
2560             if (fCurrentType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE)
2561                 block |= ((XSComplexTypeDecl) fCurrentType).fBlock;
2562             if (!XSConstraints.checkTypeDerivationOk(type, fCurrentType, block))
2563                 reportSchemaError(
2564                     "cvc-elt.4.3",
2565                     new Object[] { element.rawname, xsiType, fCurrentType.getName()});
2566         }
2567 
2568         return type;
2569     } //getAndCheckXsiType
2570 
2571     boolean getXsiNil(QName element, String xsiNil) {
2572         // Element Locally Valid (Element)
2573         // 3 The appropriate case among the following must be true:
2574         // 3.1 If {nillable} is false, then there must be no attribute information item among the element information item's [attributes] whose [namespace name] is identical to http://www.w3.org/2001/XMLSchema-instance and whose [local name] is nil.
2575         if (fCurrentElemDecl != null && !fCurrentElemDecl.getNillable()) {
2576             reportSchemaError(
2577                 "cvc-elt.3.1",
2578                 new Object[] {
2579                     element.rawname,
2580                     SchemaSymbols.URI_XSI + "," + SchemaSymbols.XSI_NIL });
2581         }
2582         // 3.2 If {nillable} is true and there is such an attribute information item and its actual value is true , then all of the following must be true:
2583         // 3.2.2 There must be no fixed {value constraint}.
2584         else {
2585             String value = XMLChar.trim(xsiNil);
2586             if (value.equals(SchemaSymbols.ATTVAL_TRUE)
2587                 || value.equals(SchemaSymbols.ATTVAL_TRUE_1)) {
2588                 if (fCurrentElemDecl != null
2589                     && fCurrentElemDecl.getConstraintType() == XSConstants.VC_FIXED) {
2590                     reportSchemaError(
2591                         "cvc-elt.3.2.2",
2592                         new Object[] {
2593                             element.rawname,
2594                             SchemaSymbols.URI_XSI + "," + SchemaSymbols.XSI_NIL });
2595                 }
2596                 return true;
2597             }
2598         }
2599         return false;
2600     }
2601 
2602     void processAttributes(QName element, XMLAttributes attributes, XSAttributeGroupDecl attrGrp) {
2603 
2604         if (DEBUG) {
2605             System.out.println("==>processAttributes: " + attributes.getLength());
2606         }
2607 
2608         // whether we have seen a Wildcard ID.
2609         String wildcardIDName = null;
2610 
2611         // for each present attribute
2612         int attCount = attributes.getLength();
2613 
2614         Augmentations augs = null;
2615         AttributePSVImpl attrPSVI = null;
2616 
2617         boolean isSimple =
2618             fCurrentType == null || fCurrentType.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE;
2619 
2620         XSObjectList attrUses = null;
2621         int useCount = 0;
2622         XSWildcardDecl attrWildcard = null;
2623         if (!isSimple) {
2624             attrUses = attrGrp.getAttributeUses();
2625             useCount = attrUses.getLength();
2626             attrWildcard = attrGrp.fAttributeWC;
2627         }
2628 
2629         // Element Locally Valid (Complex Type)
2630         // 3 For each attribute information item in the element information item's [attributes] excepting those whose [namespace name] is identical to http://www.w3.org/2001/XMLSchema-instance and whose [local name] is one of type, nil, schemaLocation or noNamespaceSchemaLocation, the appropriate case among the following must be true:
2631         // get the corresponding attribute decl
2632         for (int index = 0; index < attCount; index++) {
2633 
2634             attributes.getName(index, fTempQName);
2635 
2636             if (DEBUG) {
2637                 System.out.println("==>process attribute: " + fTempQName);
2638             }
2639 
2640             if (fAugPSVI || fIdConstraint) {
2641                 augs = attributes.getAugmentations(index);
2642                 attrPSVI = (AttributePSVImpl) augs.getItem(Constants.ATTRIBUTE_PSVI);
2643                 if (attrPSVI != null) {
2644                     attrPSVI.reset();
2645                 } else {
2646                     attrPSVI = new AttributePSVImpl();
2647                     augs.putItem(Constants.ATTRIBUTE_PSVI, attrPSVI);
2648                 }
2649                 // PSVI attribute: validation context
2650                 attrPSVI.fValidationContext = fValidationRoot;
2651             }
2652 
2653             // Element Locally Valid (Type)
2654             // 3.1.1 The element information item's [attributes] must be empty, excepting those
2655             // whose [namespace name] is identical to http://www.w3.org/2001/XMLSchema-instance and
2656             // whose [local name] is one of type, nil, schemaLocation or noNamespaceSchemaLocation.
2657 
2658             // for the 4 xsi attributes, get appropriate decl, and validate
2659             if (fTempQName.uri == SchemaSymbols.URI_XSI) {
2660                 XSAttributeDecl attrDecl = null;
2661                 if (fTempQName.localpart == SchemaSymbols.XSI_SCHEMALOCATION)
2662                     attrDecl =
2663                         SchemaGrammar.SG_XSI.getGlobalAttributeDecl(
2664                             SchemaSymbols.XSI_SCHEMALOCATION);
2665                 else if (fTempQName.localpart == SchemaSymbols.XSI_NONAMESPACESCHEMALOCATION)
2666                     attrDecl =
2667                         SchemaGrammar.SG_XSI.getGlobalAttributeDecl(
2668                             SchemaSymbols.XSI_NONAMESPACESCHEMALOCATION);
2669                 else if (fTempQName.localpart == SchemaSymbols.XSI_NIL)
2670                     attrDecl = SchemaGrammar.SG_XSI.getGlobalAttributeDecl(SchemaSymbols.XSI_NIL);
2671                 else if (fTempQName.localpart == SchemaSymbols.XSI_TYPE)
2672                     attrDecl = SchemaGrammar.SG_XSI.getGlobalAttributeDecl(SchemaSymbols.XSI_TYPE);
2673                 if (attrDecl != null) {
2674                     processOneAttribute(element, attributes, index, attrDecl, null, attrPSVI);
2675                     continue;
2676                 }
2677             }
2678 
2679             // for namespace attributes, no_validation/unknow_validity
2680             if (fTempQName.rawname == XMLSymbols.PREFIX_XMLNS
2681                 || fTempQName.rawname.startsWith("xmlns:")) {
2682                 continue;
2683             }
2684 
2685             // simple type doesn't allow any other attributes
2686             if (isSimple) {
2687                 reportSchemaError(
2688                     "cvc-type.3.1.1",
2689                     new Object[] { element.rawname, fTempQName.rawname });
2690                 continue;
2691             }
2692 
2693             // it's not xmlns, and not xsi, then we need to find a decl for it
2694             XSAttributeUseImpl currUse = null, oneUse;
2695             for (int i = 0; i < useCount; i++) {
2696                 oneUse = (XSAttributeUseImpl) attrUses.item(i);
2697                 if (oneUse.fAttrDecl.fName == fTempQName.localpart
2698                     && oneUse.fAttrDecl.fTargetNamespace == fTempQName.uri) {
2699                     currUse = oneUse;
2700                     break;
2701                 }
2702             }
2703 
2704             // 3.2 otherwise all of the following must be true:
2705             // 3.2.1 There must be an {attribute wildcard}.
2706             // 3.2.2 The attribute information item must be valid with respect to it as defined in Item Valid (Wildcard) (3.10.4).
2707 
2708             // if failed, get it from wildcard
2709             if (currUse == null) {
2710                 //if (attrWildcard == null)
2711                 //    reportSchemaError("cvc-complex-type.3.2.1", new Object[]{element.rawname, fTempQName.rawname});
2712                 if (attrWildcard == null || !attrWildcard.allowNamespace(fTempQName.uri)) {
2713                     // so this attribute is not allowed
2714                     reportSchemaError(
2715                         "cvc-complex-type.3.2.2",
2716                         new Object[] { element.rawname, fTempQName.rawname });
2717                     continue;
2718                 }
2719             }
2720 
2721             XSAttributeDecl currDecl = null;
2722             if (currUse != null) {
2723                 currDecl = currUse.fAttrDecl;
2724             } else {
2725                 // which means it matches a wildcard
2726                 // skip it if processContents is skip
2727                 if (attrWildcard.fProcessContents == XSWildcardDecl.PC_SKIP)
2728                     continue;
2729 
2730                 //try to find grammar by different means...
2731                 SchemaGrammar grammar =
2732                     findSchemaGrammar(
2733                         XSDDescription.CONTEXT_ATTRIBUTE,
2734                         fTempQName.uri,
2735                         element,
2736                         fTempQName,
2737                         attributes);
2738 
2739                 if (grammar != null) {
2740                     currDecl = grammar.getGlobalAttributeDecl(fTempQName.localpart);
2741                 }
2742 
2743                 // if can't find
2744                 if (currDecl == null) {
2745                     // if strict, report error
2746                     if (attrWildcard.fProcessContents == XSWildcardDecl.PC_STRICT) {
2747                         reportSchemaError(
2748                             "cvc-complex-type.3.2.2",
2749                             new Object[] { element.rawname, fTempQName.rawname });
2750                     }
2751 
2752                     // then continue to the next attribute
2753                     continue;
2754                 } else {
2755                     // 5 Let [Definition:]  the wild IDs be the set of all attribute information item to which clause 3.2 applied and whose validation resulted in a context-determined declaration of mustFind or no context-determined declaration at all, and whose [local name] and [namespace name] resolve (as defined by QName resolution (Instance) (3.15.4)) to an attribute declaration whose {type definition} is or is derived from ID. Then all of the following must be true:
2756                     // 5.1 There must be no more than one item in wild IDs.
2757                     if (currDecl.fType.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE
2758                         && ((XSSimpleType) currDecl.fType).isIDType()) {
2759                         if (wildcardIDName != null) {
2760                             reportSchemaError(
2761                                 "cvc-complex-type.5.1",
2762                                 new Object[] { element.rawname, currDecl.fName, wildcardIDName });
2763                         } else
2764                             wildcardIDName = currDecl.fName;
2765                     }
2766                 }
2767             }
2768 
2769             processOneAttribute(element, attributes, index, currDecl, currUse, attrPSVI);
2770         } // end of for (all attributes)
2771 
2772         // 5.2 If wild IDs is non-empty, there must not be any attribute uses among the {attribute uses} whose {attribute declaration}'s {type definition} is or is derived from ID.
2773         if (!isSimple && attrGrp.fIDAttrName != null && wildcardIDName != null) {
2774             reportSchemaError(
2775                 "cvc-complex-type.5.2",
2776                 new Object[] { element.rawname, wildcardIDName, attrGrp.fIDAttrName });
2777         }
2778 
2779     } //processAttributes
2780 
2781     void processOneAttribute(
2782         QName element,
2783         XMLAttributes attributes,
2784         int index,
2785         XSAttributeDecl currDecl,
2786         XSAttributeUseImpl currUse,
2787         AttributePSVImpl attrPSVI) {
2788 
2789         String attrValue = attributes.getValue(index);
2790         fXSIErrorReporter.pushContext();
2791 
2792         // Attribute Locally Valid
2793         // For an attribute information item to be locally valid with respect to an attribute declaration all of the following must be true:
2794         // 1 The declaration must not be absent (see Missing Sub-components (5.3) for how this can fail to be the case).
2795         // 2 Its {type definition} must not be absent.
2796         // 3 The item's normalized value must be locally valid with respect to that {type definition} as per String Valid (3.14.4).
2797         // get simple type
2798         XSSimpleType attDV = currDecl.fType;
2799 
2800         Object actualValue = null;
2801         try {
2802             actualValue = attDV.validate(attrValue, fValidationState, fValidatedInfo);
2803             // store the normalized value
2804             if (fNormalizeData)
2805                 attributes.setValue(index, fValidatedInfo.normalizedValue);
2806             if (attributes instanceof XMLAttributesImpl) {
2807                 XMLAttributesImpl attrs = (XMLAttributesImpl) attributes;
2808                 boolean schemaId =
2809                     fValidatedInfo.memberType != null
2810                         ? fValidatedInfo.memberType.isIDType()
2811                         : attDV.isIDType();
2812                 attrs.setSchemaId(index, schemaId);
2813             }
2814 
2815             // PSVI: element notation
2816             if (attDV.getVariety() == XSSimpleType.VARIETY_ATOMIC
2817                 && attDV.getPrimitiveKind() == XSSimpleType.PRIMITIVE_NOTATION) {
2818                 QName qName = (QName) actualValue;
2819                 SchemaGrammar grammar = fGrammarBucket.getGrammar(qName.uri);
2820 
2821                 //REVISIT: is it possible for the notation to be in different namespace than the attribute
2822                 //with which it is associated, CHECK !!  <fof n1:att1 = "n2:notation1" ..>
2823                 // should we give chance to the application to be able to  retrieve a grammar - nb
2824                 //REVISIT: what would be the triggering component here.. if it is attribute value that
2825                 // triggered the loading of grammar ?? -nb
2826 
2827                 if (grammar != null) {
2828                     fNotation = grammar.getGlobalNotationDecl(qName.localpart);
2829                 }
2830             }
2831         } catch (InvalidDatatypeValueException idve) {
2832             reportSchemaError(idve.getKey(), idve.getArgs());
2833             reportSchemaError(
2834                 "cvc-attribute.3",
2835                 new Object[] { element.rawname, fTempQName.rawname, attrValue, attDV.getName()});
2836         }
2837 
2838         // get the value constraint from use or decl
2839         // 4 The item's actual value must match the value of the {value constraint}, if it is present and fixed.                 // now check the value against the simpleType
2840         if (actualValue != null && currDecl.getConstraintType() == XSConstants.VC_FIXED) {
2841             if (!isComparable(fValidatedInfo, currDecl.fDefault) || !actualValue.equals(currDecl.fDefault.actualValue)) {
2842                 reportSchemaError(
2843                     "cvc-attribute.4",
2844                     new Object[] {
2845                         element.rawname,
2846                         fTempQName.rawname,
2847                         attrValue,
2848                         currDecl.fDefault.stringValue()});
2849             }
2850         }
2851 
2852         // 3.1 If there is among the {attribute uses} an attribute use with an {attribute declaration} whose {name} matches the attribute information item's [local name] and whose {target namespace} is identical to the attribute information item's [namespace name] (where an absent {target namespace} is taken to be identical to a [namespace name] with no value), then the attribute information must be valid with respect to that attribute use as per Attribute Locally Valid (Use) (3.5.4). In this case the {attribute declaration} of that attribute use is the context-determined declaration for the attribute information item with respect to Schema-Validity Assessment (Attribute) (3.2.4) and Assessment Outcome (Attribute) (3.2.5).
2853         if (actualValue != null
2854             && currUse != null
2855             && currUse.fConstraintType == XSConstants.VC_FIXED) {
2856             if (!isComparable(fValidatedInfo, currUse.fDefault) || !actualValue.equals(currUse.fDefault.actualValue)) {
2857                 reportSchemaError(
2858                     "cvc-complex-type.3.1",
2859                     new Object[] {
2860                         element.rawname,
2861                         fTempQName.rawname,
2862                         attrValue,
2863                         currUse.fDefault.stringValue()});
2864             }
2865         }
2866         if (fIdConstraint) {
2867             attrPSVI.fActualValue = actualValue;
2868         }
2869 
2870         if (fAugPSVI) {
2871             // PSVI: attribute declaration
2872             attrPSVI.fDeclaration = currDecl;
2873             // PSVI: attribute type
2874             attrPSVI.fTypeDecl = attDV;
2875 
2876             // PSVI: attribute memberType
2877             attrPSVI.fMemberType = fValidatedInfo.memberType;
2878             // PSVI: attribute normalized value
2879             // NOTE: we always store the normalized value, even if it's invlid,
2880             // because it might still be useful to the user. But when the it's
2881             // not valid, the normalized value is not trustable.
2882             attrPSVI.fNormalizedValue = fValidatedInfo.normalizedValue;
2883             attrPSVI.fActualValue = fValidatedInfo.actualValue;
2884             attrPSVI.fActualValueType = fValidatedInfo.actualValueType;
2885             attrPSVI.fItemValueTypes = fValidatedInfo.itemValueTypes;
2886 
2887 
2888 
2889             // PSVI: validation attempted:
2890             attrPSVI.fValidationAttempted = AttributePSVI.VALIDATION_FULL;
2891 
2892             String[] errors = fXSIErrorReporter.mergeContext();
2893             // PSVI: error codes
2894             attrPSVI.fErrorCodes = errors;
2895             // PSVI: validity
2896             attrPSVI.fValidity =
2897                 (errors == null) ? AttributePSVI.VALIDITY_VALID : AttributePSVI.VALIDITY_INVALID;
2898         }
2899     }
2900 
2901     void addDefaultAttributes(
2902         QName element,
2903         XMLAttributes attributes,
2904         XSAttributeGroupDecl attrGrp) {
2905         // Check after all specified attrs are scanned
2906         // (1) report error for REQUIRED attrs that are missing (V_TAGc)
2907         // REVISIT: should we check prohibited attributes?
2908         // (2) report error for PROHIBITED attrs that are present (V_TAGc)
2909         // (3) add default attrs (FIXED and NOT_FIXED)
2910         //
2911         if (DEBUG) {
2912             System.out.println("==>addDefaultAttributes: " + element);
2913         }
2914         XSObjectList attrUses = attrGrp.getAttributeUses();
2915         int useCount = attrUses.getLength();
2916         XSAttributeUseImpl currUse;
2917         XSAttributeDecl currDecl;
2918         short constType;
2919         ValidatedInfo defaultValue;
2920         boolean isSpecified;
2921         QName attName;
2922         // for each attribute use
2923         for (int i = 0; i < useCount; i++) {
2924 
2925             currUse = (XSAttributeUseImpl) attrUses.item(i);
2926             currDecl = currUse.fAttrDecl;
2927             // get value constraint
2928             constType = currUse.fConstraintType;
2929             defaultValue = currUse.fDefault;
2930             if (constType == XSConstants.VC_NONE) {
2931                 constType = currDecl.getConstraintType();
2932                 defaultValue = currDecl.fDefault;
2933             }
2934             // whether this attribute is specified
2935             isSpecified = attributes.getValue(currDecl.fTargetNamespace, currDecl.fName) != null;
2936 
2937             // Element Locally Valid (Complex Type)
2938             // 4 The {attribute declaration} of each attribute use in the {attribute uses} whose
2939             // {required} is true matches one of the attribute information items in the element
2940             // information item's [attributes] as per clause 3.1 above.
2941             if (currUse.fUse == SchemaSymbols.USE_REQUIRED) {
2942                 if (!isSpecified)
2943                     reportSchemaError(
2944                         "cvc-complex-type.4",
2945                         new Object[] { element.rawname, currDecl.fName });
2946             }
2947             // if the attribute is not specified, then apply the value constraint
2948             if (!isSpecified && constType != XSConstants.VC_NONE) {
2949                 attName =
2950                     new QName(null, currDecl.fName, currDecl.fName, currDecl.fTargetNamespace);
2951                 String normalized = (defaultValue != null) ? defaultValue.stringValue() : "";
2952                 int attrIndex = attributes.addAttribute(attName, "CDATA", normalized);
2953                 if (attributes instanceof XMLAttributesImpl) {
2954                     XMLAttributesImpl attrs = (XMLAttributesImpl) attributes;
2955                     boolean schemaId =
2956                         defaultValue != null
2957                             && defaultValue.memberType != null
2958                                 ? defaultValue.memberType.isIDType()
2959                                 : currDecl.fType.isIDType();
2960                     attrs.setSchemaId(attrIndex, schemaId);
2961                 }
2962 
2963                 if (fAugPSVI) {
2964 
2965                     // PSVI: attribute is "schema" specified
2966                     Augmentations augs = attributes.getAugmentations(attrIndex);
2967                     AttributePSVImpl attrPSVI = new AttributePSVImpl();
2968                     augs.putItem(Constants.ATTRIBUTE_PSVI, attrPSVI);
2969 
2970                     attrPSVI.fDeclaration = currDecl;
2971                     attrPSVI.fTypeDecl = currDecl.fType;
2972                     attrPSVI.fMemberType = defaultValue.memberType;
2973                     attrPSVI.fNormalizedValue = normalized;
2974                     attrPSVI.fActualValue = defaultValue.actualValue;
2975                     attrPSVI.fActualValueType = defaultValue.actualValueType;
2976                     attrPSVI.fItemValueTypes = defaultValue.itemValueTypes;
2977                     attrPSVI.fValidationContext = fValidationRoot;
2978                     attrPSVI.fValidity = AttributePSVI.VALIDITY_VALID;
2979                     attrPSVI.fValidationAttempted = AttributePSVI.VALIDATION_FULL;
2980                     attrPSVI.fSpecified = true;
2981                 }
2982             }
2983 
2984         } // for
2985     } // addDefaultAttributes
2986 
2987     /**
2988      *  If there is not text content, and there is a
2989      *  {value constraint} on the corresponding element decl, then return
2990      *  an XMLString representing the default value.
2991      */
2992     void processElementContent(QName element) {
2993         // 1 If the item is ?valid? with respect to an element declaration as per Element Locally Valid (Element) (?3.3.4) and the {value constraint} is present, but clause 3.2 of Element Locally Valid (Element) (?3.3.4) above is not satisfied and the item has no element or character information item [children], then schema. Furthermore, the post-schema-validation infoset has the canonical lexical representation of the {value constraint} value as the item's [schema normalized value] property.
2994         if (fCurrentElemDecl != null
2995             && fCurrentElemDecl.fDefault != null
2996             && !fSawText
2997             && !fSubElement
2998             && !fNil) {
2999 
3000             String strv = fCurrentElemDecl.fDefault.stringValue();
3001             int bufLen = strv.length();
3002             if (fNormalizedStr.ch == null || fNormalizedStr.ch.length < bufLen) {
3003                 fNormalizedStr.ch = new char[bufLen];
3004             }
3005             strv.getChars(0, bufLen, fNormalizedStr.ch, 0);
3006             fNormalizedStr.offset = 0;
3007             fNormalizedStr.length = bufLen;
3008             fDefaultValue = fNormalizedStr;
3009         }
3010         // fixed values are handled later, after xsi:type determined.
3011 
3012         fValidatedInfo.normalizedValue = null;
3013 
3014         // Element Locally Valid (Element)
3015         // 3.2.1 The element information item must have no character or element information item [children].
3016         if (fNil) {
3017             if (fSubElement || fSawText) {
3018                 reportSchemaError(
3019                     "cvc-elt.3.2.1",
3020                     new Object[] {
3021                         element.rawname,
3022                         SchemaSymbols.URI_XSI + "," + SchemaSymbols.XSI_NIL });
3023             }
3024         }
3025 
3026         this.fValidatedInfo.reset();
3027 
3028         // 5 The appropriate case among the following must be true:
3029         // 5.1 If the declaration has a {value constraint}, the item has neither element nor character [children] and clause 3.2 has not applied, then all of the following must be true:
3030         if (fCurrentElemDecl != null
3031             && fCurrentElemDecl.getConstraintType() != XSConstants.VC_NONE
3032             && !fSubElement
3033             && !fSawText
3034             && !fNil) {
3035             // 5.1.1 If the actual type definition is a local type definition then the canonical lexical representation of the {value constraint} value must be a valid default for the actual type definition as defined in Element Default Valid (Immediate) (3.3.6).
3036             if (fCurrentType != fCurrentElemDecl.fType) {
3037                 //REVISIT:we should pass ValidatedInfo here.
3038                 if (XSConstraints
3039                     .ElementDefaultValidImmediate(
3040                         fCurrentType,
3041                         fCurrentElemDecl.fDefault.stringValue(),
3042                         fState4XsiType,
3043                         null)
3044                     == null)
3045                     reportSchemaError(
3046                         "cvc-elt.5.1.1",
3047                         new Object[] {
3048                             element.rawname,
3049                             fCurrentType.getName(),
3050                             fCurrentElemDecl.fDefault.stringValue()});
3051             }
3052             // 5.1.2 The element information item with the canonical lexical representation of the {value constraint} value used as its normalized value must be valid with respect to the actual type definition as defined by Element Locally Valid (Type) (3.3.4).
3053             // REVISIT: don't use toString, but validateActualValue instead
3054             //          use the fState4ApplyDefault
3055             elementLocallyValidType(element, fCurrentElemDecl.fDefault.stringValue());
3056         } else {
3057             // The following method call also deal with clause 1.2.2 of the constraint
3058             // Validation Rule: Schema-Validity Assessment (Element)
3059 
3060             // 5.2 If the declaration has no {value constraint} or the item has either element or character [children] or clause 3.2 has applied, then all of the following must be true:
3061             // 5.2.1 The element information item must be valid with respect to the actual type definition as defined by Element Locally Valid (Type) (3.3.4).
3062             Object actualValue = elementLocallyValidType(element, fBuffer);
3063             // 5.2.2 If there is a fixed {value constraint} and clause 3.2 has not applied, all of the following must be true:
3064             if (fCurrentElemDecl != null
3065                 && fCurrentElemDecl.getConstraintType() == XSConstants.VC_FIXED
3066                 && !fNil) {
3067                 String content = fBuffer.toString();
3068                 // 5.2.2.1 The element information item must have no element information item [children].
3069                 if (fSubElement)
3070                     reportSchemaError("cvc-elt.5.2.2.1", new Object[] { element.rawname });
3071                 // 5.2.2.2 The appropriate case among the following must be true:
3072                 if (fCurrentType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) {
3073                     XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType;
3074                     // 5.2.2.2.1 If the {content type} of the actual type definition is mixed, then the initial value of the item must match the canonical lexical representation of the {value constraint} value.
3075                     if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_MIXED) {
3076                         // REVISIT: how to get the initial value, does whiteSpace count?
3077                         if (!fCurrentElemDecl.fDefault.normalizedValue.equals(content))
3078                             reportSchemaError(
3079                                 "cvc-elt.5.2.2.2.1",
3080                                 new Object[] {
3081                                     element.rawname,
3082                                     content,
3083                                     fCurrentElemDecl.fDefault.normalizedValue });
3084                     }
3085                     // 5.2.2.2.2 If the {content type} of the actual type definition is a simple type definition, then the actual value of the item must match the canonical lexical representation of the {value constraint} value.
3086                     else if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_SIMPLE) {
3087                         if (actualValue != null && (!isComparable(fValidatedInfo, fCurrentElemDecl.fDefault)
3088                                 || !actualValue.equals(fCurrentElemDecl.fDefault.actualValue))) {
3089                             reportSchemaError(
3090                                 "cvc-elt.5.2.2.2.2",
3091                                 new Object[] {
3092                                     element.rawname,
3093                                     content,
3094                                     fCurrentElemDecl.fDefault.stringValue()});
3095                         }
3096                     }
3097                 } else if (fCurrentType.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) {
3098                     if (actualValue != null && (!isComparable(fValidatedInfo, fCurrentElemDecl.fDefault)
3099                             || !actualValue.equals(fCurrentElemDecl.fDefault.actualValue))) {
3100                         // REVISIT: the spec didn't mention this case: fixed
3101                         //          value with simple type
3102                         reportSchemaError(
3103                             "cvc-elt.5.2.2.2.2",
3104                             new Object[] {
3105                                 element.rawname,
3106                                 content,
3107                                 fCurrentElemDecl.fDefault.stringValue()});
3108                     }
3109                 }
3110             }
3111         }
3112 
3113         if (fDefaultValue == null && fNormalizeData && fDocumentHandler != null && fUnionType) {
3114             // for union types we need to send data because we delayed sending
3115             // this data when we received it in the characters() call.
3116             String content = fValidatedInfo.normalizedValue;
3117             if (content == null)
3118                 content = fBuffer.toString();
3119 
3120             int bufLen = content.length();
3121             if (fNormalizedStr.ch == null || fNormalizedStr.ch.length < bufLen) {
3122                 fNormalizedStr.ch = new char[bufLen];
3123             }
3124             content.getChars(0, bufLen, fNormalizedStr.ch, 0);
3125             fNormalizedStr.offset = 0;
3126             fNormalizedStr.length = bufLen;
3127             fDocumentHandler.characters(fNormalizedStr, null);
3128         }
3129     } // processElementContent
3130 
3131     Object elementLocallyValidType(QName element, Object textContent) {
3132         if (fCurrentType == null)
3133             return null;
3134 
3135         Object retValue = null;
3136         // Element Locally Valid (Type)
3137         // 3 The appropriate case among the following must be true:
3138         // 3.1 If the type definition is a simple type definition, then all of the following must be true:
3139         if (fCurrentType.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) {
3140             // 3.1.2 The element information item must have no element information item [children].
3141             if (fSubElement)
3142                 reportSchemaError("cvc-type.3.1.2", new Object[] { element.rawname });
3143             // 3.1.3 If clause 3.2 of Element Locally Valid (Element) (3.3.4) did not apply, then the normalized value must be valid with respect to the type definition as defined by String Valid (3.14.4).
3144             if (!fNil) {
3145                 XSSimpleType dv = (XSSimpleType) fCurrentType;
3146                 try {
3147                     if (!fNormalizeData || fUnionType) {
3148                         fValidationState.setNormalizationRequired(true);
3149                     }
3150                     retValue = dv.validate(textContent, fValidationState, fValidatedInfo);
3151                 } catch (InvalidDatatypeValueException e) {
3152                     reportSchemaError(e.getKey(), e.getArgs());
3153                     reportSchemaError(
3154                         "cvc-type.3.1.3",
3155                         new Object[] { element.rawname, textContent });
3156                 }
3157             }
3158         } else {
3159             // 3.2 If the type definition is a complex type definition, then the element information item must be valid with respect to the type definition as per Element Locally Valid (Complex Type) (3.4.4);
3160             retValue = elementLocallyValidComplexType(element, textContent);
3161         }
3162 
3163         return retValue;
3164     } // elementLocallyValidType
3165 
3166     Object elementLocallyValidComplexType(QName element, Object textContent) {
3167         Object actualValue = null;
3168         XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType;
3169 
3170         // Element Locally Valid (Complex Type)
3171         // For an element information item to be locally valid with respect to a complex type definition all of the following must be true:
3172         // 1 {abstract} is false.
3173         // 2 If clause 3.2 of Element Locally Valid (Element) (3.3.4) did not apply, then the appropriate case among the following must be true:
3174         if (!fNil) {
3175             // 2.1 If the {content type} is empty, then the element information item has no character or element information item [children].
3176             if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_EMPTY
3177                 && (fSubElement || fSawText)) {
3178                 reportSchemaError("cvc-complex-type.2.1", new Object[] { element.rawname });
3179             }
3180             // 2.2 If the {content type} is a simple type definition, then the element information item has no element information item [children], and the normalized value of the element information item is valid with respect to that simple type definition as defined by String Valid (3.14.4).
3181             else if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_SIMPLE) {
3182                 if (fSubElement)
3183                     reportSchemaError("cvc-complex-type.2.2", new Object[] { element.rawname });
3184                 XSSimpleType dv = ctype.fXSSimpleType;
3185                 try {
3186                     if (!fNormalizeData || fUnionType) {
3187                         fValidationState.setNormalizationRequired(true);
3188                     }
3189                     actualValue = dv.validate(textContent, fValidationState, fValidatedInfo);
3190                 } catch (InvalidDatatypeValueException e) {
3191                     reportSchemaError(e.getKey(), e.getArgs());
3192                     reportSchemaError("cvc-complex-type.2.2", new Object[] { element.rawname });
3193                 }
3194                 // REVISIT: eventually, this method should return the same actualValue as elementLocallyValidType...
3195                 // obviously it'll return null when the content is complex.
3196             }
3197             // 2.3 If the {content type} is element-only, then the element information item has no character information item [children] other than those whose [character code] is defined as a white space in [XML 1.0 (Second Edition)].
3198             else if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_ELEMENT) {
3199                 if (fSawCharacters) {
3200                     reportSchemaError("cvc-complex-type.2.3", new Object[] { element.rawname });
3201                 }
3202             }
3203             // 2.4 If the {content type} is element-only or mixed, then the sequence of the element information item's element information item [children], if any, taken in order, is valid with respect to the {content type}'s particle, as defined in Element Sequence Locally Valid (Particle) (3.9.4).
3204             if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_ELEMENT
3205                 || ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_MIXED) {
3206                 // if the current state is a valid state, check whether
3207                 // it's one of the final states.
3208                 if (DEBUG) {
3209                     System.out.println(fCurrCMState);
3210                 }
3211                 if (fCurrCMState[0] >= 0 && !fCurrentCM.endContentModel(fCurrCMState)) {
3212                     String expected = expectedStr(fCurrentCM.whatCanGoHere(fCurrCMState));
3213                     reportSchemaError(
3214                         "cvc-complex-type.2.4.b",
3215                         new Object[] { element.rawname, expected });
3216                 } else {
3217                     // Constant space algorithm for a{n,m} for n > 1 and m <= unbounded
3218                     // After the DFA has completed, check minOccurs and maxOccurs
3219                     // for all elements and wildcards in this content model where
3220                     // a{n,m} is subsumed to a* or a+
3221                     ArrayList errors = fCurrentCM.checkMinMaxBounds();
3222                     if (errors != null) {
3223                         for (int i = 0; i < errors.size(); i += 2) {
3224                             reportSchemaError(
3225                                 (String) errors.get(i),
3226                                 new Object[] { element.rawname, errors.get(i + 1) });
3227                         }
3228                     }
3229                 }
3230              }
3231         }
3232         return actualValue;
3233     } // elementLocallyValidComplexType
3234 
3235     void reportSchemaError(String key, Object[] arguments) {
3236         if (fDoValidation)
3237             fXSIErrorReporter.reportError(
3238                 XSMessageFormatter.SCHEMA_DOMAIN,
3239                 key,
3240                 arguments,
3241                 XMLErrorReporter.SEVERITY_ERROR);
3242     }
3243 
3244     /** Returns true if the two ValidatedInfo objects can be compared in the same value space. **/
3245     private boolean isComparable(ValidatedInfo info1, ValidatedInfo info2) {
3246         final short primitiveType1 = convertToPrimitiveKind(info1.actualValueType);
3247         final short primitiveType2 = convertToPrimitiveKind(info2.actualValueType);
3248         if (primitiveType1 != primitiveType2) {
3249             return (primitiveType1 == XSConstants.ANYSIMPLETYPE_DT && primitiveType2 == XSConstants.STRING_DT ||
3250                     primitiveType1 == XSConstants.STRING_DT && primitiveType2 == XSConstants.ANYSIMPLETYPE_DT);
3251         }
3252         else if (primitiveType1 == XSConstants.LIST_DT || primitiveType1 == XSConstants.LISTOFUNION_DT) {
3253             final ShortList typeList1 = info1.itemValueTypes;
3254             final ShortList typeList2 = info2.itemValueTypes;
3255             final int typeList1Length = typeList1 != null ? typeList1.getLength() : 0;
3256             final int typeList2Length = typeList2 != null ? typeList2.getLength() : 0;
3257             if (typeList1Length != typeList2Length) {
3258                 return false;
3259             }
3260             for (int i = 0; i < typeList1Length; ++i) {
3261                 final short primitiveItem1 = convertToPrimitiveKind(typeList1.item(i));
3262                 final short primitiveItem2 = convertToPrimitiveKind(typeList2.item(i));
3263                 if (primitiveItem1 != primitiveItem2) {
3264                     if (primitiveItem1 == XSConstants.ANYSIMPLETYPE_DT && primitiveItem2 == XSConstants.STRING_DT ||
3265                         primitiveItem1 == XSConstants.STRING_DT && primitiveItem2 == XSConstants.ANYSIMPLETYPE_DT) {
3266                         continue;
3267                     }
3268                     return false;
3269                 }
3270             }
3271         }
3272         return true;
3273     }
3274 
3275     private short convertToPrimitiveKind(short valueType) {
3276         /** Primitive datatypes. */
3277         if (valueType <= XSConstants.NOTATION_DT) {
3278             return valueType;
3279         }
3280         /** Types derived from string. */
3281         if (valueType <= XSConstants.ENTITY_DT) {
3282             return XSConstants.STRING_DT;
3283         }
3284         /** Types derived from decimal. */
3285         if (valueType <= XSConstants.POSITIVEINTEGER_DT) {
3286             return XSConstants.DECIMAL_DT;
3287         }
3288         /** Other types. */
3289         return valueType;
3290     }
3291 
3292     private String expectedStr(Vector expected) {
3293         StringBuffer ret = new StringBuffer("{");
3294         int size = expected.size();
3295         for (int i = 0; i < size; i++) {
3296             if (i > 0)
3297                 ret.append(", ");
3298             ret.append(expected.elementAt(i).toString());
3299         }
3300         ret.append('}');
3301         return ret.toString();
3302     }
3303 
3304     /**********************************/
3305 
3306     // xpath matcher information
3307 
3308     /**
3309      * Stack of XPath matchers for identity constraints.
3310      *
3311      * @author Andy Clark, IBM
3312      */
3313     protected static class XPathMatcherStack {
3314 
3315         //
3316         // Data
3317         //
3318 
3319         /** Active matchers. */
3320         protected XPathMatcher[] fMatchers = new XPathMatcher[4];
3321 
3322         /** Count of active matchers. */
3323         protected int fMatchersCount;
3324 
3325         /** Offset stack for contexts. */
3326         protected IntStack fContextStack = new IntStack();
3327 
3328         //
3329         // Constructors
3330         //
3331 
3332         public XPathMatcherStack() {
3333         } // <init>()
3334 
3335         //
3336         // Public methods
3337         //
3338 
3339         /** Resets the XPath matcher stack. */
3340         public void clear() {
3341             for (int i = 0; i < fMatchersCount; i++) {
3342                 fMatchers[i] = null;
3343             }
3344             fMatchersCount = 0;
3345             fContextStack.clear();
3346         } // clear()
3347 
3348         /** Returns the size of the stack. */
3349         public int size() {
3350             return fContextStack.size();
3351         } // size():int
3352 
3353         /** Returns the count of XPath matchers. */
3354         public int getMatcherCount() {
3355             return fMatchersCount;
3356         } // getMatcherCount():int
3357 
3358         /** Adds a matcher. */
3359         public void addMatcher(XPathMatcher matcher) {
3360             ensureMatcherCapacity();
3361             fMatchers[fMatchersCount++] = matcher;
3362         } // addMatcher(XPathMatcher)
3363 
3364         /** Returns the XPath matcher at the specified index. */
3365         public XPathMatcher getMatcherAt(int index) {
3366             return fMatchers[index];
3367         } // getMatcherAt(index):XPathMatcher
3368 
3369         /** Pushes a new context onto the stack. */
3370         public void pushContext() {
3371             fContextStack.push(fMatchersCount);
3372         } // pushContext()
3373 
3374         /** Pops a context off of the stack. */
3375         public void popContext() {
3376             fMatchersCount = fContextStack.pop();
3377         } // popContext()
3378 
3379         //
3380         // Private methods
3381         //
3382 
3383         /** Ensures the size of the matchers array. */
3384         private void ensureMatcherCapacity() {
3385             if (fMatchersCount == fMatchers.length) {
3386                 XPathMatcher[] array = new XPathMatcher[fMatchers.length * 2];
3387                 System.arraycopy(fMatchers, 0, array, 0, fMatchers.length);
3388                 fMatchers = array;
3389             }
3390         } // ensureMatcherCapacity()
3391 
3392     } // class XPathMatcherStack
3393 
3394     // value store implementations
3395 
3396     /**
3397      * Value store implementation base class. There are specific subclasses
3398      * for handling unique, key, and keyref.
3399      *
3400      * @author Andy Clark, IBM
3401      */
3402     protected abstract class ValueStoreBase implements ValueStore {
3403 
3404         //
3405         // Data
3406         //
3407 
3408         /** Identity constraint. */
3409         protected IdentityConstraint fIdentityConstraint;
3410         protected int fFieldCount = 0;
3411         protected Field[] fFields = null;
3412         /** current data */
3413         protected Object[] fLocalValues = null;
3414         protected short[] fLocalValueTypes = null;
3415         protected ShortList[] fLocalItemValueTypes = null;
3416 
3417         /** Current data value count. */
3418         protected int fValuesCount;
3419 
3420         /** global data */
3421         public final Vector fValues = new Vector();
3422         public ShortVector fValueTypes = null;
3423         public Vector fItemValueTypes = null;
3424 
3425         private boolean fUseValueTypeVector = false;
3426         private int fValueTypesLength = 0;
3427         private short fValueType = 0;
3428 
3429         private boolean fUseItemValueTypeVector = false;
3430         private int fItemValueTypesLength = 0;
3431         private ShortList fItemValueType = null;
3432 
3433         /** buffer for error messages */
3434         final StringBuffer fTempBuffer = new StringBuffer();
3435 
3436         //
3437         // Constructors
3438         //
3439 
3440         /** Constructs a value store for the specified identity constraint. */
3441         protected ValueStoreBase(IdentityConstraint identityConstraint) {
3442             fIdentityConstraint = identityConstraint;
3443             fFieldCount = fIdentityConstraint.getFieldCount();
3444             fFields = new Field[fFieldCount];
3445             fLocalValues = new Object[fFieldCount];
3446             fLocalValueTypes = new short[fFieldCount];
3447             fLocalItemValueTypes = new ShortList[fFieldCount];
3448             for (int i = 0; i < fFieldCount; i++) {
3449                 fFields[i] = fIdentityConstraint.getFieldAt(i);
3450             }
3451         } // <init>(IdentityConstraint)
3452 
3453         //
3454         // Public methods
3455         //
3456 
3457         // destroys this ValueStore; useful when, for instance, a
3458         // locally-scoped ID constraint is involved.
3459         public void clear() {
3460             fValuesCount = 0;
3461             fUseValueTypeVector = false;
3462             fValueTypesLength = 0;
3463             fValueType = 0;
3464             fUseItemValueTypeVector = false;
3465             fItemValueTypesLength = 0;
3466             fItemValueType = null;
3467             fValues.setSize(0);
3468             if (fValueTypes != null) {
3469                 fValueTypes.clear();
3470             }
3471             if (fItemValueTypes != null) {
3472                 fItemValueTypes.setSize(0);
3473             }
3474         } // end clear():void
3475 
3476         // appends the contents of one ValueStore to those of us.
3477         public void append(ValueStoreBase newVal) {
3478             for (int i = 0; i < newVal.fValues.size(); i++) {
3479                 fValues.addElement(newVal.fValues.elementAt(i));
3480             }
3481         } // append(ValueStoreBase)
3482 
3483         /** Start scope for value store. */
3484         public void startValueScope() {
3485             fValuesCount = 0;
3486             for (int i = 0; i < fFieldCount; i++) {
3487                 fLocalValues[i] = null;
3488                 fLocalValueTypes[i] = 0;
3489                 fLocalItemValueTypes[i] = null;
3490             }
3491         } // startValueScope()
3492 
3493         /** Ends scope for value store. */
3494         public void endValueScope() {
3495 
3496             if (fValuesCount == 0) {
3497                 if (fIdentityConstraint.getCategory() == IdentityConstraint.IC_KEY) {
3498                     String code = "AbsentKeyValue";
3499                     String eName = fIdentityConstraint.getElementName();
3500                     String cName = fIdentityConstraint.getIdentityConstraintName();
3501                     reportSchemaError(code, new Object[] { eName, cName });
3502                 }
3503                 return;
3504             }
3505 
3506             // Validation Rule: Identity-constraint Satisfied
3507             // 4.2 If the {identity-constraint category} is key, then all of the following must be true:
3508             // 4.2.1 The target node set and the qualified node set are equal, that is, every member of the
3509             // target node set is also a member of the qualified node set and vice versa.
3510             //
3511             // If the IDC is a key check whether we have all the fields.
3512             if (fValuesCount != fFieldCount) {
3513                 if (fIdentityConstraint.getCategory() == IdentityConstraint.IC_KEY) {
3514                     String code = "KeyNotEnoughValues";
3515                     UniqueOrKey key = (UniqueOrKey) fIdentityConstraint;
3516                     String eName = fIdentityConstraint.getElementName();
3517                     String cName = key.getIdentityConstraintName();
3518                     reportSchemaError(code, new Object[] { eName, cName });
3519                 }
3520                 return;
3521             }
3522 
3523         } // endValueScope()
3524 
3525         // This is needed to allow keyref's to look for matched keys
3526         // in the correct scope.  Unique and Key may also need to
3527         // override this method for purposes of their own.
3528         // This method is called whenever the DocumentFragment
3529         // of an ID Constraint goes out of scope.
3530         public void endDocumentFragment() {
3531         } // endDocumentFragment():void
3532 
3533         /**
3534          * Signals the end of the document. This is where the specific
3535          * instances of value stores can verify the integrity of the
3536          * identity constraints.
3537          */
3538         public void endDocument() {
3539         } // endDocument()
3540 
3541         //
3542         // ValueStore methods
3543         //
3544 
3545         /* reports an error if an element is matched
3546          * has nillable true and is matched by a key.
3547          */
3548 
3549         public void reportError(String key, Object[] args) {
3550             reportSchemaError(key, args);
3551         } // reportError(String,Object[])
3552 
3553         /**
3554          * Adds the specified value to the value store.
3555          *
3556          * @param field The field associated to the value. This reference
3557          *              is used to ensure that each field only adds a value
3558          *              once within a selection scope.
3559          * @param actualValue The value to add.
3560          */
3561         public void addValue(Field field, Object actualValue, short valueType, ShortList itemValueType) {
3562             int i;
3563             for (i = fFieldCount - 1; i > -1; i--) {
3564                 if (fFields[i] == field) {
3565                     break;
3566                 }
3567             }
3568             // do we even know this field?
3569             if (i == -1) {
3570                 String code = "UnknownField";
3571                 String eName = fIdentityConstraint.getElementName();
3572                 String cName = fIdentityConstraint.getIdentityConstraintName();
3573                 reportSchemaError(code, new Object[] { field.toString(), eName, cName });
3574                 return;
3575             }
3576             if (Boolean.TRUE != mayMatch(field)) {
3577                 String code = "FieldMultipleMatch";
3578                 String cName = fIdentityConstraint.getIdentityConstraintName();
3579                 reportSchemaError(code, new Object[] { field.toString(), cName });
3580             } else {
3581                 fValuesCount++;
3582             }
3583             fLocalValues[i] = actualValue;
3584             fLocalValueTypes[i] = valueType;
3585             fLocalItemValueTypes[i] = itemValueType;
3586             if (fValuesCount == fFieldCount) {
3587                 checkDuplicateValues();
3588                 // store values
3589                 for (i = 0; i < fFieldCount; i++) {
3590                     fValues.addElement(fLocalValues[i]);
3591                     addValueType(fLocalValueTypes[i]);
3592                     addItemValueType(fLocalItemValueTypes[i]);
3593                 }
3594             }
3595         } // addValue(String,Field)
3596 
3597         /**
3598          * Returns true if this value store contains the locally scoped value stores
3599          */
3600         public boolean contains() {
3601             // REVISIT: we can improve performance by using hash codes, instead of
3602             // traversing global vector that could be quite large.
3603             int next = 0;
3604             final int size = fValues.size();
3605             LOOP : for (int i = 0; i < size; i = next) {
3606                 next = i + fFieldCount;
3607                 for (int j = 0; j < fFieldCount; j++) {
3608                     Object value1 = fLocalValues[j];
3609                     Object value2 = fValues.elementAt(i);
3610                     short valueType1 = fLocalValueTypes[j];
3611                     short valueType2 = getValueTypeAt(i);
3612                     if (value1 == null || value2 == null || valueType1 != valueType2 || !(value1.equals(value2))) {
3613                         continue LOOP;
3614                     }
3615                     else if(valueType1 == XSConstants.LIST_DT || valueType1 == XSConstants.LISTOFUNION_DT) {
3616                         ShortList list1 = fLocalItemValueTypes[j];
3617                         ShortList list2 = getItemValueTypeAt(i);
3618                         if(list1 == null || list2 == null || !list1.equals(list2))
3619                             continue LOOP;
3620                     }
3621                     i++;
3622                 }
3623                 // found it
3624                 return true;
3625             }
3626             // didn't find it
3627             return false;
3628         } // contains():boolean
3629 
3630         /**
3631          * Returns -1 if this value store contains the specified
3632          * values, otherwise the index of the first field in the
3633          * key sequence.
3634          */
3635         public int contains(ValueStoreBase vsb) {
3636 
3637             final Vector values = vsb.fValues;
3638             final int size1 = values.size();
3639             if (fFieldCount <= 1) {
3640                 for (int i = 0; i < size1; ++i) {
3641                     short val = vsb.getValueTypeAt(i);
3642                     if (!valueTypeContains(val) || !fValues.contains(values.elementAt(i))) {
3643                         return i;
3644                     }
3645                     else if(val == XSConstants.LIST_DT || val == XSConstants.LISTOFUNION_DT) {
3646                         ShortList list1 = vsb.getItemValueTypeAt(i);
3647                         if (!itemValueTypeContains(list1)) {
3648                             return i;
3649                         }
3650                     }
3651                 }
3652             }
3653             /** Handle n-tuples. **/
3654             else {
3655                 final int size2 = fValues.size();
3656                 /** Iterate over each set of fields. **/
3657                 OUTER: for (int i = 0; i < size1; i += fFieldCount) {
3658                     /** Check whether this set is contained in the value store. **/
3659                     INNER: for (int j = 0; j < size2; j += fFieldCount) {
3660                         for (int k = 0; k < fFieldCount; ++k) {
3661                             final Object value1 = values.elementAt(i+k);
3662                             final Object value2 = fValues.elementAt(j+k);
3663                             final short valueType1 = vsb.getValueTypeAt(i+k);
3664                             final short valueType2 = getValueTypeAt(j+k);
3665                             if (value1 != value2 && (valueType1 != valueType2 || value1 == null || !value1.equals(value2))) {
3666                                 continue INNER;
3667                             }
3668                             else if(valueType1 == XSConstants.LIST_DT || valueType1 == XSConstants.LISTOFUNION_DT) {
3669                                 ShortList list1 = vsb.getItemValueTypeAt(i+k);
3670                                 ShortList list2 = getItemValueTypeAt(j+k);
3671                                 if (list1 == null || list2 == null || !list1.equals(list2)) {
3672                                     continue INNER;
3673                                 }
3674                             }
3675                         }
3676                         continue OUTER;
3677                     }
3678                     return i;
3679                 }
3680             }
3681             return -1;
3682 
3683         } // contains(Vector):Object
3684 
3685         //
3686         // Protected methods
3687         //
3688 
3689         protected void checkDuplicateValues() {
3690             // no-op
3691         } // duplicateValue(Hashtable)
3692 
3693         /** Returns a string of the specified values. */
3694         protected String toString(Object[] values) {
3695 
3696             // no values
3697             int size = values.length;
3698             if (size == 0) {
3699                 return "";
3700             }
3701 
3702             fTempBuffer.setLength(0);
3703 
3704             // construct value string
3705             for (int i = 0; i < size; i++) {
3706                 if (i > 0) {
3707                     fTempBuffer.append(',');
3708                 }
3709                 fTempBuffer.append(values[i]);
3710             }
3711             return fTempBuffer.toString();
3712 
3713         } // toString(Object[]):String
3714 
3715         /** Returns a string of the specified values. */
3716         protected String toString(Vector values, int start, int length) {
3717 
3718             // no values
3719             if (length == 0) {
3720                 return "";
3721             }
3722 
3723             // one value
3724             if (length == 1) {
3725                 return String.valueOf(values.elementAt(start));
3726             }
3727 
3728             // construct value string
3729             StringBuffer str = new StringBuffer();
3730             for (int i = 0; i < length; i++) {
3731                 if (i > 0) {
3732                     str.append(',');
3733                 }
3734                 str.append(values.elementAt(start + i));
3735             }
3736             return str.toString();
3737 
3738         } // toString(Vector,int,int):String
3739 
3740         //
3741         // Object methods
3742         //
3743 
3744         /** Returns a string representation of this object. */
3745         public String toString() {
3746             String s = super.toString();
3747             int index1 = s.lastIndexOf('$');
3748             if (index1 != -1) {
3749                 s = s.substring(index1 + 1);
3750             }
3751             int index2 = s.lastIndexOf('.');
3752             if (index2 != -1) {
3753                 s = s.substring(index2 + 1);
3754             }
3755             return s + '[' + fIdentityConstraint + ']';
3756         } // toString():String
3757 
3758         //
3759         // Private methods
3760         //
3761 
3762         private void addValueType(short type) {
3763             if (fUseValueTypeVector) {
3764                 fValueTypes.add(type);
3765             }
3766             else if (fValueTypesLength++ == 0) {
3767                 fValueType = type;
3768             }
3769             else if (fValueType != type) {
3770                 fUseValueTypeVector = true;
3771                 if (fValueTypes == null) {
3772                     fValueTypes = new ShortVector(fValueTypesLength * 2);
3773                 }
3774                 for (int i = 1; i < fValueTypesLength; ++i) {
3775                     fValueTypes.add(fValueType);
3776                 }
3777                 fValueTypes.add(type);
3778             }
3779         }
3780 
3781         private short getValueTypeAt(int index) {
3782             if (fUseValueTypeVector) {
3783                 return fValueTypes.valueAt(index);
3784             }
3785             return fValueType;
3786         }
3787 
3788         private boolean valueTypeContains(short value) {
3789             if (fUseValueTypeVector) {
3790                 return fValueTypes.contains(value);
3791             }
3792             return fValueType == value;
3793         }
3794 
3795         private void addItemValueType(ShortList itemValueType) {
3796             if (fUseItemValueTypeVector) {
3797                 fItemValueTypes.add(itemValueType);
3798             }
3799             else if (fItemValueTypesLength++ == 0) {
3800                 fItemValueType = itemValueType;
3801             }
3802             else if (!(fItemValueType == itemValueType ||
3803                     (fItemValueType != null && fItemValueType.equals(itemValueType)))) {
3804                 fUseItemValueTypeVector = true;
3805                 if (fItemValueTypes == null) {
3806                     fItemValueTypes = new Vector(fItemValueTypesLength * 2);
3807                 }
3808                 for (int i = 1; i < fItemValueTypesLength; ++i) {
3809                     fItemValueTypes.add(fItemValueType);
3810                 }
3811                 fItemValueTypes.add(itemValueType);
3812             }
3813         }
3814 
3815         private ShortList getItemValueTypeAt(int index) {
3816             if (fUseItemValueTypeVector) {
3817                 return (ShortList) fItemValueTypes.elementAt(index);
3818             }
3819             return fItemValueType;
3820         }
3821 
3822         private boolean itemValueTypeContains(ShortList value) {
3823             if (fUseItemValueTypeVector) {
3824                 return fItemValueTypes.contains(value);
3825             }
3826             return fItemValueType == value ||
3827                 (fItemValueType != null && fItemValueType.equals(value));
3828         }
3829 
3830     } // class ValueStoreBase
3831 
3832     /**
3833      * Unique value store.
3834      *
3835      * @author Andy Clark, IBM
3836      */
3837     protected class UniqueValueStore extends ValueStoreBase {
3838 
3839         //
3840         // Constructors
3841         //
3842 
3843         /** Constructs a unique value store. */
3844         public UniqueValueStore(UniqueOrKey unique) {
3845             super(unique);
3846         } // <init>(Unique)
3847 
3848         //
3849         // ValueStoreBase protected methods
3850         //
3851 
3852         /**
3853          * Called when a duplicate value is added.
3854          */
3855         protected void checkDuplicateValues() {
3856             // is this value as a group duplicated?
3857             if (contains()) {
3858                 String code = "DuplicateUnique";
3859                 String value = toString(fLocalValues);
3860                 String eName = fIdentityConstraint.getElementName();
3861                 String cName = fIdentityConstraint.getIdentityConstraintName();
3862                 reportSchemaError(code, new Object[] { value, eName, cName });
3863             }
3864         } // duplicateValue(Hashtable)
3865 
3866     } // class UniqueValueStore
3867 
3868     /**
3869      * Key value store.
3870      *
3871      * @author Andy Clark, IBM
3872      */
3873     protected class KeyValueStore extends ValueStoreBase {
3874 
3875         // REVISIT: Implement a more efficient storage mechanism. -Ac
3876 
3877         //
3878         // Constructors
3879         //
3880 
3881         /** Constructs a key value store. */
3882         public KeyValueStore(UniqueOrKey key) {
3883             super(key);
3884         } // <init>(Key)
3885 
3886         //
3887         // ValueStoreBase protected methods
3888         //
3889 
3890         /**
3891          * Called when a duplicate value is added.
3892          */
3893         protected void checkDuplicateValues() {
3894             if (contains()) {
3895                 String code = "DuplicateKey";
3896                 String value = toString(fLocalValues);
3897                 String eName = fIdentityConstraint.getElementName();
3898                 String cName = fIdentityConstraint.getIdentityConstraintName();
3899                 reportSchemaError(code, new Object[] { value, eName, cName });
3900             }
3901         } // duplicateValue(Hashtable)
3902 
3903     } // class KeyValueStore
3904 
3905     /**
3906      * Key reference value store.
3907      *
3908      * @author Andy Clark, IBM
3909      */
3910     protected class KeyRefValueStore extends ValueStoreBase {
3911 
3912         //
3913         // Data
3914         //
3915 
3916         /** Key value store. */
3917         protected ValueStoreBase fKeyValueStore;
3918 
3919         //
3920         // Constructors
3921         //
3922 
3923         /** Constructs a key value store. */
3924         public KeyRefValueStore(KeyRef keyRef, KeyValueStore keyValueStore) {
3925             super(keyRef);
3926             fKeyValueStore = keyValueStore;
3927         } // <init>(KeyRef)
3928 
3929         //
3930         // ValueStoreBase methods
3931         //
3932 
3933         // end the value Scope; here's where we have to tie
3934         // up keyRef loose ends.
3935         public void endDocumentFragment() {
3936 
3937             // do all the necessary management...
3938             super.endDocumentFragment();
3939 
3940             // verify references
3941             // get the key store corresponding (if it exists):
3942             fKeyValueStore =
3943                 (ValueStoreBase) fValueStoreCache.fGlobalIDConstraintMap.get(
3944                     ((KeyRef) fIdentityConstraint).getKey());
3945 
3946             if (fKeyValueStore == null) {
3947                 // report error
3948                 String code = "KeyRefOutOfScope";
3949                 String value = fIdentityConstraint.toString();
3950                 reportSchemaError(code, new Object[] { value });
3951                 return;
3952             }
3953             int errorIndex = fKeyValueStore.contains(this);
3954             if (errorIndex != -1) {
3955                 String code = "KeyNotFound";
3956                 String values = toString(fValues, errorIndex, fFieldCount);
3957                 String element = fIdentityConstraint.getElementName();
3958                 String name = fIdentityConstraint.getName();
3959                 reportSchemaError(code, new Object[] { name, values, element });
3960             }
3961 
3962         } // endDocumentFragment()
3963 
3964         /** End document. */
3965         public void endDocument() {
3966             super.endDocument();
3967 
3968         } // endDocument()
3969 
3970     } // class KeyRefValueStore
3971 
3972     // value store management
3973 
3974     /**
3975      * Value store cache. This class is used to store the values for
3976      * identity constraints.
3977      *
3978      * @author Andy Clark, IBM
3979      */
3980     protected class ValueStoreCache {
3981 
3982         //
3983         // Data
3984         //
3985         final LocalIDKey fLocalId = new LocalIDKey();
3986         // values stores
3987 
3988         /** stores all global Values stores. */
3989         protected final Vector fValueStores = new Vector();
3990 
3991         /**
3992          * Values stores associated to specific identity constraints.
3993          * This hashtable maps IdentityConstraints and
3994          * the 0-based element on which their selectors first matched to
3995          * a corresponding ValueStore.  This should take care
3996          * of all cases, including where ID constraints with
3997          * descendant-or-self axes occur on recursively-defined
3998          * elements.
3999          */
4000         protected final Hashtable fIdentityConstraint2ValueStoreMap = new Hashtable();
4001 
4002         // sketch of algorithm:
4003         // - when a constraint is first encountered, its
4004         //   values are stored in the (local) fIdentityConstraint2ValueStoreMap;
4005         // - Once it is validated (i.e., when it goes out of scope),
4006         //   its values are merged into the fGlobalIDConstraintMap;
4007         // - as we encounter keyref's, we look at the global table to
4008         //    validate them.
4009         //
4010         // The fGlobalIDMapStack has the following structure:
4011         // - validation always occurs against the fGlobalIDConstraintMap
4012         // (which comprises all the "eligible" id constraints);
4013         // When an endElement is found, this Hashtable is merged with the one
4014         // below in the stack.
4015         // When a start tag is encountered, we create a new
4016         // fGlobalIDConstraintMap.
4017         // i.e., the top of the fGlobalIDMapStack always contains
4018         // the preceding siblings' eligible id constraints;
4019         // the fGlobalIDConstraintMap contains descendants+self.
4020         // keyrefs can only match descendants+self.
4021         protected final Stack fGlobalMapStack = new Stack();
4022         protected final Hashtable fGlobalIDConstraintMap = new Hashtable();
4023 
4024         //
4025         // Constructors
4026         //
4027 
4028         /** Default constructor. */
4029         public ValueStoreCache() {
4030         } // <init>()
4031 
4032         //
4033         // Public methods
4034         //
4035 
4036         /** Resets the identity constraint cache. */
4037         public void startDocument() {
4038             fValueStores.removeAllElements();
4039             fIdentityConstraint2ValueStoreMap.clear();
4040             fGlobalIDConstraintMap.clear();
4041             fGlobalMapStack.removeAllElements();
4042         } // startDocument()
4043 
4044         // startElement:  pushes the current fGlobalIDConstraintMap
4045         // onto fGlobalMapStack and clears fGlobalIDConstraint map.
4046         public void startElement() {
4047             // only clone the hashtable when there are elements
4048             if (fGlobalIDConstraintMap.size() > 0)
4049                 fGlobalMapStack.push(fGlobalIDConstraintMap.clone());
4050             else
4051                 fGlobalMapStack.push(null);
4052             fGlobalIDConstraintMap.clear();
4053         } // startElement(void)
4054 
4055         /** endElement():  merges contents of fGlobalIDConstraintMap with the
4056          * top of fGlobalMapStack into fGlobalIDConstraintMap.
4057          */
4058         public void endElement() {
4059             if (fGlobalMapStack.isEmpty()) {
4060                 return; // must be an invalid doc!
4061             }
4062             Hashtable oldMap = (Hashtable) fGlobalMapStack.pop();
4063             // return if there is no element
4064             if (oldMap == null) {
4065                 return;
4066             }
4067 
4068             Iterator entries = oldMap.entrySet().iterator();
4069             while (entries.hasNext()) {
4070                 Map.Entry entry = (Map.Entry) entries.next();
4071                 IdentityConstraint id = (IdentityConstraint) entry.getKey();
4072                 ValueStoreBase oldVal = (ValueStoreBase) entry.getValue();
4073                 if (oldVal != null) {
4074                     ValueStoreBase currVal = (ValueStoreBase) fGlobalIDConstraintMap.get(id);
4075                     if (currVal == null) {
4076                         fGlobalIDConstraintMap.put(id, oldVal);
4077                     }
4078                     else if (currVal != oldVal) {
4079                         currVal.append(oldVal);
4080                     }
4081                 }
4082             }
4083         } // endElement()
4084 
4085         /**
4086          * Initializes the value stores for the specified element
4087          * declaration.
4088          */
4089         public void initValueStoresFor(XSElementDecl eDecl, FieldActivator activator) {
4090             // initialize value stores for unique fields
4091             IdentityConstraint[] icArray = eDecl.fIDConstraints;
4092             int icCount = eDecl.fIDCPos;
4093             for (int i = 0; i < icCount; i++) {
4094                 switch (icArray[i].getCategory()) {
4095                     case (IdentityConstraint.IC_UNIQUE) :
4096                         // initialize value stores for unique fields
4097                         UniqueOrKey unique = (UniqueOrKey) icArray[i];
4098                         LocalIDKey toHash = new LocalIDKey(unique, fElementDepth);
4099                         UniqueValueStore uniqueValueStore =
4100                             (UniqueValueStore) fIdentityConstraint2ValueStoreMap.get(toHash);
4101                         if (uniqueValueStore == null) {
4102                             uniqueValueStore = new UniqueValueStore(unique);
4103                             fIdentityConstraint2ValueStoreMap.put(toHash, uniqueValueStore);
4104                         } else {
4105                             uniqueValueStore.clear();
4106                         }
4107                         fValueStores.addElement(uniqueValueStore);
4108                         activateSelectorFor(icArray[i]);
4109                         break;
4110                     case (IdentityConstraint.IC_KEY) :
4111                         // initialize value stores for key fields
4112                         UniqueOrKey key = (UniqueOrKey) icArray[i];
4113                         toHash = new LocalIDKey(key, fElementDepth);
4114                         KeyValueStore keyValueStore =
4115                             (KeyValueStore) fIdentityConstraint2ValueStoreMap.get(toHash);
4116                         if (keyValueStore == null) {
4117                             keyValueStore = new KeyValueStore(key);
4118                             fIdentityConstraint2ValueStoreMap.put(toHash, keyValueStore);
4119                         } else {
4120                             keyValueStore.clear();
4121                         }
4122                         fValueStores.addElement(keyValueStore);
4123                         activateSelectorFor(icArray[i]);
4124                         break;
4125                     case (IdentityConstraint.IC_KEYREF) :
4126                         // initialize value stores for keyRef fields
4127                         KeyRef keyRef = (KeyRef) icArray[i];
4128                         toHash = new LocalIDKey(keyRef, fElementDepth);
4129                         KeyRefValueStore keyRefValueStore =
4130                             (KeyRefValueStore) fIdentityConstraint2ValueStoreMap.get(toHash);
4131                         if (keyRefValueStore == null) {
4132                             keyRefValueStore = new KeyRefValueStore(keyRef, null);
4133                             fIdentityConstraint2ValueStoreMap.put(toHash, keyRefValueStore);
4134                         } else {
4135                             keyRefValueStore.clear();
4136                         }
4137                         fValueStores.addElement(keyRefValueStore);
4138                         activateSelectorFor(icArray[i]);
4139                         break;
4140                 }
4141             }
4142         } // initValueStoresFor(XSElementDecl)
4143 
4144         /** Returns the value store associated to the specified IdentityConstraint. */
4145         public ValueStoreBase getValueStoreFor(IdentityConstraint id, int initialDepth) {
4146             fLocalId.fDepth = initialDepth;
4147             fLocalId.fId = id;
4148             return (ValueStoreBase) fIdentityConstraint2ValueStoreMap.get(fLocalId);
4149         } // getValueStoreFor(IdentityConstraint, int):ValueStoreBase
4150 
4151         /** Returns the global value store associated to the specified IdentityConstraint. */
4152         public ValueStoreBase getGlobalValueStoreFor(IdentityConstraint id) {
4153             return (ValueStoreBase) fGlobalIDConstraintMap.get(id);
4154         } // getValueStoreFor(IdentityConstraint):ValueStoreBase
4155 
4156         // This method takes the contents of the (local) ValueStore
4157         // associated with id and moves them into the global
4158         // hashtable, if id is a <unique> or a <key>.
4159         // If it's a <keyRef>, then we leave it for later.
4160         public void transplant(IdentityConstraint id, int initialDepth) {
4161             fLocalId.fDepth = initialDepth;
4162             fLocalId.fId = id;
4163             ValueStoreBase newVals =
4164                 (ValueStoreBase) fIdentityConstraint2ValueStoreMap.get(fLocalId);
4165             if (id.getCategory() == IdentityConstraint.IC_KEYREF)
4166                 return;
4167             ValueStoreBase currVals = (ValueStoreBase) fGlobalIDConstraintMap.get(id);
4168             if (currVals != null) {
4169                 currVals.append(newVals);
4170                 fGlobalIDConstraintMap.put(id, currVals);
4171             } else
4172                 fGlobalIDConstraintMap.put(id, newVals);
4173 
4174         } // transplant(id)
4175 
4176         /** Check identity constraints. */
4177         public void endDocument() {
4178 
4179             int count = fValueStores.size();
4180             for (int i = 0; i < count; i++) {
4181                 ValueStoreBase valueStore = (ValueStoreBase) fValueStores.elementAt(i);
4182                 valueStore.endDocument();
4183             }
4184 
4185         } // endDocument()
4186 
4187         //
4188         // Object methods
4189         //
4190 
4191         /** Returns a string representation of this object. */
4192         public String toString() {
4193             String s = super.toString();
4194             int index1 = s.lastIndexOf('$');
4195             if (index1 != -1) {
4196                 return s.substring(index1 + 1);
4197             }
4198             int index2 = s.lastIndexOf('.');
4199             if (index2 != -1) {
4200                 return s.substring(index2 + 1);
4201             }
4202             return s;
4203         } // toString():String
4204 
4205     } // class ValueStoreCache
4206 
4207     // the purpose of this class is to enable IdentityConstraint,int
4208     // pairs to be used easily as keys in Hashtables.
4209     protected class LocalIDKey {
4210 
4211         public IdentityConstraint fId;
4212         public int fDepth;
4213 
4214         public LocalIDKey() {
4215         }
4216 
4217         public LocalIDKey(IdentityConstraint id, int depth) {
4218             fId = id;
4219             fDepth = depth;
4220         } // init(IdentityConstraint, int)
4221 
4222         // object method
4223         public int hashCode() {
4224             return fId.hashCode() + fDepth;
4225         }
4226 
4227         public boolean equals(Object localIDKey) {
4228             if (localIDKey instanceof LocalIDKey) {
4229                 LocalIDKey lIDKey = (LocalIDKey) localIDKey;
4230                 return (lIDKey.fId == fId && lIDKey.fDepth == fDepth);
4231             }
4232             return false;
4233         }
4234     } // class LocalIDKey
4235 
4236     /**
4237      * A simple vector for <code>short</code>s.
4238      */
4239     protected static final class ShortVector {
4240 
4241         //
4242         // Data
4243         //
4244 
4245         /** Current length. */
4246         private int fLength;
4247 
4248         /** Data. */
4249         private short[] fData;
4250 
4251         //
4252         // Constructors
4253         //
4254 
4255         public ShortVector() {}
4256 
4257         public ShortVector(int initialCapacity) {
4258             fData = new short[initialCapacity];
4259         }
4260 
4261         //
4262         // Public methods
4263         //
4264 
4265         /** Returns the length of the vector. */
4266         public int length() {
4267             return fLength;
4268         }
4269 
4270         /** Adds the value to the vector. */
4271         public void add(short value) {
4272             ensureCapacity(fLength + 1);
4273             fData[fLength++] = value;
4274         }
4275 
4276         /** Returns the short value at the specified position in the vector. */
4277         public short valueAt(int position) {
4278             return fData[position];
4279         }
4280 
4281         /** Clears the vector. */
4282         public void clear() {
4283             fLength = 0;
4284         }
4285 
4286         /** Returns whether the short is contained in the vector. */
4287         public boolean contains(short value) {
4288             for (int i = 0; i < fLength; ++i) {
4289                 if (fData[i] == value) {
4290                     return true;
4291                 }
4292             }
4293             return false;
4294         }
4295 
4296         //
4297         // Private methods
4298         //
4299 
4300         /** Ensures capacity. */
4301         private void ensureCapacity(int size) {
4302             if (fData == null) {
4303                 fData = new short[8];
4304             }
4305             else if (fData.length <= size) {
4306                 short[] newdata = new short[fData.length * 2];
4307                 System.arraycopy(fData, 0, newdata, 0, fData.length);
4308                 fData = newdata;
4309             }
4310         }
4311     }
4312 
4313 } // class SchemaValidator