1 /*
   2  * Copyright (c) 2007, 2016, 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.jaxp.validation;
  22 
  23 import com.sun.org.apache.xerces.internal.impl.Constants;
  24 import com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader;
  25 import com.sun.org.apache.xerces.internal.util.DOMEntityResolverWrapper;
  26 import com.sun.org.apache.xerces.internal.util.DOMInputSource;
  27 import com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper;
  28 import com.sun.org.apache.xerces.internal.util.SAXInputSource;
  29 import com.sun.org.apache.xerces.internal.util.SAXMessageFormatter;
  30 import com.sun.org.apache.xerces.internal.util.StAXInputSource;
  31 import com.sun.org.apache.xerces.internal.util.Status;
  32 import com.sun.org.apache.xerces.internal.util.XMLGrammarPoolImpl;
  33 import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager;
  34 import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager;
  35 import com.sun.org.apache.xerces.internal.xni.XNIException;
  36 import com.sun.org.apache.xerces.internal.xni.grammars.Grammar;
  37 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarDescription;
  38 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarPool;
  39 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
  40 import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
  41 import java.io.IOException;
  42 import java.io.InputStream;
  43 import java.io.Reader;
  44 import javax.xml.XMLConstants;
  45 import javax.xml.catalog.CatalogFeatures.Feature;
  46 import javax.xml.stream.XMLEventReader;
  47 import javax.xml.transform.Source;
  48 import javax.xml.transform.dom.DOMSource;
  49 import javax.xml.transform.sax.SAXSource;
  50 import javax.xml.transform.stax.StAXSource;
  51 import javax.xml.transform.stream.StreamSource;
  52 import javax.xml.validation.Schema;
  53 import javax.xml.validation.SchemaFactory;
  54 import jdk.xml.internal.JdkXmlUtils;
  55 import org.w3c.dom.Node;
  56 import org.w3c.dom.ls.LSResourceResolver;
  57 import org.xml.sax.ErrorHandler;
  58 import org.xml.sax.InputSource;
  59 import org.xml.sax.SAXException;
  60 import org.xml.sax.SAXNotRecognizedException;
  61 import org.xml.sax.SAXNotSupportedException;
  62 import org.xml.sax.SAXParseException;
  63 
  64 /**
  65  * {@link SchemaFactory} for XML Schema.
  66  *
  67  * @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
  68  */
  69 public final class XMLSchemaFactory extends SchemaFactory {
  70 
  71     // feature identifiers
  72 
  73     /** JAXP Source feature prefix. */
  74     private static final String JAXP_SOURCE_FEATURE_PREFIX = "http://javax.xml.transform";
  75 
  76     /** Feature identifier: schema full checking. */
  77     private static final String SCHEMA_FULL_CHECKING =
  78         Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_FULL_CHECKING;
  79 
  80     /** Feature identifier: use grammar pool only. */
  81     private static final String USE_GRAMMAR_POOL_ONLY =
  82         Constants.XERCES_FEATURE_PREFIX + Constants.USE_GRAMMAR_POOL_ONLY_FEATURE;
  83 
  84     // property identifiers
  85 
  86     /** Property identifier: grammar pool. */
  87     private static final String XMLGRAMMAR_POOL =
  88         Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY;
  89 
  90     /** Property identifier: XMLSecurityManager. */
  91     private static final String SECURITY_MANAGER =
  92         Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY;
  93 
  94     /** Property identifier: Security property manager. */
  95     private static final String XML_SECURITY_PROPERTY_MANAGER =
  96             Constants.XML_SECURITY_PROPERTY_MANAGER;
  97 
  98 
  99     //
 100     // Data
 101     //
 102 
 103     /** The XMLSchemaLoader */
 104     private final XMLSchemaLoader fXMLSchemaLoader = new XMLSchemaLoader();
 105 
 106     /** User-specified ErrorHandler; can be null. */
 107     private ErrorHandler fErrorHandler;
 108 
 109     /** The LSResrouceResolver */
 110     private LSResourceResolver fLSResourceResolver;
 111 
 112     /** The DOMEntityResolverWrapper */
 113     private final DOMEntityResolverWrapper fDOMEntityResolverWrapper;
 114 
 115     /** The ErrorHandlerWrapper */
 116     private final ErrorHandlerWrapper fErrorHandlerWrapper;
 117 
 118     /** The SecurityManager. */
 119     private XMLSecurityManager fSecurityManager;
 120 
 121     /** The Security property manager. */
 122     private XMLSecurityPropertyManager fSecurityPropertyMgr;
 123 
 124     /** The container for the real grammar pool. */
 125     private final XMLGrammarPoolWrapper fXMLGrammarPoolWrapper;
 126 
 127     /** Whether or not to allow new schemas to be added to the grammar pool */
 128     private boolean fUseGrammarPoolOnly;
 129 
 130     /**
 131      * Indicates whether implementation parts should use
 132      *   service loader (or similar).
 133      * Note the default value (false) is the safe option..
 134      */
 135     private final boolean fUseServicesMechanism;
 136 
 137 
 138     public XMLSchemaFactory() {
 139         this(true);
 140     }
 141     public static XMLSchemaFactory newXMLSchemaFactoryNoServiceLoader() {
 142         return new XMLSchemaFactory(false);
 143     }
 144     private XMLSchemaFactory(boolean useServicesMechanism) {
 145         fUseServicesMechanism = useServicesMechanism;
 146         fErrorHandlerWrapper = new ErrorHandlerWrapper(DraconianErrorHandler.getInstance());
 147         fDOMEntityResolverWrapper = new DOMEntityResolverWrapper();
 148         fXMLGrammarPoolWrapper = new XMLGrammarPoolWrapper();
 149         fXMLSchemaLoader.setFeature(SCHEMA_FULL_CHECKING, true);
 150         fXMLSchemaLoader.setProperty(XMLGRAMMAR_POOL, fXMLGrammarPoolWrapper);
 151         fXMLSchemaLoader.setEntityResolver(fDOMEntityResolverWrapper);
 152         fXMLSchemaLoader.setErrorHandler(fErrorHandlerWrapper);
 153         fUseGrammarPoolOnly = true;
 154 
 155         // Enable secure processing feature by default
 156         fSecurityManager = new XMLSecurityManager(true);
 157         fXMLSchemaLoader.setProperty(SECURITY_MANAGER, fSecurityManager);
 158 
 159         fSecurityPropertyMgr = new XMLSecurityPropertyManager();
 160         fXMLSchemaLoader.setProperty(XML_SECURITY_PROPERTY_MANAGER,
 161                 fSecurityPropertyMgr);
 162 
 163         // use catalog
 164         fXMLSchemaLoader.setFeature(XMLConstants.USE_CATALOG, JdkXmlUtils.USE_CATALOG_DEFAULT);
 165         for (Feature f : Feature.values()) {
 166             fXMLSchemaLoader.setProperty(f.getPropertyName(), null);
 167         }
 168     }
 169 
 170     /**
 171      * <p>Is specified schema supported by this <code>SchemaFactory</code>?</p>
 172      *
 173      * @param schemaLanguage Specifies the schema language which the returned <code>SchemaFactory</code> will understand.
 174      *    <code>schemaLanguage</code> must specify a <a href="#schemaLanguage">valid</a> schema language.
 175      *
 176      * @return <code>true</code> if <code>SchemaFactory</code> supports <code>schemaLanguage</code>, else <code>false</code>.
 177      *
 178      * @throws NullPointerException If <code>schemaLanguage</code> is <code>null</code>.
 179      * @throws IllegalArgumentException If <code>schemaLanguage.length() == 0</code>
 180      *   or <code>schemaLanguage</code> does not specify a <a href="#schemaLanguage">valid</a> schema language.
 181      */
 182     public boolean isSchemaLanguageSupported(String schemaLanguage) {
 183         if (schemaLanguage == null) {
 184             throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 185                     "SchemaLanguageNull", null));
 186         }
 187         if (schemaLanguage.length() == 0) {
 188             throw new IllegalArgumentException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 189                     "SchemaLanguageLengthZero", null));
 190         }
 191         // only W3C XML Schema 1.0 is supported
 192         return schemaLanguage.equals(XMLConstants.W3C_XML_SCHEMA_NS_URI) ||
 193                 schemaLanguage.equals(Constants.W3C_XML_SCHEMA10_NS_URI);
 194     }
 195 
 196     public LSResourceResolver getResourceResolver() {
 197         return fLSResourceResolver;
 198     }
 199 
 200     public void setResourceResolver(LSResourceResolver resourceResolver) {
 201         fLSResourceResolver = resourceResolver;
 202         fDOMEntityResolverWrapper.setEntityResolver(resourceResolver);
 203         fXMLSchemaLoader.setEntityResolver(fDOMEntityResolverWrapper);
 204     }
 205 
 206     public ErrorHandler getErrorHandler() {
 207         return fErrorHandler;
 208     }
 209 
 210     public void setErrorHandler(ErrorHandler errorHandler) {
 211         fErrorHandler = errorHandler;
 212         fErrorHandlerWrapper.setErrorHandler(errorHandler != null ? errorHandler : DraconianErrorHandler.getInstance());
 213         fXMLSchemaLoader.setErrorHandler(fErrorHandlerWrapper);
 214     }
 215 
 216     public Schema newSchema( Source[] schemas ) throws SAXException {
 217 
 218         // this will let the loader store parsed Grammars into the pool.
 219         XMLGrammarPoolImplExtension pool = new XMLGrammarPoolImplExtension();
 220         fXMLGrammarPoolWrapper.setGrammarPool(pool);
 221 
 222         XMLInputSource[] xmlInputSources = new XMLInputSource[schemas.length];
 223         InputStream inputStream;
 224         Reader reader;
 225         for (int i = 0; i < schemas.length; ++i) {
 226             Source source = schemas[i];
 227             if (source instanceof StreamSource) {
 228                 StreamSource streamSource = (StreamSource) source;
 229                 String publicId = streamSource.getPublicId();
 230                 String systemId = streamSource.getSystemId();
 231                 inputStream = streamSource.getInputStream();
 232                 reader = streamSource.getReader();
 233                 XMLInputSource xmlInputSource = new XMLInputSource(publicId, systemId, null, false);
 234                 xmlInputSource.setByteStream(inputStream);
 235                 xmlInputSource.setCharacterStream(reader);
 236                 xmlInputSources[i] = xmlInputSource;
 237             }
 238             else if (source instanceof SAXSource) {
 239                 SAXSource saxSource = (SAXSource) source;
 240                 InputSource inputSource = saxSource.getInputSource();
 241                 if (inputSource == null) {
 242                     throw new SAXException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 243                             "SAXSourceNullInputSource", null));
 244                 }
 245                 xmlInputSources[i] = new SAXInputSource(saxSource.getXMLReader(), inputSource);
 246             }
 247             else if (source instanceof DOMSource) {
 248                 DOMSource domSource = (DOMSource) source;
 249                 Node node = domSource.getNode();
 250                 String systemID = domSource.getSystemId();
 251                 xmlInputSources[i] = new DOMInputSource(node, systemID);
 252             }
 253              else if (source instanceof StAXSource) {
 254                 StAXSource staxSource = (StAXSource) source;
 255                 XMLEventReader eventReader = staxSource.getXMLEventReader();
 256                 if (eventReader != null) {
 257                     xmlInputSources[i] = new StAXInputSource(eventReader);
 258                 }
 259                 else {
 260                     xmlInputSources[i] = new StAXInputSource(staxSource.getXMLStreamReader());
 261                 }
 262             }
 263             else if (source == null) {
 264                 throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 265                         "SchemaSourceArrayMemberNull", null));
 266             }
 267             else {
 268                 throw new IllegalArgumentException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 269                         "SchemaFactorySourceUnrecognized",
 270                         new Object [] {source.getClass().getName()}));
 271             }
 272         }
 273 
 274         try {
 275             fXMLSchemaLoader.loadGrammar(xmlInputSources);
 276         }
 277         catch (XNIException e) {
 278             // this should have been reported to users already.
 279             throw Util.toSAXException(e);
 280         }
 281         catch (IOException e) {
 282             // this hasn't been reported, so do so now.
 283             SAXParseException se = new SAXParseException(e.getMessage(),null,e);
 284             if (fErrorHandler != null) {
 285                 fErrorHandler.error(se);
 286             }
 287             throw se; // and we must throw it.
 288         }
 289 
 290         // Clear reference to grammar pool.
 291         fXMLGrammarPoolWrapper.setGrammarPool(null);
 292 
 293         // Select Schema implementation based on grammar count.
 294         final int grammarCount = pool.getGrammarCount();
 295         AbstractXMLSchema schema = null;
 296         if (fUseGrammarPoolOnly) {
 297             if (grammarCount > 1) {
 298                 schema = new XMLSchema(new ReadOnlyGrammarPool(pool));
 299             }
 300             else if (grammarCount == 1) {
 301                 Grammar[] grammars = pool.retrieveInitialGrammarSet(XMLGrammarDescription.XML_SCHEMA);
 302                 schema = new SimpleXMLSchema(grammars[0]);
 303             }
 304             else {
 305                 schema = new EmptyXMLSchema();
 306             }
 307         }
 308         else {
 309             schema = new XMLSchema(new ReadOnlyGrammarPool(pool), false);
 310         }
 311         propagateFeatures(schema);
 312         propagateProperties(schema);
 313         return schema;
 314     }
 315 
 316     public Schema newSchema() throws SAXException {
 317         /*
 318          * It would make sense to return an EmptyXMLSchema object here, if
 319          * fUseGrammarPoolOnly is set to true. However, because the default
 320          * value of this feature is true, doing so would change the default
 321          * behaviour of this method. Thus, we return a WeakReferenceXMLSchema
 322          * regardless of the value of fUseGrammarPoolOnly. -PM
 323          */
 324 
 325         // Use a Schema that uses the system id as the equality source.
 326         AbstractXMLSchema schema = new WeakReferenceXMLSchema();
 327         propagateFeatures(schema);
 328         propagateProperties(schema);
 329         return schema;
 330     }
 331 
 332     public Schema newSchema(XMLGrammarPool pool) throws SAXException {
 333         // If the "use-grammar-pool-only" feature is set to true
 334         // prevent the application's grammar pool from being mutated
 335         // by wrapping it in a ReadOnlyGrammarPool.
 336         final AbstractXMLSchema schema = (fUseGrammarPoolOnly) ?
 337             new XMLSchema(new ReadOnlyGrammarPool(pool)) :
 338             new XMLSchema(pool, false);
 339         propagateFeatures(schema);
 340         return schema;
 341     }
 342 
 343     public boolean getFeature(String name)
 344         throws SAXNotRecognizedException, SAXNotSupportedException {
 345         if (name == null) {
 346             throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 347                     "FeatureNameNull", null));
 348         }
 349         if (name.startsWith(JAXP_SOURCE_FEATURE_PREFIX)) {
 350             // Indicates to the caller that this SchemaFactory supports a specific JAXP Source.
 351             if (name.equals(StreamSource.FEATURE) ||
 352                 name.equals(SAXSource.FEATURE) ||
 353                 name.equals(DOMSource.FEATURE) ||
 354                 name.equals(StAXSource.FEATURE)) {
 355                 return true;
 356             }
 357         }
 358         if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) {
 359             return (fSecurityManager != null && fSecurityManager.isSecureProcessing());
 360         }
 361         else if (name.equals(USE_GRAMMAR_POOL_ONLY)) {
 362             return fUseGrammarPoolOnly;
 363         }
 364         try {
 365             return fXMLSchemaLoader.getFeature(name);
 366         }
 367         catch (XMLConfigurationException e) {
 368             String identifier = e.getIdentifier();
 369             if (e.getType() == Status.NOT_RECOGNIZED) {
 370                 throw new SAXNotRecognizedException(
 371                         SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 372                         "feature-not-recognized", new Object [] {identifier}));
 373             }
 374             else {
 375                 throw new SAXNotSupportedException(
 376                         SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 377                         "feature-not-supported", new Object [] {identifier}));
 378             }
 379         }
 380     }
 381 
 382     public Object getProperty(String name)
 383         throws SAXNotRecognizedException, SAXNotSupportedException {
 384         if (name == null) {
 385             throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 386                     "ProperyNameNull", null));
 387         }
 388         if (name.equals(SECURITY_MANAGER)) {
 389             return fSecurityManager;
 390         }
 391         else if (name.equals(XMLGRAMMAR_POOL)) {
 392             throw new SAXNotSupportedException(
 393                     SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 394                     "property-not-supported", new Object [] {name}));
 395         }
 396         try {
 397             return fXMLSchemaLoader.getProperty(name);
 398         }
 399         catch (XMLConfigurationException e) {
 400             String identifier = e.getIdentifier();
 401             if (e.getType() == Status.NOT_RECOGNIZED) {
 402                 throw new SAXNotRecognizedException(
 403                         SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 404                         "property-not-recognized", new Object [] {identifier}));
 405             }
 406             else {
 407                 throw new SAXNotSupportedException(
 408                         SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 409                         "property-not-supported", new Object [] {identifier}));
 410             }
 411         }
 412     }
 413 
 414     public void setFeature(String name, boolean value)
 415         throws SAXNotRecognizedException, SAXNotSupportedException {
 416         if (name == null) {
 417             throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 418                     "FeatureNameNull", null));
 419         }
 420         if (name.startsWith(JAXP_SOURCE_FEATURE_PREFIX)) {
 421             if (name.equals(StreamSource.FEATURE) ||
 422                 name.equals(SAXSource.FEATURE) ||
 423                 name.equals(DOMSource.FEATURE) ||
 424                 name.equals(StAXSource.FEATURE)) {
 425                 throw new SAXNotSupportedException(
 426                         SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 427                         "feature-read-only", new Object [] {name}));
 428             }
 429         }
 430         if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) {
 431             if (System.getSecurityManager() != null && (!value)) {
 432                 throw new SAXNotSupportedException(
 433                         SAXMessageFormatter.formatMessage(null,
 434                         "jaxp-secureprocessing-feature", null));
 435             }
 436 
 437             fSecurityManager.setSecureProcessing(value);
 438             if (value) {
 439                 fSecurityPropertyMgr.setValue(XMLSecurityPropertyManager.Property.ACCESS_EXTERNAL_DTD,
 440                         XMLSecurityPropertyManager.State.FSP, Constants.EXTERNAL_ACCESS_DEFAULT_FSP);
 441                 fSecurityPropertyMgr.setValue(XMLSecurityPropertyManager.Property.ACCESS_EXTERNAL_SCHEMA,
 442                         XMLSecurityPropertyManager.State.FSP, Constants.EXTERNAL_ACCESS_DEFAULT_FSP);
 443             }
 444 
 445             fXMLSchemaLoader.setProperty(SECURITY_MANAGER, fSecurityManager);
 446             return;
 447         }
 448         else if (name.equals(USE_GRAMMAR_POOL_ONLY)) {
 449             fUseGrammarPoolOnly = value;
 450             return;
 451         }
 452         else if (name.equals(Constants.ORACLE_FEATURE_SERVICE_MECHANISM)) {
 453             //in secure mode, let _useServicesMechanism be determined by the constructor
 454             if (System.getSecurityManager() != null)
 455                 return;
 456         }
 457         try {
 458             fXMLSchemaLoader.setFeature(name, value);
 459         }
 460         catch (XMLConfigurationException e) {
 461             String identifier = e.getIdentifier();
 462             if (e.getType() == Status.NOT_RECOGNIZED) {
 463                 throw new SAXNotRecognizedException(
 464                         SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 465                         "feature-not-recognized", new Object [] {identifier}));
 466             }
 467             else {
 468                 throw new SAXNotSupportedException(
 469                         SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 470                         "feature-not-supported", new Object [] {identifier}));
 471             }
 472         }
 473     }
 474 
 475     public void setProperty(String name, Object object)
 476         throws SAXNotRecognizedException, SAXNotSupportedException {
 477         if (name == null) {
 478             throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 479                     "ProperyNameNull", null));
 480         }
 481         if (name.equals(SECURITY_MANAGER)) {
 482             fSecurityManager = XMLSecurityManager.convert(object, fSecurityManager);
 483             fXMLSchemaLoader.setProperty(SECURITY_MANAGER, fSecurityManager);
 484             return;
 485         } else if (name.equals(Constants.XML_SECURITY_PROPERTY_MANAGER)) {
 486             if (object == null) {
 487                 fSecurityPropertyMgr = new XMLSecurityPropertyManager();
 488             } else {
 489                 fSecurityPropertyMgr = (XMLSecurityPropertyManager)object;
 490             }
 491             fXMLSchemaLoader.setProperty(Constants.XML_SECURITY_PROPERTY_MANAGER, fSecurityPropertyMgr);
 492             return;
 493         }
 494         else if (name.equals(XMLGRAMMAR_POOL)) {
 495             throw new SAXNotSupportedException(
 496                     SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 497                     "property-not-supported", new Object [] {name}));
 498         }
 499         try {
 500             //check if the property is managed by security manager
 501             if (fSecurityManager == null ||
 502                     !fSecurityManager.setLimit(name, XMLSecurityManager.State.APIPROPERTY, object)) {
 503                 //check if the property is managed by security property manager
 504                 if (fSecurityPropertyMgr == null ||
 505                         !fSecurityPropertyMgr.setValue(name, XMLSecurityPropertyManager.State.APIPROPERTY, object)) {
 506                     //fall back to the existing property manager
 507                     fXMLSchemaLoader.setProperty(name, object);
 508                 }
 509             }
 510         }
 511         catch (XMLConfigurationException e) {
 512             String identifier = e.getIdentifier();
 513             if (e.getType() == Status.NOT_RECOGNIZED) {
 514                 throw new SAXNotRecognizedException(
 515                         SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 516                         "property-not-recognized", new Object [] {identifier}));
 517             }
 518             else {
 519                 throw new SAXNotSupportedException(
 520                         SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 521                         "property-not-supported", new Object [] {identifier}));
 522             }
 523         }
 524     }
 525 
 526     private void propagateFeatures(AbstractXMLSchema schema) {
 527         schema.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING,
 528                 (fSecurityManager != null && fSecurityManager.isSecureProcessing()));
 529         schema.setFeature(Constants.ORACLE_FEATURE_SERVICE_MECHANISM, fUseServicesMechanism);
 530         String[] features = fXMLSchemaLoader.getRecognizedFeatures();
 531         for (int i = 0; i < features.length; ++i) {
 532             boolean state = fXMLSchemaLoader.getFeature(features[i]);
 533             schema.setFeature(features[i], state);
 534         }
 535     }
 536 
 537     private void propagateProperties(AbstractXMLSchema schema) {
 538         String[] properties = fXMLSchemaLoader.getRecognizedProperties();
 539         for (int i = 0; i < properties.length; ++i) {
 540             Object state = fXMLSchemaLoader.getProperty(properties[i]);
 541             schema.setProperty(properties[i], state);
 542         }
 543     }
 544 
 545 
 546     /**
 547      * Extension of XMLGrammarPoolImpl which exposes the number of
 548      * grammars stored in the grammar pool.
 549      */
 550     static class XMLGrammarPoolImplExtension extends XMLGrammarPoolImpl {
 551 
 552         /** Constructs a grammar pool with a default number of buckets. */
 553         public XMLGrammarPoolImplExtension() {
 554             super();
 555         }
 556 
 557         /** Constructs a grammar pool with a specified number of buckets. */
 558         public XMLGrammarPoolImplExtension(int initialCapacity) {
 559             super(initialCapacity);
 560         }
 561 
 562         /** Returns the number of grammars contained in this pool. */
 563         int getGrammarCount() {
 564             return fGrammarCount;
 565         }
 566 
 567     } // XMLSchemaFactory.XMLGrammarPoolImplExtension
 568 
 569     /**
 570      * A grammar pool which wraps another.
 571      */
 572     static class XMLGrammarPoolWrapper implements XMLGrammarPool {
 573 
 574         private XMLGrammarPool fGrammarPool;
 575 
 576         /*
 577          * XMLGrammarPool methods
 578          */
 579 
 580         public Grammar[] retrieveInitialGrammarSet(String grammarType) {
 581             return fGrammarPool.retrieveInitialGrammarSet(grammarType);
 582         }
 583 
 584         public void cacheGrammars(String grammarType, Grammar[] grammars) {
 585             fGrammarPool.cacheGrammars(grammarType, grammars);
 586         }
 587 
 588         public Grammar retrieveGrammar(XMLGrammarDescription desc) {
 589             return fGrammarPool.retrieveGrammar(desc);
 590         }
 591 
 592         public void lockPool() {
 593             fGrammarPool.lockPool();
 594         }
 595 
 596         public void unlockPool() {
 597             fGrammarPool.unlockPool();
 598         }
 599 
 600         public void clear() {
 601             fGrammarPool.clear();
 602         }
 603 
 604         /*
 605          * Other methods
 606          */
 607 
 608         void setGrammarPool(XMLGrammarPool grammarPool) {
 609             fGrammarPool = grammarPool;
 610         }
 611 
 612         XMLGrammarPool getGrammarPool() {
 613             return fGrammarPool;
 614         }
 615 
 616     } // XMLSchemaFactory.XMLGrammarPoolWrapper
 617 
 618 } // XMLSchemaFactory