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         fXMLSchemaLoader.setProperty(JdkXmlUtils.CDATA_CHUNK_SIZE, JdkXmlUtils.CDATA_CHUNK_SIZE_DEFAULT);
 170     }
 171 
 172     /**
 173      * <p>Is specified schema supported by this <code>SchemaFactory</code>?</p>
 174      *
 175      * @param schemaLanguage Specifies the schema language which the returned <code>SchemaFactory</code> will understand.
 176      *    <code>schemaLanguage</code> must specify a <a href="#schemaLanguage">valid</a> schema language.
 177      *
 178      * @return <code>true</code> if <code>SchemaFactory</code> supports <code>schemaLanguage</code>, else <code>false</code>.
 179      *
 180      * @throws NullPointerException If <code>schemaLanguage</code> is <code>null</code>.
 181      * @throws IllegalArgumentException If <code>schemaLanguage.length() == 0</code>
 182      *   or <code>schemaLanguage</code> does not specify a <a href="#schemaLanguage">valid</a> schema language.
 183      */
 184     public boolean isSchemaLanguageSupported(String schemaLanguage) {
 185         if (schemaLanguage == null) {
 186             throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 187                     "SchemaLanguageNull", null));
 188         }
 189         if (schemaLanguage.length() == 0) {
 190             throw new IllegalArgumentException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 191                     "SchemaLanguageLengthZero", null));
 192         }
 193         // only W3C XML Schema 1.0 is supported
 194         return schemaLanguage.equals(XMLConstants.W3C_XML_SCHEMA_NS_URI) ||
 195                 schemaLanguage.equals(Constants.W3C_XML_SCHEMA10_NS_URI);
 196     }
 197 
 198     public LSResourceResolver getResourceResolver() {
 199         return fLSResourceResolver;
 200     }
 201 
 202     public void setResourceResolver(LSResourceResolver resourceResolver) {
 203         fLSResourceResolver = resourceResolver;
 204         fDOMEntityResolverWrapper.setEntityResolver(resourceResolver);
 205         fXMLSchemaLoader.setEntityResolver(fDOMEntityResolverWrapper);
 206     }
 207 
 208     public ErrorHandler getErrorHandler() {
 209         return fErrorHandler;
 210     }
 211 
 212     public void setErrorHandler(ErrorHandler errorHandler) {
 213         fErrorHandler = errorHandler;
 214         fErrorHandlerWrapper.setErrorHandler(errorHandler != null ? errorHandler : DraconianErrorHandler.getInstance());
 215         fXMLSchemaLoader.setErrorHandler(fErrorHandlerWrapper);
 216     }
 217 
 218     public Schema newSchema( Source[] schemas ) throws SAXException {
 219 
 220         // this will let the loader store parsed Grammars into the pool.
 221         XMLGrammarPoolImplExtension pool = new XMLGrammarPoolImplExtension();
 222         fXMLGrammarPoolWrapper.setGrammarPool(pool);
 223 
 224         XMLInputSource[] xmlInputSources = new XMLInputSource[schemas.length];
 225         InputStream inputStream;
 226         Reader reader;
 227         for (int i = 0; i < schemas.length; ++i) {
 228             Source source = schemas[i];
 229             if (source instanceof StreamSource) {
 230                 StreamSource streamSource = (StreamSource) source;
 231                 String publicId = streamSource.getPublicId();
 232                 String systemId = streamSource.getSystemId();
 233                 inputStream = streamSource.getInputStream();
 234                 reader = streamSource.getReader();
 235                 XMLInputSource xmlInputSource = new XMLInputSource(publicId, systemId, null, false);
 236                 xmlInputSource.setByteStream(inputStream);
 237                 xmlInputSource.setCharacterStream(reader);
 238                 xmlInputSources[i] = xmlInputSource;
 239             }
 240             else if (source instanceof SAXSource) {
 241                 SAXSource saxSource = (SAXSource) source;
 242                 InputSource inputSource = saxSource.getInputSource();
 243                 if (inputSource == null) {
 244                     throw new SAXException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 245                             "SAXSourceNullInputSource", null));
 246                 }
 247                 xmlInputSources[i] = new SAXInputSource(saxSource.getXMLReader(), inputSource);
 248             }
 249             else if (source instanceof DOMSource) {
 250                 DOMSource domSource = (DOMSource) source;
 251                 Node node = domSource.getNode();
 252                 String systemID = domSource.getSystemId();
 253                 xmlInputSources[i] = new DOMInputSource(node, systemID);
 254             }
 255              else if (source instanceof StAXSource) {
 256                 StAXSource staxSource = (StAXSource) source;
 257                 XMLEventReader eventReader = staxSource.getXMLEventReader();
 258                 if (eventReader != null) {
 259                     xmlInputSources[i] = new StAXInputSource(eventReader);
 260                 }
 261                 else {
 262                     xmlInputSources[i] = new StAXInputSource(staxSource.getXMLStreamReader());
 263                 }
 264             }
 265             else if (source == null) {
 266                 throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 267                         "SchemaSourceArrayMemberNull", null));
 268             }
 269             else {
 270                 throw new IllegalArgumentException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 271                         "SchemaFactorySourceUnrecognized",
 272                         new Object [] {source.getClass().getName()}));
 273             }
 274         }
 275 
 276         try {
 277             fXMLSchemaLoader.loadGrammar(xmlInputSources);
 278         }
 279         catch (XNIException e) {
 280             // this should have been reported to users already.
 281             throw Util.toSAXException(e);
 282         }
 283         catch (IOException e) {
 284             // this hasn't been reported, so do so now.
 285             SAXParseException se = new SAXParseException(e.getMessage(),null,e);
 286             if (fErrorHandler != null) {
 287                 fErrorHandler.error(se);
 288             }
 289             throw se; // and we must throw it.
 290         }
 291 
 292         // Clear reference to grammar pool.
 293         fXMLGrammarPoolWrapper.setGrammarPool(null);
 294 
 295         // Select Schema implementation based on grammar count.
 296         final int grammarCount = pool.getGrammarCount();
 297         AbstractXMLSchema schema = null;
 298         if (fUseGrammarPoolOnly) {
 299             if (grammarCount > 1) {
 300                 schema = new XMLSchema(new ReadOnlyGrammarPool(pool));
 301             }
 302             else if (grammarCount == 1) {
 303                 Grammar[] grammars = pool.retrieveInitialGrammarSet(XMLGrammarDescription.XML_SCHEMA);
 304                 schema = new SimpleXMLSchema(grammars[0]);
 305             }
 306             else {
 307                 schema = new EmptyXMLSchema();
 308             }
 309         }
 310         else {
 311             schema = new XMLSchema(new ReadOnlyGrammarPool(pool), false);
 312         }
 313         propagateFeatures(schema);
 314         propagateProperties(schema);
 315         return schema;
 316     }
 317 
 318     public Schema newSchema() throws SAXException {
 319         /*
 320          * It would make sense to return an EmptyXMLSchema object here, if
 321          * fUseGrammarPoolOnly is set to true. However, because the default
 322          * value of this feature is true, doing so would change the default
 323          * behaviour of this method. Thus, we return a WeakReferenceXMLSchema
 324          * regardless of the value of fUseGrammarPoolOnly. -PM
 325          */
 326 
 327         // Use a Schema that uses the system id as the equality source.
 328         AbstractXMLSchema schema = new WeakReferenceXMLSchema();
 329         propagateFeatures(schema);
 330         propagateProperties(schema);
 331         return schema;
 332     }
 333 
 334     public Schema newSchema(XMLGrammarPool pool) throws SAXException {
 335         // If the "use-grammar-pool-only" feature is set to true
 336         // prevent the application's grammar pool from being mutated
 337         // by wrapping it in a ReadOnlyGrammarPool.
 338         final AbstractXMLSchema schema = (fUseGrammarPoolOnly) ?
 339             new XMLSchema(new ReadOnlyGrammarPool(pool)) :
 340             new XMLSchema(pool, false);
 341         propagateFeatures(schema);
 342         return schema;
 343     }
 344 
 345     public boolean getFeature(String name)
 346         throws SAXNotRecognizedException, SAXNotSupportedException {
 347         if (name == null) {
 348             throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 349                     "FeatureNameNull", null));
 350         }
 351         if (name.startsWith(JAXP_SOURCE_FEATURE_PREFIX)) {
 352             // Indicates to the caller that this SchemaFactory supports a specific JAXP Source.
 353             if (name.equals(StreamSource.FEATURE) ||
 354                 name.equals(SAXSource.FEATURE) ||
 355                 name.equals(DOMSource.FEATURE) ||
 356                 name.equals(StAXSource.FEATURE)) {
 357                 return true;
 358             }
 359         }
 360         if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) {
 361             return (fSecurityManager != null && fSecurityManager.isSecureProcessing());
 362         }
 363         else if (name.equals(USE_GRAMMAR_POOL_ONLY)) {
 364             return fUseGrammarPoolOnly;
 365         }
 366         try {
 367             return fXMLSchemaLoader.getFeature(name);
 368         }
 369         catch (XMLConfigurationException e) {
 370             String identifier = e.getIdentifier();
 371             if (e.getType() == Status.NOT_RECOGNIZED) {
 372                 throw new SAXNotRecognizedException(
 373                         SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 374                         "feature-not-recognized", new Object [] {identifier}));
 375             }
 376             else {
 377                 throw new SAXNotSupportedException(
 378                         SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 379                         "feature-not-supported", new Object [] {identifier}));
 380             }
 381         }
 382     }
 383 
 384     public Object getProperty(String name)
 385         throws SAXNotRecognizedException, SAXNotSupportedException {
 386         if (name == null) {
 387             throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 388                     "ProperyNameNull", null));
 389         }
 390         if (name.equals(SECURITY_MANAGER)) {
 391             return fSecurityManager;
 392         }
 393         else if (name.equals(XMLGRAMMAR_POOL)) {
 394             throw new SAXNotSupportedException(
 395                     SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 396                     "property-not-supported", new Object [] {name}));
 397         }
 398         try {
 399             return fXMLSchemaLoader.getProperty(name);
 400         }
 401         catch (XMLConfigurationException e) {
 402             String identifier = e.getIdentifier();
 403             if (e.getType() == Status.NOT_RECOGNIZED) {
 404                 throw new SAXNotRecognizedException(
 405                         SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 406                         "property-not-recognized", new Object [] {identifier}));
 407             }
 408             else {
 409                 throw new SAXNotSupportedException(
 410                         SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 411                         "property-not-supported", new Object [] {identifier}));
 412             }
 413         }
 414     }
 415 
 416     public void setFeature(String name, boolean value)
 417         throws SAXNotRecognizedException, SAXNotSupportedException {
 418         if (name == null) {
 419             throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 420                     "FeatureNameNull", null));
 421         }
 422         if (name.startsWith(JAXP_SOURCE_FEATURE_PREFIX)) {
 423             if (name.equals(StreamSource.FEATURE) ||
 424                 name.equals(SAXSource.FEATURE) ||
 425                 name.equals(DOMSource.FEATURE) ||
 426                 name.equals(StAXSource.FEATURE)) {
 427                 throw new SAXNotSupportedException(
 428                         SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 429                         "feature-read-only", new Object [] {name}));
 430             }
 431         }
 432         if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) {
 433             if (System.getSecurityManager() != null && (!value)) {
 434                 throw new SAXNotSupportedException(
 435                         SAXMessageFormatter.formatMessage(null,
 436                         "jaxp-secureprocessing-feature", null));
 437             }
 438 
 439             fSecurityManager.setSecureProcessing(value);
 440             if (value) {
 441                 fSecurityPropertyMgr.setValue(XMLSecurityPropertyManager.Property.ACCESS_EXTERNAL_DTD,
 442                         XMLSecurityPropertyManager.State.FSP, Constants.EXTERNAL_ACCESS_DEFAULT_FSP);
 443                 fSecurityPropertyMgr.setValue(XMLSecurityPropertyManager.Property.ACCESS_EXTERNAL_SCHEMA,
 444                         XMLSecurityPropertyManager.State.FSP, Constants.EXTERNAL_ACCESS_DEFAULT_FSP);
 445             }
 446 
 447             fXMLSchemaLoader.setProperty(SECURITY_MANAGER, fSecurityManager);
 448             return;
 449         }
 450         else if (name.equals(USE_GRAMMAR_POOL_ONLY)) {
 451             fUseGrammarPoolOnly = value;
 452             return;
 453         }
 454         else if (name.equals(Constants.ORACLE_FEATURE_SERVICE_MECHANISM)) {
 455             //in secure mode, let _useServicesMechanism be determined by the constructor
 456             if (System.getSecurityManager() != null)
 457                 return;
 458         }
 459         try {
 460             fXMLSchemaLoader.setFeature(name, value);
 461         }
 462         catch (XMLConfigurationException e) {
 463             String identifier = e.getIdentifier();
 464             if (e.getType() == Status.NOT_RECOGNIZED) {
 465                 throw new SAXNotRecognizedException(
 466                         SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 467                         "feature-not-recognized", new Object [] {identifier}));
 468             }
 469             else {
 470                 throw new SAXNotSupportedException(
 471                         SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 472                         "feature-not-supported", new Object [] {identifier}));
 473             }
 474         }
 475     }
 476 
 477     public void setProperty(String name, Object object)
 478         throws SAXNotRecognizedException, SAXNotSupportedException {
 479         if (name == null) {
 480             throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 481                     "ProperyNameNull", null));
 482         }
 483         if (name.equals(SECURITY_MANAGER)) {
 484             fSecurityManager = XMLSecurityManager.convert(object, fSecurityManager);
 485             fXMLSchemaLoader.setProperty(SECURITY_MANAGER, fSecurityManager);
 486             return;
 487         } else if (name.equals(Constants.XML_SECURITY_PROPERTY_MANAGER)) {
 488             if (object == null) {
 489                 fSecurityPropertyMgr = new XMLSecurityPropertyManager();
 490             } else {
 491                 fSecurityPropertyMgr = (XMLSecurityPropertyManager)object;
 492             }
 493             fXMLSchemaLoader.setProperty(Constants.XML_SECURITY_PROPERTY_MANAGER, fSecurityPropertyMgr);
 494             return;
 495         }
 496         else if (name.equals(XMLGRAMMAR_POOL)) {
 497             throw new SAXNotSupportedException(
 498                     SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 499                     "property-not-supported", new Object [] {name}));
 500         }
 501         try {
 502             //check if the property is managed by security manager
 503             if (fSecurityManager == null ||
 504                     !fSecurityManager.setLimit(name, XMLSecurityManager.State.APIPROPERTY, object)) {
 505                 //check if the property is managed by security property manager
 506                 if (fSecurityPropertyMgr == null ||
 507                         !fSecurityPropertyMgr.setValue(name, XMLSecurityPropertyManager.State.APIPROPERTY, object)) {
 508                     //fall back to the existing property manager
 509                     fXMLSchemaLoader.setProperty(name, object);
 510                 }
 511             }
 512         }
 513         catch (XMLConfigurationException e) {
 514             String identifier = e.getIdentifier();
 515             if (e.getType() == Status.NOT_RECOGNIZED) {
 516                 throw new SAXNotRecognizedException(
 517                         SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 518                         "property-not-recognized", new Object [] {identifier}));
 519             }
 520             else {
 521                 throw new SAXNotSupportedException(
 522                         SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(),
 523                         "property-not-supported", new Object [] {identifier}));
 524             }
 525         }
 526     }
 527 
 528     private void propagateFeatures(AbstractXMLSchema schema) {
 529         schema.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING,
 530                 (fSecurityManager != null && fSecurityManager.isSecureProcessing()));
 531         schema.setFeature(Constants.ORACLE_FEATURE_SERVICE_MECHANISM, fUseServicesMechanism);
 532         String[] features = fXMLSchemaLoader.getRecognizedFeatures();
 533         for (int i = 0; i < features.length; ++i) {
 534             boolean state = fXMLSchemaLoader.getFeature(features[i]);
 535             schema.setFeature(features[i], state);
 536         }
 537     }
 538 
 539     private void propagateProperties(AbstractXMLSchema schema) {
 540         String[] properties = fXMLSchemaLoader.getRecognizedProperties();
 541         for (int i = 0; i < properties.length; ++i) {
 542             Object state = fXMLSchemaLoader.getProperty(properties[i]);
 543             schema.setProperty(properties[i], state);
 544         }
 545     }
 546 
 547 
 548     /**
 549      * Extension of XMLGrammarPoolImpl which exposes the number of
 550      * grammars stored in the grammar pool.
 551      */
 552     static class XMLGrammarPoolImplExtension extends XMLGrammarPoolImpl {
 553 
 554         /** Constructs a grammar pool with a default number of buckets. */
 555         public XMLGrammarPoolImplExtension() {
 556             super();
 557         }
 558 
 559         /** Constructs a grammar pool with a specified number of buckets. */
 560         public XMLGrammarPoolImplExtension(int initialCapacity) {
 561             super(initialCapacity);
 562         }
 563 
 564         /** Returns the number of grammars contained in this pool. */
 565         int getGrammarCount() {
 566             return fGrammarCount;
 567         }
 568 
 569     } // XMLSchemaFactory.XMLGrammarPoolImplExtension
 570 
 571     /**
 572      * A grammar pool which wraps another.
 573      */
 574     static class XMLGrammarPoolWrapper implements XMLGrammarPool {
 575 
 576         private XMLGrammarPool fGrammarPool;
 577 
 578         /*
 579          * XMLGrammarPool methods
 580          */
 581 
 582         public Grammar[] retrieveInitialGrammarSet(String grammarType) {
 583             return fGrammarPool.retrieveInitialGrammarSet(grammarType);
 584         }
 585 
 586         public void cacheGrammars(String grammarType, Grammar[] grammars) {
 587             fGrammarPool.cacheGrammars(grammarType, grammars);
 588         }
 589 
 590         public Grammar retrieveGrammar(XMLGrammarDescription desc) {
 591             return fGrammarPool.retrieveGrammar(desc);
 592         }
 593 
 594         public void lockPool() {
 595             fGrammarPool.lockPool();
 596         }
 597 
 598         public void unlockPool() {
 599             fGrammarPool.unlockPool();
 600         }
 601 
 602         public void clear() {
 603             fGrammarPool.clear();
 604         }
 605 
 606         /*
 607          * Other methods
 608          */
 609 
 610         void setGrammarPool(XMLGrammarPool grammarPool) {
 611             fGrammarPool = grammarPool;
 612         }
 613 
 614         XMLGrammarPool getGrammarPool() {
 615             return fGrammarPool;
 616         }
 617 
 618     } // XMLSchemaFactory.XMLGrammarPoolWrapper
 619 
 620 } // XMLSchemaFactory