/**
   * setProperty
   *
   * @param propertyId
   * @param value
   */
  public void setProperty(String propertyId, Object value) throws XMLConfigurationException {
    fConfigUpdated = true;
    // forward to every XML 1.0 component
    int count = fComponents.size();
    for (int i = 0; i < count; i++) {
      XMLComponent c = (XMLComponent) fComponents.get(i);
      c.setProperty(propertyId, value);
    }
    // forward it to every common Component
    count = fCommonComponents.size();
    for (int i = 0; i < count; i++) {
      XMLComponent c = (XMLComponent) fCommonComponents.get(i);
      c.setProperty(propertyId, value);
    }
    // forward it to every XML 1.1 component
    count = fXML11Components.size();
    for (int i = 0; i < count; i++) {
      XMLComponent c = (XMLComponent) fXML11Components.get(i);
      try {
        c.setProperty(propertyId, value);
      } catch (Exception e) {
        // ignore it
      }
    }

    // store value if noone "objects"
    super.setProperty(propertyId, value);
  } // setProperty(String,Object)
  /**
   * Set the state of a feature.
   *
   * <p>Set the state of any feature in a SAX2 parser. The parser might not recognize the feature,
   * and if it does recognize it, it might not be able to fulfill the request.
   *
   * @param featureId The unique identifier (URI) of the feature.
   * @param state The requested state of the feature (true or false).
   * @exception org.apache.xerces.xni.parser.XMLConfigurationException If the requested feature is
   *     not known.
   */
  public void setFeature(String featureId, boolean state) throws XMLConfigurationException {
    fConfigUpdated = true;
    // forward to every XML 1.0 component
    int count = fComponents.size();
    for (int i = 0; i < count; i++) {
      XMLComponent c = (XMLComponent) fComponents.get(i);
      c.setFeature(featureId, state);
    }
    // forward it to common components
    count = fCommonComponents.size();
    for (int i = 0; i < count; i++) {
      XMLComponent c = (XMLComponent) fCommonComponents.get(i);
      c.setFeature(featureId, state);
    }

    // forward to every XML 1.1 component
    count = fXML11Components.size();
    for (int i = 0; i < count; i++) {
      XMLComponent c = (XMLComponent) fXML11Components.get(i);
      try {
        c.setFeature(featureId, state);
      } catch (Exception e) {
        // no op
      }
    }
    // save state if noone "objects"
    super.setFeature(featureId, state);
  } // setFeature(String,boolean)
 /** Sets a feature. */
 public void setFeature(String featureId, boolean state) throws XMLConfigurationException {
   super.setFeature(featureId, state);
   int size = fHTMLComponents.size();
   for (int i = 0; i < size; i++) {
     HTMLComponent component = (HTMLComponent) fHTMLComponents.elementAt(i);
     component.setFeature(featureId, state);
   }
 } // setFeature(String,boolean)
  /**
   * Check a property. If the property is know and supported, this method simply returns. Otherwise,
   * the appropriate exception is thrown.
   *
   * @param propertyId The unique identifier (URI) of the property being set.
   * @throws XMLConfigurationException Thrown for configuration error. In general, components should
   *     only throw this exception if it is <strong>really</strong> a critical error.
   */
  protected void checkProperty(String propertyId) throws XMLConfigurationException {

    //
    // Xerces Properties
    //

    if (propertyId.startsWith(Constants.XERCES_PROPERTY_PREFIX)) {
      final int suffixLength = propertyId.length() - Constants.XERCES_PROPERTY_PREFIX.length();

      if (suffixLength == Constants.DTD_SCANNER_PROPERTY.length()
          && propertyId.endsWith(Constants.DTD_SCANNER_PROPERTY)) {
        return;
      }
    }

    // special cases
    if (propertyId.startsWith(Constants.SAX_PROPERTY_PREFIX)) {
      final int suffixLength = propertyId.length() - Constants.SAX_PROPERTY_PREFIX.length();

      //
      // http://xml.org/sax/properties/xml-string
      // Value type: String
      // Access: read-only
      //   Get the literal string of characters associated with the
      //   current event.  If the parser recognises and supports this
      //   property but is not currently parsing text, it should return
      //   null (this is a good way to check for availability before the
      //   parse begins).
      //
      if (suffixLength == Constants.XML_STRING_PROPERTY.length()
          && propertyId.endsWith(Constants.XML_STRING_PROPERTY)) {
        // REVISIT - we should probably ask xml-dev for a precise
        // definition of what this is actually supposed to return, and
        // in exactly which circumstances.
        short type = XMLConfigurationException.NOT_SUPPORTED;
        throw new XMLConfigurationException(type, propertyId);
      }
    }

    //
    // Not recognized
    //

    super.checkProperty(propertyId);
  } // checkProperty(String)
  /** Sets a property. */
  public void setProperty(String propertyId, Object value) throws XMLConfigurationException {
    super.setProperty(propertyId, value);

    if (propertyId.equals(FILTERS)) {
      XMLDocumentFilter[] filters = (XMLDocumentFilter[]) getProperty(FILTERS);
      if (filters != null) {
        for (int i = 0; i < filters.length; i++) {
          XMLDocumentFilter filter = filters[i];
          if (filter instanceof HTMLComponent) {
            addComponent((HTMLComponent) filter);
          }
        }
      }
    }

    int size = fHTMLComponents.size();
    for (int i = 0; i < size; i++) {
      HTMLComponent component = (HTMLComponent) fHTMLComponents.elementAt(i);
      component.setProperty(propertyId, value);
    }
  } // setProperty(String,Object)
  /**
   * Check a feature. If feature is know and supported, this method simply returns. Otherwise, the
   * appropriate exception is thrown.
   *
   * @param featureId The unique identifier (URI) of the feature.
   * @throws XMLConfigurationException Thrown for configuration error. In general, components should
   *     only throw this exception if it is <strong>really</strong> a critical error.
   */
  protected void checkFeature(String featureId) throws XMLConfigurationException {

    //
    // Xerces Features
    //

    if (featureId.startsWith(Constants.XERCES_FEATURE_PREFIX)) {
      final int suffixLength = featureId.length() - Constants.XERCES_FEATURE_PREFIX.length();

      //
      // http://apache.org/xml/features/validation/dynamic
      //   Allows the parser to validate a document only when it
      //   contains a grammar. Validation is turned on/off based
      //   on each document instance, automatically.
      //
      if (suffixLength == Constants.DYNAMIC_VALIDATION_FEATURE.length()
          && featureId.endsWith(Constants.DYNAMIC_VALIDATION_FEATURE)) {
        return;
      }

      //
      // http://apache.org/xml/features/validation/default-attribute-values
      //
      if (suffixLength == Constants.DEFAULT_ATTRIBUTE_VALUES_FEATURE.length()
          && featureId.endsWith(Constants.DEFAULT_ATTRIBUTE_VALUES_FEATURE)) {
        // REVISIT
        short type = XMLConfigurationException.NOT_SUPPORTED;
        throw new XMLConfigurationException(type, featureId);
      }
      //
      // http://apache.org/xml/features/validation/default-attribute-values
      //
      if (suffixLength == Constants.VALIDATE_CONTENT_MODELS_FEATURE.length()
          && featureId.endsWith(Constants.VALIDATE_CONTENT_MODELS_FEATURE)) {
        // REVISIT
        short type = XMLConfigurationException.NOT_SUPPORTED;
        throw new XMLConfigurationException(type, featureId);
      }
      //
      // http://apache.org/xml/features/validation/nonvalidating/load-dtd-grammar
      //
      if (suffixLength == Constants.LOAD_DTD_GRAMMAR_FEATURE.length()
          && featureId.endsWith(Constants.LOAD_DTD_GRAMMAR_FEATURE)) {
        return;
      }
      //
      // http://apache.org/xml/features/validation/nonvalidating/load-external-dtd
      //
      if (suffixLength == Constants.LOAD_EXTERNAL_DTD_FEATURE.length()
          && featureId.endsWith(Constants.LOAD_EXTERNAL_DTD_FEATURE)) {
        return;
      }

      //
      // http://apache.org/xml/features/validation/default-attribute-values
      //
      if (suffixLength == Constants.VALIDATE_DATATYPES_FEATURE.length()
          && featureId.endsWith(Constants.VALIDATE_DATATYPES_FEATURE)) {
        short type = XMLConfigurationException.NOT_SUPPORTED;
        throw new XMLConfigurationException(type, featureId);
      }

      // special performance feature: only component manager is allowed to set it.
      if (suffixLength == Constants.PARSER_SETTINGS.length()
          && featureId.endsWith(Constants.PARSER_SETTINGS)) {
        short type = XMLConfigurationException.NOT_SUPPORTED;
        throw new XMLConfigurationException(type, featureId);
      }
    }

    //
    // Not recognized
    //

    super.checkFeature(featureId);
  } // checkFeature(String)