/** Cleans out configuration, restoring it to its initial state. */
  void restoreInitialState() {
    fConfigUpdated = true;

    // Remove error resolver and error handler
    fComponents.put(ENTITY_RESOLVER, null);
    fComponents.put(ERROR_HANDLER, null);

    // Set the Locale back to null.
    setLocale(null);
    fComponents.put(LOCALE, null);

    // Restore initial security manager
    fComponents.put(SECURITY_MANAGER, fInitSecurityManager);

    // Set the Locale back to null.
    setLocale(null);
    fComponents.put(LOCALE, null);

    // Reset feature and property values to their initial values
    if (!fInitFeatures.isEmpty()) {
      Iterator iter = fInitFeatures.entrySet().iterator();
      while (iter.hasNext()) {
        Map.Entry entry = (Map.Entry) iter.next();
        String name = (String) entry.getKey();
        boolean value = ((Boolean) entry.getValue()).booleanValue();
        super.setFeature(name, value);
      }
      fInitFeatures.clear();
    }
    if (!fInitProperties.isEmpty()) {
      Iterator iter = fInitProperties.entrySet().iterator();
      while (iter.hasNext()) {
        Map.Entry entry = (Map.Entry) iter.next();
        String name = (String) entry.getKey();
        Object value = entry.getValue();
        super.setProperty(name, value);
      }
      fInitProperties.clear();
    }
  }
  /**
   * Sets the state of a property.
   *
   * @param propertyId The unique identifier (URI) of the property.
   * @param value The requested state of the property.
   * @exception XMLConfigurationException If the requested property is not known.
   */
  public void setProperty(String propertyId, Object value) throws XMLConfigurationException {
    if (ENTITY_MANAGER.equals(propertyId)
        || ERROR_REPORTER.equals(propertyId)
        || NAMESPACE_CONTEXT.equals(propertyId)
        || SCHEMA_VALIDATOR.equals(propertyId)
        || SYMBOL_TABLE.equals(propertyId)
        || VALIDATION_MANAGER.equals(propertyId)
        || XMLGRAMMAR_POOL.equals(propertyId)) {
      throw new XMLConfigurationException(Status.NOT_SUPPORTED, propertyId);
    }
    fConfigUpdated = true;
    fEntityManager.setProperty(propertyId, value);
    fErrorReporter.setProperty(propertyId, value);
    fSchemaValidator.setProperty(propertyId, value);
    if (ENTITY_RESOLVER.equals(propertyId)
        || ERROR_HANDLER.equals(propertyId)
        || SECURITY_MANAGER.equals(propertyId)) {
      fComponents.put(propertyId, value);
      return;
    } else if (LOCALE.equals(propertyId)) {
      setLocale((Locale) value);
      fComponents.put(propertyId, value);
      return;
    }

    // check if the property is managed by security manager
    if (fInitSecurityManager == null
        || !fInitSecurityManager.setLimit(
            propertyId, XMLSecurityManager.State.APIPROPERTY, value)) {
      // check if the property is managed by security property manager
      if (fSecurityPropertyMgr == null
          || !fSecurityPropertyMgr.setValue(
              propertyId, XMLSecurityPropertyManager.State.APIPROPERTY, value)) {
        // fall back to the existing property manager
        if (!fInitProperties.containsKey(propertyId)) {
          fInitProperties.put(propertyId, super.getProperty(propertyId));
        }
        super.setProperty(propertyId, value);
      }
    }
  }
  /**
   * Set the state of a feature.
   *
   * @param featureId The unique identifier (URI) of the feature.
   * @param state The requested state of the feature (true or false).
   * @exception XMLConfigurationException If the requested feature is not known.
   */
  public void setFeature(String featureId, boolean value) throws XMLConfigurationException {
    if (PARSER_SETTINGS.equals(featureId)) {
      throw new XMLConfigurationException(Status.NOT_SUPPORTED, featureId);
    } else if (value == false
        && (VALIDATION.equals(featureId) || SCHEMA_VALIDATION.equals(featureId))) {
      throw new XMLConfigurationException(Status.NOT_SUPPORTED, featureId);
    } else if (USE_GRAMMAR_POOL_ONLY.equals(featureId) && value != fUseGrammarPoolOnly) {
      throw new XMLConfigurationException(Status.NOT_SUPPORTED, featureId);
    }
    if (XMLConstants.FEATURE_SECURE_PROCESSING.equals(featureId)) {
      if (_isSecureMode && !value) {
        throw new XMLConfigurationException(
            Status.NOT_ALLOWED, XMLConstants.FEATURE_SECURE_PROCESSING);
      }
      fInitSecurityManager.setSecureProcessing(value);
      setProperty(SECURITY_MANAGER, fInitSecurityManager);

      if (value && Constants.IS_JDK8_OR_ABOVE) {
        fSecurityPropertyMgr.setValue(
            XMLSecurityPropertyManager.Property.ACCESS_EXTERNAL_DTD,
            XMLSecurityPropertyManager.State.FSP,
            Constants.EXTERNAL_ACCESS_DEFAULT_FSP);
        fSecurityPropertyMgr.setValue(
            XMLSecurityPropertyManager.Property.ACCESS_EXTERNAL_SCHEMA,
            XMLSecurityPropertyManager.State.FSP,
            Constants.EXTERNAL_ACCESS_DEFAULT_FSP);
        setProperty(XML_SECURITY_PROPERTY_MANAGER, fSecurityPropertyMgr);
      }

      return;
    }
    fConfigUpdated = true;
    fEntityManager.setFeature(featureId, value);
    fErrorReporter.setFeature(featureId, value);
    fSchemaValidator.setFeature(featureId, value);
    if (!fInitFeatures.containsKey(featureId)) {
      boolean current = super.getFeature(featureId);
      fInitFeatures.put(featureId, current ? Boolean.TRUE : Boolean.FALSE);
    }
    super.setFeature(featureId, value);
  }