1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * Copyright 2005 The Apache Software Foundation.
   7  *
   8  * Licensed under the Apache License, Version 2.0 (the "License");
   9  * you may not use this file except in compliance with the License.
  10  * 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 java.util.HashMap;
  24 import java.util.Locale;
  25 import java.util.Iterator;
  26 import java.util.Map;
  27 
  28 import javax.xml.XMLConstants;
  29 
  30 import com.sun.org.apache.xerces.internal.impl.Constants;
  31 import com.sun.org.apache.xerces.internal.impl.XMLEntityManager;
  32 import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter;
  33 import com.sun.org.apache.xerces.internal.impl.validation.ValidationManager;
  34 import com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator;
  35 import com.sun.org.apache.xerces.internal.impl.xs.XSMessageFormatter;
  36 import com.sun.org.apache.xerces.internal.util.DOMEntityResolverWrapper;
  37 import com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper;
  38 import com.sun.org.apache.xerces.internal.util.FeatureState;
  39 import com.sun.org.apache.xerces.internal.util.NamespaceSupport;
  40 import com.sun.org.apache.xerces.internal.util.ParserConfigurationSettings;
  41 import com.sun.org.apache.xerces.internal.util.PropertyState;
  42 import com.sun.org.apache.xerces.internal.util.SecurityManager;
  43 import com.sun.org.apache.xerces.internal.util.Status;
  44 import com.sun.org.apache.xerces.internal.util.SymbolTable;
  45 import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager;
  46 import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
  47 import com.sun.org.apache.xerces.internal.xni.XNIException;
  48 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent;
  49 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
  50 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
  51 import org.w3c.dom.ls.LSResourceResolver;
  52 import org.xml.sax.ErrorHandler;
  53 
  54 /**
  55  * <p>An implementation of XMLComponentManager for a schema validator.</p>
  56  *
  57  * @author Michael Glavassevich, IBM
  58  * @version $Id: XMLSchemaValidatorComponentManager.java,v 1.9 2010-11-01 04:40:08 joehw Exp $
  59  */
  60 final class XMLSchemaValidatorComponentManager extends ParserConfigurationSettings implements
  61         XMLComponentManager {
  62 
  63     // feature identifiers
  64 
  65     /** Feature identifier: schema validation. */
  66     private static final String SCHEMA_VALIDATION =
  67         Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE;
  68 
  69     /** Feature identifier: validation. */
  70     private static final String VALIDATION =
  71         Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE;
  72 
  73     /** Feature identifier: send element default value via characters() */
  74     private static final String SCHEMA_ELEMENT_DEFAULT =
  75         Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_ELEMENT_DEFAULT;
  76 
  77     /** Feature identifier: use grammar pool only. */
  78     private static final String USE_GRAMMAR_POOL_ONLY =
  79         Constants.XERCES_FEATURE_PREFIX + Constants.USE_GRAMMAR_POOL_ONLY_FEATURE;
  80 
  81     // property identifiers
  82 
  83     /** Property identifier: entity manager. */
  84     private static final String ENTITY_MANAGER =
  85         Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY;
  86 
  87     /** Property identifier: entity resolver. */
  88     private static final String ENTITY_RESOLVER =
  89         Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY;
  90 
  91     /** Property identifier: error handler. */
  92     private static final String ERROR_HANDLER =
  93         Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_HANDLER_PROPERTY;
  94 
  95     /** Property identifier: error reporter. */
  96     private static final String ERROR_REPORTER =
  97         Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY;
  98 
  99     /** Property identifier: namespace context. */
 100     private static final String NAMESPACE_CONTEXT =
 101         Constants.XERCES_PROPERTY_PREFIX + Constants.NAMESPACE_CONTEXT_PROPERTY;
 102 
 103     /** Property identifier: XML Schema validator. */
 104     private static final String SCHEMA_VALIDATOR =
 105         Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_VALIDATOR_PROPERTY;
 106 
 107     /** Property identifier: security manager. */
 108     private static final String SECURITY_MANAGER =
 109         Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY;
 110 
 111     /** Property identifier: security property manager. */
 112     private static final String XML_SECURITY_PROPERTY_MANAGER =
 113             Constants.XML_SECURITY_PROPERTY_MANAGER;
 114 
 115     /** Property identifier: symbol table. */
 116     private static final String SYMBOL_TABLE =
 117         Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
 118 
 119     /** Property identifier: validation manager. */
 120     private static final String VALIDATION_MANAGER =
 121         Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY;
 122 
 123     /** Property identifier: grammar pool. */
 124     private static final String XMLGRAMMAR_POOL =
 125         Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY;
 126 
 127     /** Property identifier: locale. */
 128     private static final String LOCALE =
 129         Constants.XERCES_PROPERTY_PREFIX + Constants.LOCALE_PROPERTY;
 130 
 131     //
 132     // Data
 133     //
 134     /**
 135      * <p>State of secure mode.</p>
 136      */
 137     private boolean _isSecureMode = false;
 138 
 139     /**
 140      * fConfigUpdated is set to true if there has been any change to the configuration settings,
 141      * i.e a feature or a property was changed.
 142      */
 143     private boolean fConfigUpdated = true;
 144 
 145     /**
 146      * Tracks whether the validator should use components from
 147      * the grammar pool to the exclusion of all others.
 148      */
 149     private boolean fUseGrammarPoolOnly;
 150 
 151     /** Lookup map for components required for validation. **/
 152     private final HashMap fComponents = new HashMap();
 153 
 154     //
 155     // Components
 156     //
 157 
 158     /** Entity manager. */
 159     private XMLEntityManager fEntityManager;
 160 
 161     /** Error reporter. */
 162     private XMLErrorReporter fErrorReporter;
 163 
 164     /** Namespace context. */
 165     private NamespaceContext fNamespaceContext;
 166 
 167     /** XML Schema validator. */
 168     private XMLSchemaValidator fSchemaValidator;
 169 
 170     /** Validation manager. */
 171     private ValidationManager fValidationManager;
 172 
 173     //
 174     // Configuration
 175     //
 176 
 177     /** Stores initial feature values for validator reset. */
 178     private final HashMap fInitFeatures = new HashMap();
 179 
 180     /** Stores initial property values for validator reset. */
 181     private final HashMap fInitProperties = new HashMap();
 182 
 183     /** Stores the initial security manager. */
 184     private final SecurityManager fInitSecurityManager;
 185 
 186     /** Stores the initial security property manager. */
 187     private final XMLSecurityPropertyManager fSecurityPropertyMgr;
 188 
 189     //
 190     // User Objects
 191     //
 192 
 193     /** Application's ErrorHandler. **/
 194     private ErrorHandler fErrorHandler = null;
 195 
 196     /** Application's LSResourceResolver. */
 197     private LSResourceResolver fResourceResolver = null;
 198 
 199     /** Locale chosen by the application. */
 200     private Locale fLocale = null;
 201 
 202     /** Constructs a component manager suitable for Xerces' schema validator. */
 203     public XMLSchemaValidatorComponentManager(XSGrammarPoolContainer grammarContainer) {
 204         // setup components
 205         fEntityManager = new XMLEntityManager();
 206         fComponents.put(ENTITY_MANAGER, fEntityManager);
 207 
 208         fErrorReporter = new XMLErrorReporter();
 209         fComponents.put(ERROR_REPORTER, fErrorReporter);
 210 
 211         fNamespaceContext = new NamespaceSupport();
 212         fComponents.put(NAMESPACE_CONTEXT, fNamespaceContext);
 213 
 214         fSchemaValidator = new XMLSchemaValidator();
 215         fComponents.put(SCHEMA_VALIDATOR, fSchemaValidator);
 216 
 217         fValidationManager = new ValidationManager();
 218         fComponents.put(VALIDATION_MANAGER, fValidationManager);
 219 
 220         // setup other properties
 221         fComponents.put(ENTITY_RESOLVER, null);
 222         fComponents.put(ERROR_HANDLER, null);
 223 
 224         if (System.getSecurityManager() != null) {
 225             _isSecureMode = true;
 226             setProperty(SECURITY_MANAGER, new SecurityManager());
 227         } else {
 228             fComponents.put(SECURITY_MANAGER, null);
 229         }
 230         fComponents.put(SYMBOL_TABLE, new SymbolTable());
 231 
 232         // setup grammar pool
 233         fComponents.put(XMLGRAMMAR_POOL, grammarContainer.getGrammarPool());
 234         fUseGrammarPoolOnly = grammarContainer.isFullyComposed();
 235 
 236         // add schema message formatter to error reporter
 237         fErrorReporter.putMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN, new XSMessageFormatter());
 238 
 239         // add all recognized features and properties and apply their defaults
 240         addRecognizedParamsAndSetDefaults(fEntityManager, grammarContainer);
 241         addRecognizedParamsAndSetDefaults(fErrorReporter, grammarContainer);
 242         addRecognizedParamsAndSetDefaults(fSchemaValidator, grammarContainer);
 243 
 244         // if the secure processing feature is set to true, add a security manager to the configuration
 245         Boolean secureProcessing = grammarContainer.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING);
 246         if (Boolean.TRUE.equals(secureProcessing)) {
 247             fInitSecurityManager = new SecurityManager();
 248         }
 249         else {
 250             fInitSecurityManager = null;
 251         }
 252         fComponents.put(SECURITY_MANAGER, fInitSecurityManager);
 253 
 254         //pass on properties set on SchemaFactory
 255         fSecurityPropertyMgr = (XMLSecurityPropertyManager)
 256                 grammarContainer.getProperty(Constants.XML_SECURITY_PROPERTY_MANAGER);
 257         setProperty(XML_SECURITY_PROPERTY_MANAGER, fSecurityPropertyMgr);
 258     }
 259 
 260     /**
 261      * Returns the state of a feature.
 262      *
 263      * @param featureId The feature identifier.
 264      * @return true if the feature is supported
 265      *
 266      * @throws XMLConfigurationException Thrown for configuration error.
 267      *                                   In general, components should
 268      *                                   only throw this exception if
 269      *                                   it is <strong>really</strong>
 270      *                                   a critical error.
 271      */
 272     public FeatureState getFeatureState(String featureId)
 273             throws XMLConfigurationException {
 274         if (PARSER_SETTINGS.equals(featureId)) {
 275             return FeatureState.is(fConfigUpdated);
 276         }
 277         else if (VALIDATION.equals(featureId) || SCHEMA_VALIDATION.equals(featureId)) {
 278             return FeatureState.is(true);
 279         }
 280         else if (USE_GRAMMAR_POOL_ONLY.equals(featureId)) {
 281             return FeatureState.is(fUseGrammarPoolOnly);
 282         }
 283         else if (XMLConstants.FEATURE_SECURE_PROCESSING.equals(featureId)) {
 284             return FeatureState.is(getProperty(SECURITY_MANAGER) != null);
 285         }
 286         else if (SCHEMA_ELEMENT_DEFAULT.equals(featureId)) {
 287             return FeatureState.is(true); //pre-condition: VALIDATION and SCHEMA_VALIDATION are always true
 288         }
 289         return super.getFeatureState(featureId);
 290     }
 291 
 292     /**
 293      * Set the state of a feature.
 294      *
 295      * @param featureId The unique identifier (URI) of the feature.
 296      * @param state The requested state of the feature (true or false).
 297      *
 298      * @exception XMLConfigurationException If the requested feature is not known.
 299      */
 300     public void setFeature(String featureId, boolean value) throws XMLConfigurationException {
 301         if (PARSER_SETTINGS.equals(featureId)) {
 302             throw new XMLConfigurationException(Status.NOT_SUPPORTED, featureId);
 303         }
 304         else if (value == false && (VALIDATION.equals(featureId) || SCHEMA_VALIDATION.equals(featureId))) {
 305             throw new XMLConfigurationException(Status.NOT_SUPPORTED, featureId);
 306         }
 307         else if (USE_GRAMMAR_POOL_ONLY.equals(featureId) && value != fUseGrammarPoolOnly) {
 308             throw new XMLConfigurationException(Status.NOT_SUPPORTED, featureId);
 309         }
 310         if (XMLConstants.FEATURE_SECURE_PROCESSING.equals(featureId)) {
 311             if (_isSecureMode && !value) {
 312                 throw new XMLConfigurationException(Status.NOT_ALLOWED, XMLConstants.FEATURE_SECURE_PROCESSING);
 313             }
 314             setProperty(SECURITY_MANAGER, value ? new SecurityManager() : null);
 315             
 316             if (value && Constants.IS_JDK8_OR_ABOVE) {
 317                 fSecurityPropertyMgr.setValue(XMLSecurityPropertyManager.Property.ACCESS_EXTERNAL_DTD, 
 318                         XMLSecurityPropertyManager.State.FSP, Constants.EXTERNAL_ACCESS_DEFAULT_FSP);
 319                 fSecurityPropertyMgr.setValue(XMLSecurityPropertyManager.Property.ACCESS_EXTERNAL_SCHEMA, 
 320                         XMLSecurityPropertyManager.State.FSP, Constants.EXTERNAL_ACCESS_DEFAULT_FSP);
 321                 setProperty(XML_SECURITY_PROPERTY_MANAGER, fSecurityPropertyMgr);                
 322             }
 323 
 324             return;
 325         }
 326         fConfigUpdated = true;
 327         fEntityManager.setFeature(featureId, value);
 328         fErrorReporter.setFeature(featureId, value);
 329         fSchemaValidator.setFeature(featureId, value);
 330         if (!fInitFeatures.containsKey(featureId)) {
 331             boolean current = super.getFeature(featureId);
 332             fInitFeatures.put(featureId, current ? Boolean.TRUE : Boolean.FALSE);
 333         }
 334         super.setFeature(featureId, value);
 335     }
 336 
 337     /**
 338      * Returns the value of a property.
 339      *
 340      * @param propertyId The property identifier.
 341      * @return the value of the property
 342      *
 343      * @throws XMLConfigurationException Thrown for configuration error.
 344      *                                   In general, components should
 345      *                                   only throw this exception if
 346      *                                   it is <strong>really</strong>
 347      *                                   a critical error.
 348      */
 349     public PropertyState getPropertyState(String propertyId)
 350             throws XMLConfigurationException {
 351         if (LOCALE.equals(propertyId)) {
 352             return PropertyState.is(getLocale());
 353         }
 354         final Object component = fComponents.get(propertyId);
 355         if (component != null) {
 356             return PropertyState.is(component);
 357         }
 358         else if (fComponents.containsKey(propertyId)) {
 359             return PropertyState.is(null);
 360         }
 361         return super.getPropertyState(propertyId);
 362     }
 363 
 364     /**
 365      * Sets the state of a property.
 366      *
 367      * @param propertyId The unique identifier (URI) of the property.
 368      * @param value The requested state of the property.
 369      *
 370      * @exception XMLConfigurationException If the requested property is not known.
 371      */
 372     public void setProperty(String propertyId, Object value) throws XMLConfigurationException {
 373         if ( ENTITY_MANAGER.equals(propertyId) || ERROR_REPORTER.equals(propertyId) ||
 374              NAMESPACE_CONTEXT.equals(propertyId) || SCHEMA_VALIDATOR.equals(propertyId) ||
 375              SYMBOL_TABLE.equals(propertyId) || VALIDATION_MANAGER.equals(propertyId) ||
 376              XMLGRAMMAR_POOL.equals(propertyId)) {
 377             throw new XMLConfigurationException(Status.NOT_SUPPORTED, propertyId);
 378         }
 379         fConfigUpdated = true;
 380         fEntityManager.setProperty(propertyId, value);
 381         fErrorReporter.setProperty(propertyId, value);
 382         fSchemaValidator.setProperty(propertyId, value);
 383         if (ENTITY_RESOLVER.equals(propertyId) || ERROR_HANDLER.equals(propertyId) ||
 384                 SECURITY_MANAGER.equals(propertyId)) {
 385             fComponents.put(propertyId, value);
 386             return;
 387         }
 388         else if (LOCALE.equals(propertyId)) {
 389             setLocale((Locale) value);
 390             fComponents.put(propertyId, value);
 391             return;
 392         }
 393         if (!fInitProperties.containsKey(propertyId)) {
 394             fInitProperties.put(propertyId, super.getProperty(propertyId));
 395         }
 396         super.setProperty(propertyId, value);
 397     }
 398 
 399     /**
 400      * Adds all of the component's recognized features and properties
 401      * to the list of default recognized features and properties, and
 402      * sets default values on the configuration for features and
 403      * properties which were previously absent from the configuration.
 404      *
 405      * @param component The component whose recognized features
 406      * and properties will be added to the configuration
 407      */
 408     public void addRecognizedParamsAndSetDefaults(XMLComponent component, XSGrammarPoolContainer grammarContainer) {
 409 
 410         // register component's recognized features
 411         final String[] recognizedFeatures = component.getRecognizedFeatures();
 412         addRecognizedFeatures(recognizedFeatures);
 413 
 414         // register component's recognized properties
 415         final String[] recognizedProperties = component.getRecognizedProperties();
 416         addRecognizedProperties(recognizedProperties);
 417 
 418         // set default values
 419         setFeatureDefaults(component, recognizedFeatures, grammarContainer);
 420         setPropertyDefaults(component, recognizedProperties);
 421     }
 422 
 423     /** Calls reset on each of the components owned by this component manager. **/
 424     public void reset() throws XNIException {
 425         fNamespaceContext.reset();
 426         fValidationManager.reset();
 427         fEntityManager.reset(this);
 428         fErrorReporter.reset(this);
 429         fSchemaValidator.reset(this);
 430         // Mark configuration as fixed.
 431         fConfigUpdated = false;
 432     }
 433 
 434     void setErrorHandler(ErrorHandler errorHandler) {
 435         fErrorHandler = errorHandler;
 436         setProperty(ERROR_HANDLER, (errorHandler != null) ? new ErrorHandlerWrapper(errorHandler) :
 437                 new ErrorHandlerWrapper(DraconianErrorHandler.getInstance()));
 438     }
 439 
 440     ErrorHandler getErrorHandler() {
 441         return fErrorHandler;
 442     }
 443 
 444     void setResourceResolver(LSResourceResolver resourceResolver) {
 445         fResourceResolver = resourceResolver;
 446         setProperty(ENTITY_RESOLVER, new DOMEntityResolverWrapper(resourceResolver));
 447     }
 448 
 449     LSResourceResolver getResourceResolver() {
 450         return fResourceResolver;
 451     }
 452 
 453     void setLocale(Locale locale) {
 454         fLocale = locale;
 455         fErrorReporter.setLocale(locale);
 456     }
 457 
 458     Locale getLocale() {
 459         return fLocale;
 460     }
 461 
 462     /** Cleans out configuration, restoring it to its initial state. */
 463     void restoreInitialState() {
 464         fConfigUpdated = true;
 465 
 466         // Remove error resolver and error handler
 467         fComponents.put(ENTITY_RESOLVER, null);
 468         fComponents.put(ERROR_HANDLER, null);
 469 
 470         // Set the Locale back to null.
 471         setLocale(null);
 472         fComponents.put(LOCALE, null);
 473 
 474         // Restore initial security manager
 475         fComponents.put(SECURITY_MANAGER, fInitSecurityManager);
 476 
 477         // Set the Locale back to null.
 478         setLocale(null);
 479         fComponents.put(LOCALE, null);
 480 
 481         // Reset feature and property values to their initial values
 482         if (!fInitFeatures.isEmpty()) {
 483             Iterator iter = fInitFeatures.entrySet().iterator();
 484             while (iter.hasNext()) {
 485                 Map.Entry entry = (Map.Entry) iter.next();
 486                 String name = (String) entry.getKey();
 487                 boolean value = ((Boolean) entry.getValue()).booleanValue();
 488                 super.setFeature(name, value);
 489             }
 490             fInitFeatures.clear();
 491         }
 492         if (!fInitProperties.isEmpty()) {
 493             Iterator iter = fInitProperties.entrySet().iterator();
 494             while (iter.hasNext()) {
 495                 Map.Entry entry = (Map.Entry) iter.next();
 496                 String name = (String) entry.getKey();
 497                 Object value = entry.getValue();
 498                 super.setProperty(name, value);
 499             }
 500             fInitProperties.clear();
 501         }
 502     }
 503 
 504     /** Sets feature defaults for the given component on this configuration. */
 505     private void setFeatureDefaults(final XMLComponent component,
 506             final String [] recognizedFeatures, XSGrammarPoolContainer grammarContainer) {
 507         if (recognizedFeatures != null) {
 508             for (int i = 0; i < recognizedFeatures.length; ++i) {
 509                 String featureId = recognizedFeatures[i];
 510                 Boolean state = grammarContainer.getFeature(featureId);
 511                 if (state == null) {
 512                     state = component.getFeatureDefault(featureId);
 513                 }
 514                 if (state != null) {
 515                     // Do not overwrite values already set on the configuration.
 516                     if (!fFeatures.containsKey(featureId)) {
 517                         fFeatures.put(featureId, state);
 518                         // For newly added components who recognize this feature
 519                         // but did not offer a default value, we need to make
 520                         // sure these components will get an opportunity to read
 521                         // the value before parsing begins.
 522                         fConfigUpdated = true;
 523                     }
 524                 }
 525             }
 526         }
 527     }
 528 
 529     /** Sets property defaults for the given component on this configuration. */
 530     private void setPropertyDefaults(final XMLComponent component, final String [] recognizedProperties) {
 531         if (recognizedProperties != null) {
 532             for (int i = 0; i < recognizedProperties.length; ++i) {
 533                 String propertyId = recognizedProperties[i];
 534                 Object value = component.getPropertyDefault(propertyId);
 535                 if (value != null) {
 536                     // Do not overwrite values already set on the configuration.
 537                     if (!fProperties.containsKey(propertyId)) {
 538                         fProperties.put(propertyId, value);
 539                         // For newly added components who recognize this property
 540                         // but did not offer a default value, we need to make
 541                         // sure these components will get an opportunity to read
 542                         // the value before parsing begins.
 543                         fConfigUpdated = true;
 544                     }
 545                 }
 546             }
 547         }
 548     }
 549 
 550 } // XMLSchemaValidatorComponentManager