content: /*
   *  This file is part of AndroidIDE.
   *
   *  AndroidIDE is free software: you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License as published by
   *  the Free Software Foundation, either version 3 of the License, or
   *  (at your option) any later version.
   *
   *  AndroidIDE is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *  GNU General Public License for more details.
   *
   *  You should have received a copy of the GNU General Public License
   *   along with AndroidIDE.  If not, see <https://www.gnu.org/licenses/>.
   */
  
  /*
   * reserved comment block
   * DO NOT REMOVE OR ALTER!
   */
  /*
   * Copyright 2005 The Apache Software Foundation.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package jaxp.sun.org.apache.xerces.internal.jaxp.validation;
  
  import java.util.HashMap;
  import java.util.Locale;
  import java.util.Iterator;
  import java.util.Map;
  
  import jaxp.xml.XMLConstants;
  
  import jaxp.sun.org.apache.xerces.internal.impl.Constants;
  import jaxp.sun.org.apache.xerces.internal.impl.XMLEntityManager;
  import jaxp.sun.org.apache.xerces.internal.impl.XMLErrorReporter;
  import jaxp.sun.org.apache.xerces.internal.impl.validation.ValidationManager;
  import jaxp.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator;
  import jaxp.sun.org.apache.xerces.internal.impl.xs.XSMessageFormatter;
  import jaxp.sun.org.apache.xerces.internal.util.DOMEntityResolverWrapper;
  import jaxp.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper;
  import jaxp.sun.org.apache.xerces.internal.util.FeatureState;
  import jaxp.sun.org.apache.xerces.internal.util.NamespaceSupport;
  import jaxp.sun.org.apache.xerces.internal.util.ParserConfigurationSettings;
  import jaxp.sun.org.apache.xerces.internal.util.PropertyState;
  import jaxp.sun.org.apache.xerces.internal.util.Status;
  import jaxp.sun.org.apache.xerces.internal.util.SymbolTable;
  import jaxp.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager;
  import jaxp.sun.org.apache.xerces.internal.utils.XMLSecurityManager;
  import jaxp.sun.org.apache.xerces.internal.xni.NamespaceContext;
  import jaxp.sun.org.apache.xerces.internal.xni.XNIException;
  import jaxp.sun.org.apache.xerces.internal.xni.parser.XMLComponent;
  import jaxp.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
  import jaxp.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
  import org.w3c.dom.ls.LSResourceResolver;
  import org.xml.sax.ErrorHandler;
  
  /**
   * <p>An implementation of XMLComponentManager for a schema validator.</p>
   *
   * @author Michael Glavassevich, IBM
   * @version $Id: XMLSchemaValidatorComponentManager.java,v 1.9 2010-11-01 04:40:08 joehw Exp $
   */
  final class XMLSchemaValidatorComponentManager extends ParserConfigurationSettings implements
    XMLComponentManager {
  
      // feature identifiers
  
      /** Feature identifier: schema validation. */
      private static final String SCHEMA_VALIDATION =
          Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE;
  
      /** Feature identifier: validation. */
      private static final String VALIDATION =
          Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE;
  
      /** Feature identifier: send element default value via characters() */
      private static final String SCHEMA_ELEMENT_DEFAULT =
          Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_ELEMENT_DEFAULT;
  
      /** Feature identifier: use grammar pool only. */
      private static final String USE_GRAMMAR_POOL_ONLY =
          Constants.XERCES_FEATURE_PREFIX + Constants.USE_GRAMMAR_POOL_ONLY_FEATURE;
  
      // property identifiers
  
      /** Property identifier: entity manager. */
      private static final String ENTITY_MANAGER =
          Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY;
  
      /** Property identifier: entity resolver. */
      private static final String ENTITY_RESOLVER =
          Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY;
  
      /** Property identifier: error handler. */
      private static final String ERROR_HANDLER =
          Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_HANDLER_PROPERTY;
  
      /** Property identifier: error reporter. */
      private static final String ERROR_REPORTER =
          Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY;
  
      /** Property identifier: namespace context. */
      private static final String NAMESPACE_CONTEXT =
          Constants.XERCES_PROPERTY_PREFIX + Constants.NAMESPACE_CONTEXT_PROPERTY;
  
      /** Property identifier: XML Schema validator. */
      private static final String SCHEMA_VALIDATOR =
          Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_VALIDATOR_PROPERTY;
  
      /** Property identifier: security manager. */
      private static final String SECURITY_MANAGER =
          Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY;
  
      /** Property identifier: security property manager. */
      private static final String XML_SECURITY_PROPERTY_MANAGER =
              Constants.XML_SECURITY_PROPERTY_MANAGER;
  
      /** Property identifier: symbol table. */
      private static final String SYMBOL_TABLE =
          Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
  
      /** Property identifier: validation manager. */
      private static final String VALIDATION_MANAGER =
          Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY;
  
      /** Property identifier: grammar pool. */
      private static final String XMLGRAMMAR_POOL =
          Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY;
  
      /** Property identifier: locale. */
      private static final String LOCALE =
          Constants.XERCES_PROPERTY_PREFIX + Constants.LOCALE_PROPERTY;
  
      //
      // Data
      //
      /**
       * <p>State of secure mode.</p>
       */
      private boolean _isSecureMode = false;
  
      /**
       * fConfigUpdated is set to true if there has been any change to the configuration settings,
       * i.e a feature or a property was changed.
       */
      private boolean fConfigUpdated = true;
  
      /**
       * Tracks whether the validator should use components from
       * the grammar pool to the exclusion of all others.
       */
      private boolean fUseGrammarPoolOnly;
  
      /** Lookup map for components required for validation. **/
      private final HashMap fComponents = new HashMap();
  
      //
      // Components
      //
  
      /** Entity manager. */
      private XMLEntityManager fEntityManager;
  
      /** Error reporter. */
      private XMLErrorReporter fErrorReporter;
  
      /** Namespace context. */
      private NamespaceContext fNamespaceContext;
  
      /** XML Schema validator. */
      private XMLSchemaValidator fSchemaValidator;
  
      /** Validation manager. */
      private ValidationManager fValidationManager;
  
      //
      // Configuration
      //
  
      /** Stores initial feature values for validator reset. */
      private final HashMap fInitFeatures = new HashMap();
  
      /** Stores initial property values for validator reset. */
      private final HashMap fInitProperties = new HashMap();
  
      /** Stores the initial security manager. */
      private XMLSecurityManager fInitSecurityManager;
  
      /** Stores the initial security property manager. */
      private final XMLSecurityPropertyManager fSecurityPropertyMgr;
  
      //
      // User Objects
      //
  
      /** Application's ErrorHandler. **/
      private ErrorHandler fErrorHandler = null;
  
      /** Application's LSResourceResolver. */
      private LSResourceResolver fResourceResolver = null;
  
      /** Locale chosen by the application. */
      private Locale fLocale = null;
  
      /** Constructs a component manager suitable for Xerces' schema validator. */
      public XMLSchemaValidatorComponentManager(XSGrammarPoolContainer grammarContainer) {
          // setup components
          fEntityManager = new XMLEntityManager();
          fComponents.put(ENTITY_MANAGER, fEntityManager);
  
          fErrorReporter = new XMLErrorReporter();
          fComponents.put(ERROR_REPORTER, fErrorReporter);
  
          fNamespaceContext = new NamespaceSupport();
          fComponents.put(NAMESPACE_CONTEXT, fNamespaceContext);
  
          fSchemaValidator = new XMLSchemaValidator();
          fComponents.put(SCHEMA_VALIDATOR, fSchemaValidator);
  
          fValidationManager = new ValidationManager();
          fComponents.put(VALIDATION_MANAGER, fValidationManager);
  
          // setup other properties
          fComponents.put(ENTITY_RESOLVER, null);
          fComponents.put(ERROR_HANDLER, null);
  
          fComponents.put(SYMBOL_TABLE, new SymbolTable());
  
          // setup grammar pool
          fComponents.put(XMLGRAMMAR_POOL, grammarContainer.getGrammarPool());
          fUseGrammarPoolOnly = grammarContainer.isFullyComposed();
  
          // add schema message formatter to error reporter
          fErrorReporter.putMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN, new XSMessageFormatter());
  
          // add all recognized features and properties and apply their defaults
          addRecognizedParamsAndSetDefaults(fEntityManager, grammarContainer);
          addRecognizedParamsAndSetDefaults(fErrorReporter, grammarContainer);
          addRecognizedParamsAndSetDefaults(fSchemaValidator, grammarContainer);
  
          boolean secureProcessing = grammarContainer.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING);
          if (System.getSecurityManager() != null) {
              _isSecureMode = true;
              secureProcessing = true;
          }
  
          fInitSecurityManager = (XMLSecurityManager)
                  grammarContainer.getProperty(SECURITY_MANAGER);
          if (fInitSecurityManager != null ) {
              fInitSecurityManager.setSecureProcessing(secureProcessing);
          } else {
              fInitSecurityManager = new XMLSecurityManager(secureProcessing);
          }
  
          setProperty(SECURITY_MANAGER, fInitSecurityManager);
  
          //pass on properties set on SchemaFactory
          fSecurityPropertyMgr = (XMLSecurityPropertyManager)
                  grammarContainer.getProperty(Constants.XML_SECURITY_PROPERTY_MANAGER);
          setProperty(XML_SECURITY_PROPERTY_MANAGER, fSecurityPropertyMgr);
      }
  
      /**
       * Returns the state of a feature.
       *
       * @param featureId The feature identifier.
       * @return true if the feature is supported
       *
       * @throws XMLConfigurationException Thrown for configuration error.
       *                                   In general, components should
       *                                   only throw this exception if
       *                                   it is <strong>really</strong>
       *                                   a critical error.
       */
      public FeatureState getFeatureState(String featureId)
              throws XMLConfigurationException {
          if (PARSER_SETTINGS.equals(featureId)) {
              return FeatureState.is(fConfigUpdated);
          }
          else if (VALIDATION.equals(featureId) || SCHEMA_VALIDATION.equals(featureId)) {
              return FeatureState.is(true);
          }
          else if (USE_GRAMMAR_POOL_ONLY.equals(featureId)) {
              return FeatureState.is(fUseGrammarPoolOnly);
          }
          else if (XMLConstants.FEATURE_SECURE_PROCESSING.equals(featureId)) {
              return FeatureState.is(fInitSecurityManager.isSecureProcessing());
          }
          else if (SCHEMA_ELEMENT_DEFAULT.equals(featureId)) {
              return FeatureState.is(true); //pre-condition: VALIDATION and SCHEMA_VALIDATION are always true
          }
          return super.getFeatureState(featureId);
      }
  
      /**
       * 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);
      }
  
      /**
       * Returns the value of a property.
       *
       * @param propertyId The property identifier.
       * @return the value of the property
       *
       * @throws XMLConfigurationException Thrown for configuration error.
       *                                   In general, components should
       *                                   only throw this exception if
       *                                   it is <strong>really</strong>
       *                                   a critical error.
       */
      public PropertyState getPropertyState(String propertyId)
              throws XMLConfigurationException {
          if (LOCALE.equals(propertyId)) {
              return PropertyState.is(getLocale());
          }
          final Object component = fComponents.get(propertyId);
          if (component != null) {
              return PropertyState.is(component);
          }
          else if (fComponents.containsKey(propertyId)) {
              return PropertyState.is(null);
          }
          return super.getPropertyState(propertyId);
      }
  
      /**
       * 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);
              }
          }
      }
  
      /**
       * Adds all of the component's recognized features and properties
       * to the list of default recognized features and properties, and
       * sets default values on the configuration for features and
       * properties which were previously absent from the configuration.
       *
       * @param component The component whose recognized features
       * and properties will be added to the configuration
       */
      public void addRecognizedParamsAndSetDefaults(XMLComponent component, XSGrammarPoolContainer grammarContainer) {
  
          // register component's recognized features
          final String[] recognizedFeatures = component.getRecognizedFeatures();
          addRecognizedFeatures(recognizedFeatures);
  
          // register component's recognized properties
          final String[] recognizedProperties = component.getRecognizedProperties();
          addRecognizedProperties(recognizedProperties);
  
          // set default values
          setFeatureDefaults(component, recognizedFeatures, grammarContainer);
          setPropertyDefaults(component, recognizedProperties);
      }
  
      /** Calls reset on each of the components owned by this component manager. **/
      public void reset() throws XNIException {
          fNamespaceContext.reset();
          fValidationManager.reset();
          fEntityManager.reset(this);
          fErrorReporter.reset(this);
          fSchemaValidator.reset(this);
          // Mark configuration as fixed.
          fConfigUpdated = false;
      }
  
      void setErrorHandler(ErrorHandler errorHandler) {
          fErrorHandler = errorHandler;
          setProperty(ERROR_HANDLER, (errorHandler != null) ? new ErrorHandlerWrapper(errorHandler) :
                  new ErrorHandlerWrapper(DraconianErrorHandler.getInstance()));
      }
  
      ErrorHandler getErrorHandler() {
          return fErrorHandler;
      }
  
      void setResourceResolver(LSResourceResolver resourceResolver) {
          fResourceResolver = resourceResolver;
          setProperty(ENTITY_RESOLVER, new DOMEntityResolverWrapper(resourceResolver));
      }
  
      LSResourceResolver getResourceResolver() {
          return fResourceResolver;
      }
  
      void setLocale(Locale locale) {
          fLocale = locale;
          fErrorReporter.setLocale(locale);
      }
  
      Locale getLocale() {
          return fLocale;
      }
  
      /** 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 feature defaults for the given component on this configuration. */
      private void setFeatureDefaults(final XMLComponent component,
              final String [] recognizedFeatures, XSGrammarPoolContainer grammarContainer) {
          if (recognizedFeatures != null) {
              for (int i = 0; i < recognizedFeatures.length; ++i) {
                  String featureId = recognizedFeatures[i];
                  Boolean state = grammarContainer.getFeature(featureId);
                  if (state == null) {
                      state = component.getFeatureDefault(featureId);
                  }
                  if (state != null) {
                      // Do not overwrite values already set on the configuration.
                      if (!fFeatures.containsKey(featureId)) {
                          fFeatures.put(featureId, state);
                          // For newly added components who recognize this feature
                          // but did not offer a default value, we need to make
                          // sure these components will get an opportunity to read
                          // the value before parsing begins.
                          fConfigUpdated = true;
                      }
                  }
              }
          }
      }
  
      /** Sets property defaults for the given component on this configuration. */
      private void setPropertyDefaults(final XMLComponent component, final String [] recognizedProperties) {
          if (recognizedProperties != null) {
              for (int i = 0; i < recognizedProperties.length; ++i) {
                  String propertyId = recognizedProperties[i];
                  Object value = component.getPropertyDefault(propertyId);
                  if (value != null) {
                      // Do not overwrite values already set on the configuration.
                      if (!fProperties.containsKey(propertyId)) {
                          fProperties.put(propertyId, value);
                          // For newly added components who recognize this property
                          // but did not offer a default value, we need to make
                          // sure these components will get an opportunity to read
                          // the value before parsing begins.
                          fConfigUpdated = true;
                      }
                  }
              }
          }
      }
  
  } // XMLSchemaValidatorComponentManager
  