1 /*
   2  * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
   3  */
   4 /*
   5  * Licensed to the Apache Software Foundation (ASF) under one or more
   6  * contributor license agreements.  See the NOTICE file distributed with
   7  * this work for additional information regarding copyright ownership.
   8  * The ASF licenses this file to You under the Apache License, Version 2.0
   9  * (the "License"); you may not use this file except in compliance with
  10  * the License.  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 com.sun.org.apache.xerces.internal.dom.DOMErrorImpl;
  24 import com.sun.org.apache.xerces.internal.dom.DOMMessageFormatter;
  25 import com.sun.org.apache.xerces.internal.dom.DOMStringListImpl;
  26 import com.sun.org.apache.xerces.internal.impl.Constants;
  27 import com.sun.org.apache.xerces.internal.impl.XMLEntityManager;
  28 import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter;
  29 import com.sun.org.apache.xerces.internal.impl.dv.InvalidDatatypeValueException;
  30 import com.sun.org.apache.xerces.internal.impl.dv.SchemaDVFactory;
  31 import com.sun.org.apache.xerces.internal.impl.dv.xs.SchemaDVFactoryImpl;
  32 import com.sun.org.apache.xerces.internal.impl.xs.models.CMBuilder;
  33 import com.sun.org.apache.xerces.internal.impl.xs.models.CMNodeFactory;
  34 import com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler;
  35 import com.sun.org.apache.xerces.internal.util.DOMEntityResolverWrapper;
  36 import com.sun.org.apache.xerces.internal.util.DOMErrorHandlerWrapper;
  37 import com.sun.org.apache.xerces.internal.util.DefaultErrorHandler;
  38 import com.sun.org.apache.xerces.internal.util.ParserConfigurationSettings;
  39 import com.sun.org.apache.xerces.internal.util.Status;
  40 import com.sun.org.apache.xerces.internal.util.SymbolTable;
  41 import com.sun.org.apache.xerces.internal.util.XMLSymbols;
  42 import com.sun.org.apache.xerces.internal.utils.SecuritySupport;
  43 import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager;
  44 import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager;
  45 import com.sun.org.apache.xerces.internal.xni.XNIException;
  46 import com.sun.org.apache.xerces.internal.xni.grammars.Grammar;
  47 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarDescription;
  48 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarLoader;
  49 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarPool;
  50 import com.sun.org.apache.xerces.internal.xni.grammars.XSGrammar;
  51 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent;
  52 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
  53 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
  54 import com.sun.org.apache.xerces.internal.xni.parser.XMLEntityResolver;
  55 import com.sun.org.apache.xerces.internal.xni.parser.XMLErrorHandler;
  56 import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
  57 import com.sun.org.apache.xerces.internal.xs.LSInputList;
  58 import com.sun.org.apache.xerces.internal.xs.StringList;
  59 import com.sun.org.apache.xerces.internal.xs.XSLoader;
  60 import com.sun.org.apache.xerces.internal.xs.XSModel;
  61 import java.io.BufferedInputStream;
  62 import java.io.File;
  63 import java.io.FileInputStream;
  64 import java.io.FileNotFoundException;
  65 import java.io.IOException;
  66 import java.io.InputStream;
  67 import java.io.Reader;
  68 import java.io.StringReader;
  69 import java.util.HashMap;
  70 import java.util.Locale;
  71 import java.util.Map;
  72 import java.util.StringTokenizer;
  73 import java.util.Vector;
  74 import javax.xml.XMLConstants;
  75 import jdk.xml.internal.JdkXmlUtils;
  76 import org.w3c.dom.DOMConfiguration;
  77 import org.w3c.dom.DOMError;
  78 import org.w3c.dom.DOMErrorHandler;
  79 import org.w3c.dom.DOMException;
  80 import org.w3c.dom.DOMStringList;
  81 import org.w3c.dom.ls.LSInput;
  82 import org.w3c.dom.ls.LSResourceResolver;
  83 import org.xml.sax.InputSource;
  84 
  85 /**
  86  * This class implements xni.grammars.XMLGrammarLoader.
  87  * It also serves as implementation of xs.XSLoader interface and DOMConfiguration interface.
  88  *
  89  * This class is designed to interact either with a proxy for a user application
  90  * which wants to preparse schemas, or with our own Schema validator.
  91  * It is hoped that none of these "external" classes will therefore need to communicate directly
  92  * with XSDHandler in future.
  93  * <p>This class only knows how to make XSDHandler do its thing.
  94  * The caller must ensure that all its properties (schemaLocation, JAXPSchemaSource
  95  * etc.) have been properly set.
  96  *
  97  * @xerces.internal
  98  *
  99  * @author Neil Graham, IBM
 100  */
 101 
 102 public class XMLSchemaLoader implements XMLGrammarLoader, XMLComponent,
 103 // XML Component API
 104 XSLoader, DOMConfiguration {
 105 
 106     // Feature identifiers:
 107 
 108     /** Feature identifier: schema full checking*/
 109     protected static final String SCHEMA_FULL_CHECKING =
 110         Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_FULL_CHECKING;
 111 
 112     /** Feature identifier: continue after fatal error. */
 113     protected static final String CONTINUE_AFTER_FATAL_ERROR =
 114         Constants.XERCES_FEATURE_PREFIX + Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE;
 115 
 116     /** Feature identifier: allow java encodings to be recognized when parsing schema docs. */
 117     protected static final String ALLOW_JAVA_ENCODINGS =
 118         Constants.XERCES_FEATURE_PREFIX + Constants.ALLOW_JAVA_ENCODINGS_FEATURE;
 119 
 120     /** Feature identifier: standard uri conformant feature. */
 121     protected static final String STANDARD_URI_CONFORMANT_FEATURE =
 122         Constants.XERCES_FEATURE_PREFIX + Constants.STANDARD_URI_CONFORMANT_FEATURE;
 123 
 124     /** Feature identifier: validate annotations. */
 125     protected static final String VALIDATE_ANNOTATIONS =
 126         Constants.XERCES_FEATURE_PREFIX + Constants.VALIDATE_ANNOTATIONS_FEATURE;
 127 
 128     /** Feature: disallow doctype*/
 129     protected static final String DISALLOW_DOCTYPE =
 130         Constants.XERCES_FEATURE_PREFIX + Constants.DISALLOW_DOCTYPE_DECL_FEATURE;
 131 
 132     /** Feature: generate synthetic annotations */
 133     protected static final String GENERATE_SYNTHETIC_ANNOTATIONS =
 134         Constants.XERCES_FEATURE_PREFIX + Constants.GENERATE_SYNTHETIC_ANNOTATIONS_FEATURE;
 135 
 136     /** Feature identifier: honour all schemaLocations */
 137     protected static final String HONOUR_ALL_SCHEMALOCATIONS =
 138         Constants.XERCES_FEATURE_PREFIX + Constants.HONOUR_ALL_SCHEMALOCATIONS_FEATURE;
 139 
 140     protected static final String AUGMENT_PSVI =
 141         Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_AUGMENT_PSVI;
 142 
 143     protected static final String PARSER_SETTINGS =
 144         Constants.XERCES_FEATURE_PREFIX + Constants.PARSER_SETTINGS;
 145 
 146     /** Feature identifier: namespace growth */
 147     protected static final String NAMESPACE_GROWTH =
 148         Constants.XERCES_FEATURE_PREFIX + Constants.NAMESPACE_GROWTH_FEATURE;
 149 
 150     /** Feature identifier: tolerate duplicates */
 151     protected static final String TOLERATE_DUPLICATES =
 152         Constants.XERCES_FEATURE_PREFIX + Constants.TOLERATE_DUPLICATES_FEATURE;
 153 
 154     /** Property identifier: Schema DV Factory */
 155     protected static final String SCHEMA_DV_FACTORY =
 156         Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_DV_FACTORY_PROPERTY;
 157 
 158     protected static final String OVERRIDE_PARSER = JdkXmlUtils.OVERRIDE_PARSER;
 159 
 160     // recognized features:
 161     private static final String[] RECOGNIZED_FEATURES = {
 162         SCHEMA_FULL_CHECKING,
 163         AUGMENT_PSVI,
 164         CONTINUE_AFTER_FATAL_ERROR,
 165         ALLOW_JAVA_ENCODINGS,
 166         STANDARD_URI_CONFORMANT_FEATURE,
 167         DISALLOW_DOCTYPE,
 168         GENERATE_SYNTHETIC_ANNOTATIONS,
 169         VALIDATE_ANNOTATIONS,
 170         HONOUR_ALL_SCHEMALOCATIONS,
 171         NAMESPACE_GROWTH,
 172         TOLERATE_DUPLICATES,
 173         OVERRIDE_PARSER
 174     };
 175 
 176     // property identifiers
 177 
 178     /** Property identifier: symbol table. */
 179     public static final String SYMBOL_TABLE =
 180         Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
 181 
 182     /** Property identifier: error reporter. */
 183     public static final String ERROR_REPORTER =
 184         Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY;
 185 
 186     /** Property identifier: error handler. */
 187     protected static final String ERROR_HANDLER =
 188         Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_HANDLER_PROPERTY;
 189 
 190     /** Property identifier: entity resolver. */
 191     public static final String ENTITY_RESOLVER =
 192         Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY;
 193 
 194     /** Property identifier: grammar pool. */
 195     public static final String XMLGRAMMAR_POOL =
 196         Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY;
 197 
 198     /** Property identifier: schema location. */
 199     protected static final String SCHEMA_LOCATION =
 200         Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_LOCATION;
 201 
 202     /** Property identifier: no namespace schema location. */
 203     protected static final String SCHEMA_NONS_LOCATION =
 204         Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_NONS_LOCATION;
 205 
 206     /** Property identifier: JAXP schema source. */
 207     protected static final String JAXP_SCHEMA_SOURCE =
 208         Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_SOURCE;
 209 
 210     protected static final String SECURITY_MANAGER =
 211         Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY;
 212 
 213     /** Property identifier: locale. */
 214     protected static final String LOCALE =
 215         Constants.XERCES_PROPERTY_PREFIX + Constants.LOCALE_PROPERTY;
 216 
 217     protected static final String ENTITY_MANAGER =
 218         Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY;
 219 
 220     /** Property identifier: Security property manager. */
 221     private static final String XML_SECURITY_PROPERTY_MANAGER =
 222             Constants.XML_SECURITY_PROPERTY_MANAGER;
 223 
 224     /** Property identifier: access to external dtd */
 225     public static final String ACCESS_EXTERNAL_DTD = XMLConstants.ACCESS_EXTERNAL_DTD;
 226 
 227     /** Property identifier: access to external schema */
 228     public static final String ACCESS_EXTERNAL_SCHEMA = XMLConstants.ACCESS_EXTERNAL_SCHEMA;
 229 
 230     // recognized properties
 231     private static final String [] RECOGNIZED_PROPERTIES = {
 232         ENTITY_MANAGER,
 233         SYMBOL_TABLE,
 234         ERROR_REPORTER,
 235         ERROR_HANDLER,
 236         ENTITY_RESOLVER,
 237         XMLGRAMMAR_POOL,
 238         SCHEMA_LOCATION,
 239         SCHEMA_NONS_LOCATION,
 240         JAXP_SCHEMA_SOURCE,
 241         SECURITY_MANAGER,
 242         LOCALE,
 243         SCHEMA_DV_FACTORY,
 244         XML_SECURITY_PROPERTY_MANAGER
 245     };
 246 
 247     // Data
 248 
 249     // features and properties
 250     private ParserConfigurationSettings fLoaderConfig = new ParserConfigurationSettings();
 251     private SymbolTable fSymbolTable = null;
 252     private XMLErrorReporter fErrorReporter = new XMLErrorReporter ();
 253     private XMLEntityManager fEntityManager = null;
 254     private XMLEntityResolver fUserEntityResolver = null;
 255     private XMLGrammarPool fGrammarPool = null;
 256     private String fExternalSchemas = null;
 257     private String fExternalNoNSSchema = null;
 258     // JAXP property: schema source
 259     private Object fJAXPSource = null;
 260     // is Schema Full Checking enabled
 261     private boolean fIsCheckedFully = false;
 262     // boolean that tells whether we've tested the JAXP property.
 263     private boolean fJAXPProcessed = false;
 264     // if features/properties has not been changed, the value of this attribute is "false"
 265     private boolean fSettingsChanged = true;
 266 
 267     // xml schema parsing
 268     private XSDHandler fSchemaHandler;
 269     private XSGrammarBucket fGrammarBucket;
 270     private XSDeclarationPool fDeclPool = null;
 271     private SubstitutionGroupHandler fSubGroupHandler;
 272     private final CMNodeFactory fNodeFactory = new CMNodeFactory(); //component mgr will be set later
 273     private CMBuilder fCMBuilder;
 274     private XSDDescription fXSDDescription = new XSDDescription();
 275     private String faccessExternalSchema = Constants.EXTERNAL_ACCESS_DEFAULT;
 276 
 277     private Map fJAXPCache;
 278     private Locale fLocale = Locale.getDefault();
 279 
 280     // XSLoader attributes
 281     private DOMStringList fRecognizedParameters = null;
 282 
 283     /** DOM L3 error handler */
 284     private DOMErrorHandlerWrapper fErrorHandler = null;
 285 
 286     /** DOM L3 resource resolver */
 287     private DOMEntityResolverWrapper fResourceResolver = null;
 288 
 289     // default constructor.  Create objects we absolutely need:
 290     public XMLSchemaLoader() {
 291         this( new SymbolTable(), null, new XMLEntityManager(), null, null, null);
 292     }
 293 
 294     public XMLSchemaLoader(SymbolTable symbolTable) {
 295         this( symbolTable, null, new XMLEntityManager(), null, null, null);
 296     }
 297 
 298     /**
 299      * This constractor is used by the XMLSchemaValidator. Additional properties, i.e. XMLEntityManager,
 300      * will be passed during reset(XMLComponentManager).
 301      * @param errorReporter
 302      * @param grammarBucket
 303      * @param sHandler
 304      * @param builder
 305      */
 306     XMLSchemaLoader(XMLErrorReporter errorReporter, XSGrammarBucket grammarBucket,
 307             SubstitutionGroupHandler sHandler, CMBuilder builder) {
 308         this(null, errorReporter, null, grammarBucket, sHandler, builder);
 309     }
 310 
 311     XMLSchemaLoader(SymbolTable symbolTable, XMLErrorReporter errorReporter,
 312             XMLEntityManager entityResolver, XSGrammarBucket grammarBucket,
 313             SubstitutionGroupHandler sHandler, CMBuilder builder) {
 314 
 315         // store properties and features in configuration
 316         fLoaderConfig.addRecognizedFeatures(RECOGNIZED_FEATURES);
 317         fLoaderConfig.addRecognizedProperties(RECOGNIZED_PROPERTIES);
 318         if (symbolTable != null){
 319             fLoaderConfig.setProperty(SYMBOL_TABLE, symbolTable);
 320         }
 321 
 322         if(errorReporter == null) {
 323             errorReporter = new XMLErrorReporter ();
 324             errorReporter.setLocale(fLocale);
 325             errorReporter.setProperty(ERROR_HANDLER, new DefaultErrorHandler());
 326 
 327         }
 328         fErrorReporter = errorReporter;
 329         // make sure error reporter knows about schemas...
 330         if(fErrorReporter.getMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN) == null) {
 331             fErrorReporter.putMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN, new XSMessageFormatter());
 332         }
 333         fLoaderConfig.setProperty(ERROR_REPORTER, fErrorReporter);
 334         fEntityManager = entityResolver;
 335         // entity manager is null if XMLSchemaValidator creates the loader
 336         if (fEntityManager != null){
 337             fLoaderConfig.setProperty(ENTITY_MANAGER, fEntityManager);
 338         }
 339 
 340         // by default augment PSVI (i.e. don't use declaration pool)
 341         fLoaderConfig.setFeature(AUGMENT_PSVI, true);
 342 
 343         if(grammarBucket == null ) {
 344             grammarBucket = new XSGrammarBucket();
 345         }
 346         fGrammarBucket = grammarBucket;
 347         if(sHandler == null) {
 348             sHandler = new SubstitutionGroupHandler(fGrammarBucket);
 349         }
 350         fSubGroupHandler = sHandler;
 351 
 352         if(builder == null) {
 353             builder = new CMBuilder(fNodeFactory);
 354         }
 355         fCMBuilder = builder;
 356         fSchemaHandler = new XSDHandler(fGrammarBucket);
 357         if (fDeclPool != null) {
 358             fDeclPool.reset();
 359         }
 360         fJAXPCache = new HashMap();
 361 
 362         fSettingsChanged = true;
 363     }
 364 
 365     /**
 366      * Returns a list of feature identifiers that are recognized by
 367      * this XMLGrammarLoader.  This method may return null if no features
 368      * are recognized.
 369      */
 370     public String[] getRecognizedFeatures() {
 371         return (String[])(RECOGNIZED_FEATURES.clone());
 372     } // getRecognizedFeatures():  String[]
 373 
 374     /**
 375      * Returns the state of a feature.
 376      *
 377      * @param featureId The feature identifier.
 378      *
 379      * @throws XMLConfigurationException Thrown on configuration error.
 380      */
 381     public boolean getFeature(String featureId)
 382     throws XMLConfigurationException {
 383         return fLoaderConfig.getFeature(featureId);
 384     } // getFeature (String):  boolean
 385 
 386     /**
 387      * Sets the state of a feature.
 388      *
 389      * @param featureId The feature identifier.
 390      * @param state     The state of the feature.
 391      *
 392      * @throws XMLConfigurationException Thrown when a feature is not
 393      *                  recognized or cannot be set.
 394      */
 395     public void setFeature(String featureId,
 396             boolean state) throws XMLConfigurationException {
 397         fSettingsChanged = true;
 398         if(featureId.equals(CONTINUE_AFTER_FATAL_ERROR)) {
 399             fErrorReporter.setFeature(CONTINUE_AFTER_FATAL_ERROR, state);
 400         }
 401         else if(featureId.equals(GENERATE_SYNTHETIC_ANNOTATIONS)) {
 402             fSchemaHandler.setGenerateSyntheticAnnotations(state);
 403         }
 404         fLoaderConfig.setFeature(featureId, state);
 405     } // setFeature(String, boolean)
 406 
 407     /**
 408      * Returns a list of property identifiers that are recognized by
 409      * this XMLGrammarLoader.  This method may return null if no properties
 410      * are recognized.
 411      */
 412     public String[] getRecognizedProperties() {
 413         return (String[])(RECOGNIZED_PROPERTIES.clone());
 414     } // getRecognizedProperties():  String[]
 415 
 416     /**
 417      * Returns the state of a property.
 418      *
 419      * @param propertyId The property identifier.
 420      *
 421      * @throws XMLConfigurationException Thrown on configuration error.
 422      */
 423     public Object getProperty(String propertyId)
 424     throws XMLConfigurationException {
 425         return fLoaderConfig.getProperty(propertyId);
 426     } // getProperty(String):  Object
 427 
 428     /**
 429      * Sets the state of a property.
 430      *
 431      * @param propertyId The property identifier.
 432      * @param state     The state of the property.
 433      *
 434      * @throws XMLConfigurationException Thrown when a property is not
 435      *                  recognized or cannot be set.
 436      */
 437     public void setProperty(String propertyId,
 438             Object state) throws XMLConfigurationException {
 439         fSettingsChanged = true;
 440         fLoaderConfig.setProperty(propertyId, state);
 441         if (propertyId.equals(JAXP_SCHEMA_SOURCE)) {
 442             fJAXPSource = state;
 443             fJAXPProcessed = false;
 444         }
 445         else if (propertyId.equals(XMLGRAMMAR_POOL)) {
 446             fGrammarPool = (XMLGrammarPool)state;
 447         }
 448         else if (propertyId.equals(SCHEMA_LOCATION)) {
 449             fExternalSchemas = (String)state;
 450         }
 451         else if (propertyId.equals(SCHEMA_NONS_LOCATION)) {
 452             fExternalNoNSSchema = (String) state;
 453         }
 454         else if (propertyId.equals(LOCALE)) {
 455             setLocale((Locale) state);
 456         }
 457         else if (propertyId.equals(ENTITY_RESOLVER)) {
 458             fEntityManager.setProperty(ENTITY_RESOLVER, state);
 459         }
 460         else if (propertyId.equals(ERROR_REPORTER)) {
 461             fErrorReporter = (XMLErrorReporter)state;
 462             if (fErrorReporter.getMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN) == null) {
 463                 fErrorReporter.putMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN, new XSMessageFormatter());
 464             }
 465         }
 466         else if (propertyId.equals(XML_SECURITY_PROPERTY_MANAGER)) {
 467             XMLSecurityPropertyManager spm = (XMLSecurityPropertyManager)state;
 468             faccessExternalSchema = spm.getValue(XMLSecurityPropertyManager.Property.ACCESS_EXTERNAL_SCHEMA);
 469         }
 470     } // setProperty(String, Object)
 471 
 472     /**
 473      * Set the locale to use for messages.
 474      *
 475      * @param locale The locale object to use for localization of messages.
 476      *
 477      * @exception XNIException Thrown if the parser does not support the
 478      *                         specified locale.
 479      */
 480     public void setLocale(Locale locale) {
 481         fLocale = locale;
 482         fErrorReporter.setLocale(locale);
 483     } // setLocale(Locale)
 484 
 485     /** Return the Locale the XMLGrammarLoader is using. */
 486     public Locale getLocale() {
 487         return fLocale;
 488     } // getLocale():  Locale
 489 
 490     /**
 491      * Sets the error handler.
 492      *
 493      * @param errorHandler The error handler.
 494      */
 495     public void setErrorHandler(XMLErrorHandler errorHandler) {
 496         fErrorReporter.setProperty(ERROR_HANDLER, errorHandler);
 497     } // setErrorHandler(XMLErrorHandler)
 498 
 499     /** Returns the registered error handler.  */
 500     public XMLErrorHandler getErrorHandler() {
 501         return fErrorReporter.getErrorHandler();
 502     } // getErrorHandler():  XMLErrorHandler
 503 
 504     /**
 505      * Sets the entity resolver.
 506      *
 507      * @param entityResolver The new entity resolver.
 508      */
 509     public void setEntityResolver(XMLEntityResolver entityResolver) {
 510         fUserEntityResolver = entityResolver;
 511         fLoaderConfig.setProperty(ENTITY_RESOLVER, entityResolver);
 512         fEntityManager.setProperty(ENTITY_RESOLVER, entityResolver);
 513     } // setEntityResolver(XMLEntityResolver)
 514 
 515     /** Returns the registered entity resolver.  */
 516     public XMLEntityResolver getEntityResolver() {
 517         return fUserEntityResolver;
 518     } // getEntityResolver():  XMLEntityResolver
 519 
 520     /**
 521      * Returns a Grammar object by parsing the contents of the
 522      * entities pointed to by sources.
 523      *
 524      * @param source[]  the locations of the entity which forms
 525      *                      the staring point of the grammars to be constructed
 526      * @throws IOException  when a problem is encounted reading the entity
 527      * @throws XNIException when a condition arises (such as a FatalError) that requires parsing
 528      *                          of the entity be terminated
 529      */
 530     public void loadGrammar(XMLInputSource source[])
 531     throws IOException, XNIException {
 532         int numSource = source.length;
 533         for (int i = 0; i < numSource; ++i) {
 534             loadGrammar(source[i]);
 535         }
 536     }
 537 
 538     /**
 539      * Returns a Grammar object by parsing the contents of the
 540      * entity pointed to by source.
 541      *
 542      * @param source        the location of the entity which forms
 543      *                          the starting point of the grammar to be constructed.
 544      * @throws IOException      When a problem is encountered reading the entity
 545      *          XNIException    When a condition arises (such as a FatalError) that requires parsing
 546      *                              of the entity be terminated.
 547      */
 548     public Grammar loadGrammar(XMLInputSource source)
 549     throws IOException, XNIException {
 550 
 551         // REVISIT: this method should have a namespace parameter specified by
 552         // user. In this case we can easily detect if a schema asked to be loaded
 553         // is already in the local cache.
 554 
 555         reset(fLoaderConfig);
 556         fSettingsChanged = false;
 557         XSDDescription desc = new XSDDescription();
 558         desc.fContextType = XSDDescription.CONTEXT_PREPARSE;
 559         desc.setBaseSystemId(source.getBaseSystemId());
 560         desc.setLiteralSystemId( source.getSystemId());
 561         // none of the other fields make sense for preparsing
 562         Map locationPairs = new HashMap();
 563         // Process external schema location properties.
 564         // We don't call tokenizeSchemaLocationStr here, because we also want
 565         // to check whether the values are valid URI.
 566         processExternalHints(fExternalSchemas, fExternalNoNSSchema,
 567                 locationPairs, fErrorReporter);
 568         SchemaGrammar grammar = loadSchema(desc, source, locationPairs);
 569 
 570         if(grammar != null && fGrammarPool != null) {
 571             fGrammarPool.cacheGrammars(XMLGrammarDescription.XML_SCHEMA, fGrammarBucket.getGrammars());
 572             // NOTE: we only need to verify full checking in case the schema was not provided via JAXP
 573             // since full checking already verified for all JAXP schemas
 574             if(fIsCheckedFully && fJAXPCache.get(grammar) != grammar) {
 575                 XSConstraints.fullSchemaChecking(fGrammarBucket, fSubGroupHandler, fCMBuilder, fErrorReporter);
 576             }
 577         }
 578         return grammar;
 579     } // loadGrammar(XMLInputSource):  Grammar
 580 
 581     /**
 582      * This method is called either from XMLGrammarLoader.loadGrammar or from XMLSchemaValidator.
 583      * Note: in either case, the EntityManager (or EntityResolvers) are not going to be invoked
 584      * to resolve the location of the schema in XSDDescription
 585      * @param desc
 586      * @param source
 587      * @param locationPairs
 588      * @return An XML Schema grammar
 589      * @throws IOException
 590      * @throws XNIException
 591      */
 592     SchemaGrammar loadSchema(XSDDescription desc, XMLInputSource source,
 593             Map<String, LocationArray> locationPairs) throws IOException, XNIException {
 594 
 595         // this should only be done once per invocation of this object;
 596         // unless application alters JAXPSource in the mean time.
 597         if(!fJAXPProcessed) {
 598             processJAXPSchemaSource(locationPairs);
 599         }
 600 
 601         if (desc.isExternal()) {
 602             String accessError = SecuritySupport.checkAccess(desc.getExpandedSystemId(), faccessExternalSchema, Constants.ACCESS_EXTERNAL_ALL);
 603             if (accessError != null) {
 604                 throw new XNIException(fErrorReporter.reportError(XSMessageFormatter.SCHEMA_DOMAIN,
 605                         "schema_reference.access",
 606                         new Object[] { SecuritySupport.sanitizePath(desc.getExpandedSystemId()), accessError }, XMLErrorReporter.SEVERITY_ERROR));
 607             }
 608         }
 609         SchemaGrammar grammar = fSchemaHandler.parseSchema(source, desc, locationPairs);
 610 
 611         return grammar;
 612     } // loadSchema(XSDDescription, XMLInputSource):  SchemaGrammar
 613 
 614     /** This method tries to resolve location of the given schema.
 615      * The loader stores the namespace/location pairs in a map (use "" as the
 616      * namespace of absent namespace). When resolving an entity, loader first tries
 617      * to find in the map whether there is a value for that namespace,
 618      * if so, pass that location value to the user-defined entity resolver.
 619      *
 620      * @param desc
 621      * @param locationPairs
 622      * @param entityResolver
 623      * @return
 624      * @throws IOException
 625      */
 626     public static XMLInputSource resolveDocument(XSDDescription desc,
 627             Map<String, LocationArray> locationPairs,
 628             XMLEntityResolver entityResolver) throws IOException {
 629         String loc = null;
 630         // we consider the schema location properties for import
 631         if (desc.getContextType() == XSDDescription.CONTEXT_IMPORT ||
 632                 desc.fromInstance()) {
 633             // use empty string as the key for absent namespace
 634             String namespace = desc.getTargetNamespace();
 635             String ns = namespace == null ? XMLSymbols.EMPTY_STRING : namespace;
 636             // get the location hint for that namespace
 637             LocationArray tempLA = locationPairs.get(ns);
 638             if(tempLA != null)
 639                 loc = tempLA.getFirstLocation();
 640         }
 641 
 642         // if it's not import, or if the target namespace is not set
 643         // in the schema location properties, use location hint
 644         if (loc == null) {
 645             String[] hints = desc.getLocationHints();
 646             if (hints != null && hints.length > 0)
 647                 loc = hints[0];
 648         }
 649 
 650         String expandedLoc = XMLEntityManager.expandSystemId(loc, desc.getBaseSystemId(), false);
 651         desc.setLiteralSystemId(loc);
 652         desc.setExpandedSystemId(expandedLoc);
 653         return entityResolver.resolveEntity(desc);
 654     }
 655 
 656     // add external schema locations to the location pairs
 657     public static void processExternalHints(String sl, String nsl,
 658             Map<String, XMLSchemaLoader.LocationArray> locations,
 659             XMLErrorReporter er) {
 660         if (sl != null) {
 661             try {
 662                 // get the attribute decl for xsi:schemaLocation
 663                 // because external schema location property has the same syntax
 664                 // as xsi:schemaLocation
 665                 XSAttributeDecl attrDecl = SchemaGrammar.SG_XSI.getGlobalAttributeDecl(SchemaSymbols.XSI_SCHEMALOCATION);
 666                 // validation the string value to get the list of URI's
 667                 attrDecl.fType.validate(sl, null, null);
 668                 if (!tokenizeSchemaLocationStr(sl, locations)) {
 669                     // report warning (odd number of items)
 670                     er.reportError(XSMessageFormatter.SCHEMA_DOMAIN,
 671                             "SchemaLocation",
 672                             new Object[]{sl},
 673                             XMLErrorReporter.SEVERITY_WARNING);
 674                 }
 675             }
 676             catch (InvalidDatatypeValueException ex) {
 677                 // report warning (not list of URI's)
 678                 er.reportError(XSMessageFormatter.SCHEMA_DOMAIN,
 679                         ex.getKey(), ex.getArgs(),
 680                         XMLErrorReporter.SEVERITY_WARNING);
 681             }
 682         }
 683 
 684         if (nsl != null) {
 685             try {
 686                 // similarly for no ns schema location property
 687                 XSAttributeDecl attrDecl = SchemaGrammar.SG_XSI.getGlobalAttributeDecl(SchemaSymbols.XSI_NONAMESPACESCHEMALOCATION);
 688                 attrDecl.fType.validate(nsl, null, null);
 689                 LocationArray la = ((LocationArray)locations.get(XMLSymbols.EMPTY_STRING));
 690                 if(la == null) {
 691                     la = new LocationArray();
 692                     locations.put(XMLSymbols.EMPTY_STRING, la);
 693                 }
 694                 la.addLocation(nsl);
 695             }
 696             catch (InvalidDatatypeValueException ex) {
 697                 // report warning (not a URI)
 698                 er.reportError(XSMessageFormatter.SCHEMA_DOMAIN,
 699                         ex.getKey(), ex.getArgs(),
 700                         XMLErrorReporter.SEVERITY_WARNING);
 701             }
 702         }
 703     }
 704     // this method takes a SchemaLocation string.
 705     // If an error is encountered, false is returned;
 706     // otherwise, true is returned.  In either case, locations
 707     // is augmented to include as many tokens as possible.
 708     // @param schemaStr     The schemaLocation string to tokenize
 709     // @param locations     HashMap mapping namespaces to LocationArray objects holding lists of locaitons
 710     // @return true if no problems; false if string could not be tokenized
 711     public static boolean tokenizeSchemaLocationStr(String schemaStr,
 712             Map<String, XMLSchemaLoader.LocationArray> locations) {
 713         if (schemaStr!= null) {
 714             StringTokenizer t = new StringTokenizer(schemaStr, " \n\t\r");
 715             String namespace, location;
 716             while (t.hasMoreTokens()) {
 717                 namespace = t.nextToken ();
 718                 if (!t.hasMoreTokens()) {
 719                     return false; // error!
 720                 }
 721                 location = t.nextToken();
 722                 LocationArray la = locations.get(namespace);
 723                 if(la == null) {
 724                     la = new LocationArray();
 725                     locations.put(namespace, la);
 726                 }
 727                 la.addLocation(location);
 728             }
 729         }
 730         return true;
 731     } // tokenizeSchemaLocation(String, HashMap):  boolean
 732 
 733     /**
 734      * Translate the various JAXP SchemaSource property types to XNI
 735      * XMLInputSource.  Valid types are: String, org.xml.sax.InputSource,
 736      * InputStream, File, or Object[] of any of previous types.
 737      * REVISIT:  the JAXP 1.2 spec is less than clear as to whether this property
 738      * should be available to imported schemas.  I have assumed
 739      * that it should.  - NG
 740      * Note: all JAXP schema files will be checked for full-schema validity if the feature was set up
 741      *
 742      */
 743     private void processJAXPSchemaSource(
 744             Map<String, LocationArray> locationPairs) throws IOException {
 745         fJAXPProcessed = true;
 746         if (fJAXPSource == null) {
 747             return;
 748         }
 749 
 750         Class componentType = fJAXPSource.getClass().getComponentType();
 751         XMLInputSource xis = null;
 752         String sid = null;
 753         if (componentType == null) {
 754             // Not an array
 755             if(fJAXPSource instanceof InputStream ||
 756                     fJAXPSource instanceof InputSource) {
 757                 SchemaGrammar g = (SchemaGrammar)fJAXPCache.get(fJAXPSource);
 758                 if(g != null) {
 759                     fGrammarBucket.putGrammar(g);
 760                     return;
 761                 }
 762             }
 763             fXSDDescription.reset();
 764             xis = xsdToXMLInputSource(fJAXPSource);
 765             sid = xis.getSystemId();
 766             fXSDDescription.fContextType = XSDDescription.CONTEXT_PREPARSE;
 767             if (sid != null) {
 768                 fXSDDescription.setBaseSystemId(xis.getBaseSystemId());
 769                 fXSDDescription.setLiteralSystemId(sid);
 770                 fXSDDescription.setExpandedSystemId(sid);
 771                 fXSDDescription.fLocationHints = new String[]{sid};
 772             }
 773             SchemaGrammar g = loadSchema(fXSDDescription, xis, locationPairs);
 774             // it is possible that we won't be able to resolve JAXP schema-source location
 775             if (g != null){
 776                 if(fJAXPSource instanceof InputStream ||
 777                         fJAXPSource instanceof InputSource) {
 778                     fJAXPCache.put(fJAXPSource, g);
 779                     if(fIsCheckedFully) {
 780                         XSConstraints.fullSchemaChecking(fGrammarBucket, fSubGroupHandler, fCMBuilder, fErrorReporter);
 781                     }
 782                 }
 783                 fGrammarBucket.putGrammar(g);
 784             }
 785             return ;
 786         } else if ( (componentType != Object.class) &&
 787                 (componentType != String.class) &&
 788                 (componentType != File.class) &&
 789                 (componentType != InputStream.class) &&
 790                 (componentType != InputSource.class)
 791         ) {
 792             // Not an Object[], String[], File[], InputStream[], InputSource[]
 793             throw new XMLConfigurationException(
 794                     Status.NOT_SUPPORTED, "\""+JAXP_SCHEMA_SOURCE+
 795                     "\" property cannot have an array of type {"+componentType.getName()+
 796                     "}. Possible types of the array supported are Object, String, File, "+
 797             "InputStream, InputSource.");
 798         }
 799 
 800         // JAXP spec. allow []s of type String, File, InputStream,
 801         // InputSource also, apart from [] of type Object.
 802         Object[] objArr = (Object[]) fJAXPSource;
 803         //make local vector for storing targetn namespaces of schemasources specified in object arrays.
 804         Vector jaxpSchemaSourceNamespaces = new Vector() ;
 805         for (int i = 0; i < objArr.length; i++) {
 806             if(objArr[i] instanceof InputStream ||
 807                     objArr[i] instanceof InputSource) {
 808                 SchemaGrammar g = (SchemaGrammar)fJAXPCache.get(objArr[i]);
 809                 if (g != null) {
 810                     fGrammarBucket.putGrammar(g);
 811                     continue;
 812                 }
 813             }
 814             fXSDDescription.reset();
 815             xis = xsdToXMLInputSource(objArr[i]);
 816             sid = xis.getSystemId();
 817             fXSDDescription.fContextType = XSDDescription.CONTEXT_PREPARSE;
 818             if (sid != null) {
 819                 fXSDDescription.setBaseSystemId(xis.getBaseSystemId());
 820                 fXSDDescription.setLiteralSystemId(sid);
 821                 fXSDDescription.setExpandedSystemId(sid);
 822                 fXSDDescription.fLocationHints = new String[]{sid};
 823             }
 824             String targetNamespace = null ;
 825             // load schema
 826             SchemaGrammar grammar = fSchemaHandler.parseSchema(xis,fXSDDescription, locationPairs);
 827 
 828             if(fIsCheckedFully) {
 829                 XSConstraints.fullSchemaChecking(fGrammarBucket, fSubGroupHandler, fCMBuilder, fErrorReporter);
 830             }
 831             if(grammar != null){
 832                 targetNamespace = grammar.getTargetNamespace() ;
 833                 if(jaxpSchemaSourceNamespaces.contains(targetNamespace)){
 834                     //when an array of objects is passed it is illegal to have two schemas that share same namespace.
 835                     throw new java.lang.IllegalArgumentException(
 836                             " When using array of Objects as the value of SCHEMA_SOURCE property , " +
 837                     "no two Schemas should share the same targetNamespace. " );
 838                 }
 839                 else{
 840                     jaxpSchemaSourceNamespaces.add(targetNamespace) ;
 841                 }
 842                 if(objArr[i] instanceof InputStream ||
 843                         objArr[i] instanceof InputSource) {
 844                     fJAXPCache.put(objArr[i], grammar);
 845                 }
 846                 fGrammarBucket.putGrammar(grammar);
 847             }
 848             else{
 849                 //REVISIT: What should be the acutal behavior if grammar can't be loaded as specified in schema source?
 850             }
 851         }
 852     }//processJAXPSchemaSource
 853 
 854     private XMLInputSource xsdToXMLInputSource(
 855             Object val)
 856     {
 857         if (val instanceof String) {
 858             // String value is treated as a URI that is passed through the
 859             // EntityResolver
 860             String loc = (String) val;
 861             fXSDDescription.reset();
 862             fXSDDescription.setValues(null, loc, null, null);
 863             XMLInputSource xis = null;
 864             try {
 865                 xis = fEntityManager.resolveEntity(fXSDDescription);
 866             } catch (IOException ex) {
 867                 fErrorReporter.reportError(XSMessageFormatter.SCHEMA_DOMAIN,
 868                         "schema_reference.4",
 869                         new Object[] { loc }, XMLErrorReporter.SEVERITY_ERROR);
 870             }
 871             if (xis == null) {
 872                 // REVISIT: can this happen?
 873                 // Treat value as a URI and pass in as systemId
 874                 return new XMLInputSource(null, loc, null);
 875             }
 876             return xis;
 877         } else if (val instanceof InputSource) {
 878             return saxToXMLInputSource((InputSource) val);
 879         } else if (val instanceof InputStream) {
 880             return new XMLInputSource(null, null, null,
 881                     (InputStream) val, null);
 882         } else if (val instanceof File) {
 883             File file = (File) val;
 884             InputStream is = null;
 885             try {
 886                 is = new BufferedInputStream(new FileInputStream(file));
 887             } catch (FileNotFoundException ex) {
 888                 fErrorReporter.reportError(XSMessageFormatter.SCHEMA_DOMAIN,
 889                         "schema_reference.4", new Object[] { file.toString() },
 890                         XMLErrorReporter.SEVERITY_ERROR);
 891             }
 892             return new XMLInputSource(null, null, null, is, null);
 893         }
 894         throw new XMLConfigurationException(
 895                 Status.NOT_SUPPORTED, "\""+JAXP_SCHEMA_SOURCE+
 896                 "\" property cannot have a value of type {"+val.getClass().getName()+
 897                 "}. Possible types of the value supported are String, File, InputStream, "+
 898         "InputSource OR an array of these types.");
 899     }
 900 
 901 
 902     //Convert a SAX InputSource to an equivalent XNI XMLInputSource
 903 
 904     private static XMLInputSource saxToXMLInputSource(InputSource sis) {
 905         String publicId = sis.getPublicId();
 906         String systemId = sis.getSystemId();
 907 
 908         Reader charStream = sis.getCharacterStream();
 909         if (charStream != null) {
 910             return new XMLInputSource(publicId, systemId, null, charStream,
 911                     null);
 912         }
 913 
 914         InputStream byteStream = sis.getByteStream();
 915         if (byteStream != null) {
 916             return new XMLInputSource(publicId, systemId, null, byteStream,
 917                     sis.getEncoding());
 918         }
 919 
 920         return new XMLInputSource(publicId, systemId, null);
 921     }
 922 
 923     public static class LocationArray{
 924 
 925         int length ;
 926         String [] locations = new String[2];
 927 
 928         public void resize(int oldLength , int newLength){
 929             String [] temp = new String[newLength] ;
 930             System.arraycopy(locations, 0, temp, 0, Math.min(oldLength, newLength));
 931             locations = temp ;
 932             length = Math.min(oldLength, newLength);
 933         }
 934 
 935         public void addLocation(String location){
 936             if(length >= locations.length ){
 937                 resize(length, Math.max(1, length*2));
 938             }
 939             locations[length++] = location;
 940         }//setLocation()
 941 
 942         public String [] getLocationArray(){
 943             if(length < locations.length ){
 944                 resize(locations.length, length);
 945             }
 946             return locations;
 947         }//getLocationArray()
 948 
 949         public String getFirstLocation(){
 950             return length > 0 ? locations[0] : null;
 951         }
 952 
 953         public int getLength(){
 954             return length ;
 955         }
 956 
 957     } //locationArray
 958 
 959     /* (non-Javadoc)
 960      * @see com.sun.org.apache.xerces.internal.xni.parser.XMLComponent#getFeatureDefault(java.lang.String)
 961      */
 962     public Boolean getFeatureDefault(String featureId) {
 963         if (featureId.equals(AUGMENT_PSVI)){
 964             return Boolean.TRUE;
 965         }
 966         return null;
 967     }
 968 
 969     /* (non-Javadoc)
 970      * @see com.sun.org.apache.xerces.internal.xni.parser.XMLComponent#getPropertyDefault(java.lang.String)
 971      */
 972     public Object getPropertyDefault(String propertyId) {
 973         // TODO Auto-generated method stub
 974         return null;
 975     }
 976 
 977     /* (non-Javadoc)
 978      * @see com.sun.org.apache.xerces.internal.xni.parser.XMLComponent#reset(com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager)
 979      */
 980     public void reset(XMLComponentManager componentManager) throws XMLConfigurationException {
 981 
 982         XMLSecurityPropertyManager spm = (XMLSecurityPropertyManager)componentManager.getProperty(XML_SECURITY_PROPERTY_MANAGER);
 983         if (spm == null) {
 984             spm = new XMLSecurityPropertyManager();
 985             setProperty(XML_SECURITY_PROPERTY_MANAGER, spm);
 986         }
 987 
 988         XMLSecurityManager sm = (XMLSecurityManager)componentManager.getProperty(SECURITY_MANAGER);
 989         if (sm == null)
 990             setProperty(SECURITY_MANAGER,new XMLSecurityManager(true));
 991 
 992         faccessExternalSchema = spm.getValue(XMLSecurityPropertyManager.Property.ACCESS_EXTERNAL_SCHEMA);
 993 
 994         fGrammarBucket.reset();
 995 
 996         fSubGroupHandler.reset();
 997 
 998         boolean parser_settings = componentManager.getFeature(PARSER_SETTINGS, true);
 999 
1000         if (!parser_settings || !fSettingsChanged){
1001             // need to reprocess JAXP schema sources
1002             fJAXPProcessed = false;
1003             // reinitialize grammar bucket
1004             initGrammarBucket();
1005             return;
1006         }
1007 
1008         //pass the component manager to the factory..
1009         fNodeFactory.reset(componentManager);
1010 
1011         // get registered entity manager to be able to resolve JAXP schema-source property:
1012         // Note: in case XMLSchemaValidator has created the loader,
1013         // the entity manager property is null
1014         fEntityManager = (XMLEntityManager)componentManager.getProperty(ENTITY_MANAGER);
1015 
1016         // get the error reporter
1017         fErrorReporter = (XMLErrorReporter)componentManager.getProperty(ERROR_REPORTER);
1018 
1019         // Determine schema dv factory to use
1020         SchemaDVFactory dvFactory = null;
1021         dvFactory = fSchemaHandler.getDVFactory();
1022         if (dvFactory == null) {
1023             dvFactory = SchemaDVFactory.getInstance();
1024             fSchemaHandler.setDVFactory(dvFactory);
1025         }
1026 
1027         boolean psvi = componentManager.getFeature(AUGMENT_PSVI, false);
1028 
1029         if (!psvi) {
1030             if (fDeclPool != null) {
1031                 fDeclPool.reset();
1032             }
1033             else {
1034                 fDeclPool = new XSDeclarationPool();
1035             }
1036             fCMBuilder.setDeclPool(fDeclPool);
1037             fSchemaHandler.setDeclPool(fDeclPool);
1038             if (dvFactory instanceof SchemaDVFactoryImpl) {
1039                 fDeclPool.setDVFactory((SchemaDVFactoryImpl)dvFactory);
1040                 ((SchemaDVFactoryImpl)dvFactory).setDeclPool(fDeclPool);
1041             }
1042         } else {
1043             fCMBuilder.setDeclPool(null);
1044             fSchemaHandler.setDeclPool(null);
1045         }
1046 
1047         // get schema location properties
1048         try {
1049             fExternalSchemas = (String) componentManager.getProperty(SCHEMA_LOCATION);
1050             fExternalNoNSSchema = (String) componentManager.getProperty(SCHEMA_NONS_LOCATION);
1051         } catch (XMLConfigurationException e) {
1052             fExternalSchemas = null;
1053             fExternalNoNSSchema = null;
1054         }
1055 
1056         // get JAXP sources if available
1057         fJAXPSource = componentManager.getProperty(JAXP_SCHEMA_SOURCE, null);
1058         fJAXPProcessed = false;
1059 
1060         // clear grammars, and put the one for schema namespace there
1061         fGrammarPool = (XMLGrammarPool) componentManager.getProperty(XMLGRAMMAR_POOL, null);
1062         initGrammarBucket();
1063         // get continue-after-fatal-error feature
1064         try {
1065             boolean fatalError = componentManager.getFeature(CONTINUE_AFTER_FATAL_ERROR, false);
1066             if (!fatalError) {
1067                 fErrorReporter.setFeature(CONTINUE_AFTER_FATAL_ERROR, fatalError);
1068             }
1069         } catch (XMLConfigurationException e) {
1070         }
1071         // set full validation to false
1072         fIsCheckedFully = componentManager.getFeature(SCHEMA_FULL_CHECKING, false);
1073 
1074         // get generate-synthetic-annotations feature
1075         fSchemaHandler.setGenerateSyntheticAnnotations(componentManager.getFeature(GENERATE_SYNTHETIC_ANNOTATIONS, false));
1076         fSchemaHandler.reset(componentManager);
1077     }
1078 
1079     private void initGrammarBucket(){
1080         if(fGrammarPool != null) {
1081             Grammar [] initialGrammars = fGrammarPool.retrieveInitialGrammarSet(XMLGrammarDescription.XML_SCHEMA);
1082             for (int i = 0; i < initialGrammars.length; i++) {
1083                 // put this grammar into the bucket, along with grammars
1084                 // imported by it (directly or indirectly)
1085                 if (!fGrammarBucket.putGrammar((SchemaGrammar)(initialGrammars[i]), true)) {
1086                     // REVISIT: a conflict between new grammar(s) and grammars
1087                     // in the bucket. What to do? A warning? An exception?
1088                     fErrorReporter.reportError(XSMessageFormatter.SCHEMA_DOMAIN,
1089                             "GrammarConflict", null,
1090                             XMLErrorReporter.SEVERITY_WARNING);
1091                 }
1092             }
1093         }
1094     }
1095 
1096 
1097     /* (non-Javadoc)
1098      * @see com.sun.org.apache.xerces.internal.xs.XSLoader#getConfig()
1099      */
1100     public DOMConfiguration getConfig() {
1101         return this;
1102     }
1103 
1104     /* (non-Javadoc)
1105      * @see com.sun.org.apache.xerces.internal.xs.XSLoader#load(org.w3c.dom.ls.LSInput)
1106      */
1107     public XSModel load(LSInput is) {
1108         try {
1109             Grammar g = loadGrammar(dom2xmlInputSource(is));
1110             return ((XSGrammar) g).toXSModel();
1111         } catch (Exception e) {
1112             reportDOMFatalError(e);
1113             return null;
1114         }
1115     }
1116 
1117     /* (non-Javadoc)
1118      * @see com.sun.org.apache.xerces.internal.xs.XSLoader#loadInputList(com.sun.org.apache.xerces.internal.xs.DOMInputList)
1119      */
1120     public XSModel loadInputList(LSInputList is) {
1121         int length = is.getLength();
1122         SchemaGrammar[] gs = new SchemaGrammar[length];
1123         for (int i = 0; i < length; i++) {
1124             try {
1125                 gs[i] = (SchemaGrammar) loadGrammar(dom2xmlInputSource(is.item(i)));
1126             } catch (Exception e) {
1127                 reportDOMFatalError(e);
1128                 return null;
1129             }
1130         }
1131         return new XSModelImpl(gs);
1132     }
1133 
1134     /* (non-Javadoc)
1135      * @see com.sun.org.apache.xerces.internal.xs.XSLoader#loadURI(java.lang.String)
1136      */
1137     public XSModel loadURI(String uri) {
1138         try {
1139             Grammar g = loadGrammar(new XMLInputSource(null, uri, null));
1140             return ((XSGrammar)g).toXSModel();
1141         }
1142         catch (Exception e){
1143             reportDOMFatalError(e);
1144             return null;
1145         }
1146     }
1147 
1148     /* (non-Javadoc)
1149      * @see com.sun.org.apache.xerces.internal.xs.XSLoader#loadURIList(com.sun.org.apache.xerces.internal.xs.StringList)
1150      */
1151     public XSModel loadURIList(StringList uriList) {
1152         int length = uriList.getLength();
1153         SchemaGrammar[] gs = new SchemaGrammar[length];
1154         for (int i = 0; i < length; i++) {
1155             try {
1156                 gs[i] =
1157                     (SchemaGrammar) loadGrammar(new XMLInputSource(null, uriList.item(i), null));
1158             } catch (Exception e) {
1159                 reportDOMFatalError(e);
1160                 return null;
1161             }
1162         }
1163         return new XSModelImpl(gs);
1164     }
1165 
1166     void reportDOMFatalError(Exception e) {
1167                 if (fErrorHandler != null) {
1168                     DOMErrorImpl error = new DOMErrorImpl();
1169                     error.fException = e;
1170                     error.fMessage = e.getMessage();
1171                     error.fSeverity = DOMError.SEVERITY_FATAL_ERROR;
1172                     fErrorHandler.getErrorHandler().handleError(error);
1173                 }
1174             }
1175 
1176     /* (non-Javadoc)
1177      * @see DOMConfiguration#canSetParameter(String, Object)
1178      */
1179     public boolean canSetParameter(String name, Object value) {
1180         if(value instanceof Boolean){
1181             if (name.equals(Constants.DOM_VALIDATE) ||
1182                 name.equals(SCHEMA_FULL_CHECKING) ||
1183                 name.equals(VALIDATE_ANNOTATIONS) ||
1184                 name.equals(CONTINUE_AFTER_FATAL_ERROR) ||
1185                 name.equals(ALLOW_JAVA_ENCODINGS) ||
1186                 name.equals(STANDARD_URI_CONFORMANT_FEATURE) ||
1187                 name.equals(GENERATE_SYNTHETIC_ANNOTATIONS) ||
1188                 name.equals(HONOUR_ALL_SCHEMALOCATIONS) ||
1189                 name.equals(NAMESPACE_GROWTH) ||
1190                 name.equals(TOLERATE_DUPLICATES) ||
1191                 name.equals(OVERRIDE_PARSER)) {
1192                 return true;
1193 
1194             }
1195             return false;
1196         }
1197         if (name.equals(Constants.DOM_ERROR_HANDLER) ||
1198             name.equals(Constants.DOM_RESOURCE_RESOLVER) ||
1199             name.equals(SYMBOL_TABLE) ||
1200             name.equals(ERROR_REPORTER) ||
1201             name.equals(ERROR_HANDLER) ||
1202             name.equals(ENTITY_RESOLVER) ||
1203             name.equals(XMLGRAMMAR_POOL) ||
1204             name.equals(SCHEMA_LOCATION) ||
1205             name.equals(SCHEMA_NONS_LOCATION) ||
1206             name.equals(JAXP_SCHEMA_SOURCE) ||
1207             name.equals(SCHEMA_DV_FACTORY)) {
1208             return true;
1209         }
1210         return false;
1211     }
1212 
1213     /* (non-Javadoc)
1214      * @see DOMConfiguration#getParameter(String)
1215      */
1216     public Object getParameter(String name) throws DOMException {
1217 
1218         if (name.equals(Constants.DOM_ERROR_HANDLER)){
1219             return (fErrorHandler != null) ? fErrorHandler.getErrorHandler() : null;
1220         }
1221         else if (name.equals(Constants.DOM_RESOURCE_RESOLVER)) {
1222             return (fResourceResolver != null) ? fResourceResolver.getEntityResolver() : null;
1223         }
1224 
1225         try {
1226             boolean feature = getFeature(name);
1227             return (feature) ? Boolean.TRUE : Boolean.FALSE;
1228         } catch (Exception e) {
1229             Object property;
1230             try {
1231                 property = getProperty(name);
1232                 return property;
1233             } catch (Exception ex) {
1234                 String msg =
1235                     DOMMessageFormatter.formatMessage(
1236                             DOMMessageFormatter.DOM_DOMAIN,
1237                             "FEATURE_NOT_SUPPORTED",
1238                             new Object[] { name });
1239                 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
1240             }
1241         }
1242     }
1243 
1244     /* (non-Javadoc)
1245      * @see DOMConfiguration#getParameterNames()
1246      */
1247     public DOMStringList getParameterNames() {
1248         if (fRecognizedParameters == null){
1249             Vector v = new Vector();
1250             v.add(Constants.DOM_VALIDATE);
1251             v.add(Constants.DOM_ERROR_HANDLER);
1252             v.add(Constants.DOM_RESOURCE_RESOLVER);
1253             v.add(SYMBOL_TABLE);
1254             v.add(ERROR_REPORTER);
1255             v.add(ERROR_HANDLER);
1256             v.add(ENTITY_RESOLVER);
1257             v.add(XMLGRAMMAR_POOL);
1258             v.add(SCHEMA_LOCATION);
1259             v.add(SCHEMA_NONS_LOCATION);
1260             v.add(JAXP_SCHEMA_SOURCE);
1261             v.add(SCHEMA_FULL_CHECKING);
1262             v.add(CONTINUE_AFTER_FATAL_ERROR);
1263             v.add(ALLOW_JAVA_ENCODINGS);
1264             v.add(STANDARD_URI_CONFORMANT_FEATURE);
1265             v.add(VALIDATE_ANNOTATIONS);
1266             v.add(GENERATE_SYNTHETIC_ANNOTATIONS);
1267             v.add(HONOUR_ALL_SCHEMALOCATIONS);
1268             v.add(NAMESPACE_GROWTH);
1269             v.add(TOLERATE_DUPLICATES);
1270             v.add(OVERRIDE_PARSER);
1271             fRecognizedParameters = new DOMStringListImpl(v);
1272         }
1273         return fRecognizedParameters;
1274     }
1275 
1276     /* (non-Javadoc)
1277      * @see DOMConfiguration#setParameter(String, Object)
1278      */
1279     public void setParameter(String name, Object value) throws DOMException {
1280         if (value instanceof Boolean) {
1281             boolean state = ((Boolean) value).booleanValue();
1282             if (name.equals("validate") && state) {
1283                 return;
1284             }
1285             try {
1286                 setFeature(name, state);
1287             } catch (Exception e) {
1288                 String msg =
1289                     DOMMessageFormatter.formatMessage(
1290                             DOMMessageFormatter.DOM_DOMAIN,
1291                             "FEATURE_NOT_SUPPORTED",
1292                             new Object[] { name });
1293                 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
1294             }
1295             return;
1296         }
1297         if (name.equals(Constants.DOM_ERROR_HANDLER)) {
1298             if (value instanceof DOMErrorHandler) {
1299                 try {
1300                     fErrorHandler = new DOMErrorHandlerWrapper((DOMErrorHandler) value);
1301                     setErrorHandler(fErrorHandler);
1302                 } catch (XMLConfigurationException e) {
1303                 }
1304             } else {
1305                 // REVISIT: type mismatch
1306                 String msg =
1307                     DOMMessageFormatter.formatMessage(
1308                             DOMMessageFormatter.DOM_DOMAIN,
1309                             "FEATURE_NOT_SUPPORTED",
1310                             new Object[] { name });
1311                 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
1312             }
1313             return;
1314 
1315         }
1316         if (name.equals(Constants.DOM_RESOURCE_RESOLVER)) {
1317             if (value instanceof LSResourceResolver) {
1318                 try {
1319                     fResourceResolver = new DOMEntityResolverWrapper((LSResourceResolver) value);
1320                     setEntityResolver(fResourceResolver);
1321                 }
1322                 catch (XMLConfigurationException e) {}
1323             } else {
1324                 // REVISIT: type mismatch
1325                 String msg =
1326                     DOMMessageFormatter.formatMessage(
1327                             DOMMessageFormatter.DOM_DOMAIN,
1328                             "FEATURE_NOT_SUPPORTED",
1329                             new Object[] { name });
1330                 throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
1331             }
1332             return;
1333         }
1334 
1335         try {
1336             setProperty(name, value);
1337         } catch (Exception ex) {
1338 
1339             String msg =
1340                 DOMMessageFormatter.formatMessage(
1341                         DOMMessageFormatter.DOM_DOMAIN,
1342                         "FEATURE_NOT_SUPPORTED",
1343                         new Object[] { name });
1344             throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
1345 
1346         }
1347 
1348     }
1349 
1350         XMLInputSource dom2xmlInputSource(LSInput is) {
1351         // need to wrap the LSInput with an XMLInputSource
1352         XMLInputSource xis = null;
1353 
1354         /**
1355          * An LSParser looks at inputs specified in LSInput in
1356          * the following order: characterStream, byteStream,
1357          * stringData, systemId, publicId. For consistency
1358          * have the same behaviour for XSLoader.
1359          */
1360 
1361         // check whether there is a Reader
1362         // according to DOM, we need to treat such reader as "UTF-16".
1363         if (is.getCharacterStream() != null) {
1364             xis = new XMLInputSource(is.getPublicId(), is.getSystemId(),
1365                     is.getBaseURI(), is.getCharacterStream(),
1366             "UTF-16");
1367         }
1368         // check whether there is an InputStream
1369         else if (is.getByteStream() != null) {
1370             xis = new XMLInputSource(is.getPublicId(), is.getSystemId(),
1371                     is.getBaseURI(), is.getByteStream(),
1372                     is.getEncoding());
1373         }
1374         // if there is a string data, use a StringReader
1375         // according to DOM, we need to treat such data as "UTF-16".
1376         else if (is.getStringData() != null && is.getStringData().length() != 0) {
1377             xis = new XMLInputSource(is.getPublicId(), is.getSystemId(),
1378                     is.getBaseURI(), new StringReader(is.getStringData()),
1379             "UTF-16");
1380         }
1381         // otherwise, just use the public/system/base Ids
1382         else {
1383             xis = new XMLInputSource(is.getPublicId(), is.getSystemId(),
1384                     is.getBaseURI());
1385         }
1386 
1387         return xis;
1388     }
1389 
1390 } // XMLGrammarLoader