/* * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 com.sun.org.apache.xerces.internal.impl.xs; import com.sun.org.apache.xerces.internal.dom.DOMErrorImpl; import com.sun.org.apache.xerces.internal.dom.DOMMessageFormatter; import com.sun.org.apache.xerces.internal.dom.DOMStringListImpl; import com.sun.org.apache.xerces.internal.impl.Constants; import com.sun.org.apache.xerces.internal.impl.XMLEntityManager; import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter; import com.sun.org.apache.xerces.internal.impl.dv.InvalidDatatypeValueException; import com.sun.org.apache.xerces.internal.impl.dv.SchemaDVFactory; import com.sun.org.apache.xerces.internal.impl.dv.xs.SchemaDVFactoryImpl; import com.sun.org.apache.xerces.internal.impl.xs.models.CMBuilder; import com.sun.org.apache.xerces.internal.impl.xs.models.CMNodeFactory; import com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler; import com.sun.org.apache.xerces.internal.util.DOMEntityResolverWrapper; import com.sun.org.apache.xerces.internal.util.DOMErrorHandlerWrapper; import com.sun.org.apache.xerces.internal.util.DefaultErrorHandler; import com.sun.org.apache.xerces.internal.util.ParserConfigurationSettings; import com.sun.org.apache.xerces.internal.util.Status; import com.sun.org.apache.xerces.internal.util.SymbolTable; import com.sun.org.apache.xerces.internal.util.XMLSymbols; import com.sun.org.apache.xerces.internal.utils.SecuritySupport; import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager; import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager; import com.sun.org.apache.xerces.internal.xni.XNIException; import com.sun.org.apache.xerces.internal.xni.grammars.Grammar; import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarDescription; import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarLoader; import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarPool; import com.sun.org.apache.xerces.internal.xni.grammars.XSGrammar; import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent; import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager; import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException; import com.sun.org.apache.xerces.internal.xni.parser.XMLEntityResolver; import com.sun.org.apache.xerces.internal.xni.parser.XMLErrorHandler; import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource; import com.sun.org.apache.xerces.internal.xs.LSInputList; import com.sun.org.apache.xerces.internal.xs.StringList; import com.sun.org.apache.xerces.internal.xs.XSLoader; import com.sun.org.apache.xerces.internal.xs.XSModel; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.Reader; import java.io.StringReader; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.StringTokenizer; import java.util.Vector; import javax.xml.XMLConstants; import org.w3c.dom.DOMConfiguration; import org.w3c.dom.DOMError; import org.w3c.dom.DOMErrorHandler; import org.w3c.dom.DOMException; import org.w3c.dom.DOMStringList; import org.w3c.dom.ls.LSInput; import org.w3c.dom.ls.LSResourceResolver; import org.xml.sax.InputSource; /** * This class implements xni.grammars.XMLGrammarLoader. * It also serves as implementation of xs.XSLoader interface and DOMConfiguration interface. * * This class is designed to interact either with a proxy for a user application * which wants to preparse schemas, or with our own Schema validator. * It is hoped that none of these "external" classes will therefore need to communicate directly * with XSDHandler in future. *
This class only knows how to make XSDHandler do its thing.
* The caller must ensure that all its properties (schemaLocation, JAXPSchemaSource
* etc.) have been properly set.
*
* @xerces.internal
*
* @author Neil Graham, IBM
* @version $Id: XMLSchemaLoader.java,v 1.10 2010-11-01 04:39:55 joehw Exp $
*/
public class XMLSchemaLoader implements XMLGrammarLoader, XMLComponent,
// XML Component API
XSLoader, DOMConfiguration {
// Feature identifiers:
/** Feature identifier: schema full checking*/
protected static final String SCHEMA_FULL_CHECKING =
Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_FULL_CHECKING;
/** Feature identifier: continue after fatal error. */
protected static final String CONTINUE_AFTER_FATAL_ERROR =
Constants.XERCES_FEATURE_PREFIX + Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE;
/** Feature identifier: allow java encodings to be recognized when parsing schema docs. */
protected static final String ALLOW_JAVA_ENCODINGS =
Constants.XERCES_FEATURE_PREFIX + Constants.ALLOW_JAVA_ENCODINGS_FEATURE;
/** Feature identifier: standard uri conformant feature. */
protected static final String STANDARD_URI_CONFORMANT_FEATURE =
Constants.XERCES_FEATURE_PREFIX + Constants.STANDARD_URI_CONFORMANT_FEATURE;
/** Feature identifier: validate annotations. */
protected static final String VALIDATE_ANNOTATIONS =
Constants.XERCES_FEATURE_PREFIX + Constants.VALIDATE_ANNOTATIONS_FEATURE;
/** Feature: disallow doctype*/
protected static final String DISALLOW_DOCTYPE =
Constants.XERCES_FEATURE_PREFIX + Constants.DISALLOW_DOCTYPE_DECL_FEATURE;
/** Feature: generate synthetic annotations */
protected static final String GENERATE_SYNTHETIC_ANNOTATIONS =
Constants.XERCES_FEATURE_PREFIX + Constants.GENERATE_SYNTHETIC_ANNOTATIONS_FEATURE;
/** Feature identifier: honour all schemaLocations */
protected static final String HONOUR_ALL_SCHEMALOCATIONS =
Constants.XERCES_FEATURE_PREFIX + Constants.HONOUR_ALL_SCHEMALOCATIONS_FEATURE;
protected static final String AUGMENT_PSVI =
Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_AUGMENT_PSVI;
protected static final String PARSER_SETTINGS =
Constants.XERCES_FEATURE_PREFIX + Constants.PARSER_SETTINGS;
/** Feature identifier: namespace growth */
protected static final String NAMESPACE_GROWTH =
Constants.XERCES_FEATURE_PREFIX + Constants.NAMESPACE_GROWTH_FEATURE;
/** Feature identifier: tolerate duplicates */
protected static final String TOLERATE_DUPLICATES =
Constants.XERCES_FEATURE_PREFIX + Constants.TOLERATE_DUPLICATES_FEATURE;
/** Property identifier: Schema DV Factory */
protected static final String SCHEMA_DV_FACTORY =
Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_DV_FACTORY_PROPERTY;
protected static final String USE_SERVICE_MECHANISM = Constants.ORACLE_FEATURE_SERVICE_MECHANISM;
// recognized features:
private static final String[] RECOGNIZED_FEATURES = {
SCHEMA_FULL_CHECKING,
AUGMENT_PSVI,
CONTINUE_AFTER_FATAL_ERROR,
ALLOW_JAVA_ENCODINGS,
STANDARD_URI_CONFORMANT_FEATURE,
DISALLOW_DOCTYPE,
GENERATE_SYNTHETIC_ANNOTATIONS,
VALIDATE_ANNOTATIONS,
HONOUR_ALL_SCHEMALOCATIONS,
NAMESPACE_GROWTH,
TOLERATE_DUPLICATES,
USE_SERVICE_MECHANISM
};
// property identifiers
/** Property identifier: symbol table. */
public static final String SYMBOL_TABLE =
Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
/** Property identifier: error reporter. */
public static final String ERROR_REPORTER =
Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY;
/** Property identifier: error handler. */
protected static final String ERROR_HANDLER =
Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_HANDLER_PROPERTY;
/** Property identifier: entity resolver. */
public static final String ENTITY_RESOLVER =
Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY;
/** Property identifier: grammar pool. */
public static final String XMLGRAMMAR_POOL =
Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY;
/** Property identifier: schema location. */
protected static final String SCHEMA_LOCATION =
Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_LOCATION;
/** Property identifier: no namespace schema location. */
protected static final String SCHEMA_NONS_LOCATION =
Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_NONS_LOCATION;
/** Property identifier: JAXP schema source. */
protected static final String JAXP_SCHEMA_SOURCE =
Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_SOURCE;
protected static final String SECURITY_MANAGER =
Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY;
/** Property identifier: locale. */
protected static final String LOCALE =
Constants.XERCES_PROPERTY_PREFIX + Constants.LOCALE_PROPERTY;
protected static final String ENTITY_MANAGER =
Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY;
/** Property identifier: Security property manager. */
private static final String XML_SECURITY_PROPERTY_MANAGER =
Constants.XML_SECURITY_PROPERTY_MANAGER;
/** Property identifier: access to external dtd */
public static final String ACCESS_EXTERNAL_DTD = XMLConstants.ACCESS_EXTERNAL_DTD;
/** Property identifier: access to external schema */
public static final String ACCESS_EXTERNAL_SCHEMA = XMLConstants.ACCESS_EXTERNAL_SCHEMA;
// recognized properties
private static final String [] RECOGNIZED_PROPERTIES = {
ENTITY_MANAGER,
SYMBOL_TABLE,
ERROR_REPORTER,
ERROR_HANDLER,
ENTITY_RESOLVER,
XMLGRAMMAR_POOL,
SCHEMA_LOCATION,
SCHEMA_NONS_LOCATION,
JAXP_SCHEMA_SOURCE,
SECURITY_MANAGER,
LOCALE,
SCHEMA_DV_FACTORY,
XML_SECURITY_PROPERTY_MANAGER
};
// Data
// features and properties
private ParserConfigurationSettings fLoaderConfig = new ParserConfigurationSettings();
private SymbolTable fSymbolTable = null;
private XMLErrorReporter fErrorReporter = new XMLErrorReporter ();
private XMLEntityManager fEntityManager = null;
private XMLEntityResolver fUserEntityResolver = null;
private XMLGrammarPool fGrammarPool = null;
private String fExternalSchemas = null;
private String fExternalNoNSSchema = null;
// JAXP property: schema source
private Object fJAXPSource = null;
// is Schema Full Checking enabled
private boolean fIsCheckedFully = false;
// boolean that tells whether we've tested the JAXP property.
private boolean fJAXPProcessed = false;
// if features/properties has not been changed, the value of this attribute is "false"
private boolean fSettingsChanged = true;
// xml schema parsing
private XSDHandler fSchemaHandler;
private XSGrammarBucket fGrammarBucket;
private XSDeclarationPool fDeclPool = null;
private SubstitutionGroupHandler fSubGroupHandler;
private final CMNodeFactory fNodeFactory = new CMNodeFactory(); //component mgr will be set later
private CMBuilder fCMBuilder;
private XSDDescription fXSDDescription = new XSDDescription();
private String faccessExternalSchema = Constants.EXTERNAL_ACCESS_DEFAULT;
private Map fJAXPCache;
private Locale fLocale = Locale.getDefault();
// XSLoader attributes
private DOMStringList fRecognizedParameters = null;
/** DOM L3 error handler */
private DOMErrorHandlerWrapper fErrorHandler = null;
/** DOM L3 resource resolver */
private DOMEntityResolverWrapper fResourceResolver = null;
// default constructor. Create objects we absolutely need:
public XMLSchemaLoader() {
this( new SymbolTable(), null, new XMLEntityManager(), null, null, null);
}
public XMLSchemaLoader(SymbolTable symbolTable) {
this( symbolTable, null, new XMLEntityManager(), null, null, null);
}
/**
* This constractor is used by the XMLSchemaValidator. Additional properties, i.e. XMLEntityManager,
* will be passed during reset(XMLComponentManager).
* @param errorReporter
* @param grammarBucket
* @param sHandler
* @param builder
*/
XMLSchemaLoader(XMLErrorReporter errorReporter,
XSGrammarBucket grammarBucket,
SubstitutionGroupHandler sHandler, CMBuilder builder) {
this(null, errorReporter, null, grammarBucket, sHandler, builder);
}
XMLSchemaLoader(SymbolTable symbolTable,
XMLErrorReporter errorReporter,
XMLEntityManager entityResolver,
XSGrammarBucket grammarBucket,
SubstitutionGroupHandler sHandler,
CMBuilder builder) {
// store properties and features in configuration
fLoaderConfig.addRecognizedFeatures(RECOGNIZED_FEATURES);
fLoaderConfig.addRecognizedProperties(RECOGNIZED_PROPERTIES);
if (symbolTable != null){
fLoaderConfig.setProperty(SYMBOL_TABLE, symbolTable);
}
if(errorReporter == null) {
errorReporter = new XMLErrorReporter ();
errorReporter.setLocale(fLocale);
errorReporter.setProperty(ERROR_HANDLER, new DefaultErrorHandler());
}
fErrorReporter = errorReporter;
// make sure error reporter knows about schemas...
if(fErrorReporter.getMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN) == null) {
fErrorReporter.putMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN, new XSMessageFormatter());
}
fLoaderConfig.setProperty(ERROR_REPORTER, fErrorReporter);
fEntityManager = entityResolver;
// entity manager is null if XMLSchemaValidator creates the loader
if (fEntityManager != null){
fLoaderConfig.setProperty(ENTITY_MANAGER, fEntityManager);
}
// by default augment PSVI (i.e. don't use declaration pool)
fLoaderConfig.setFeature(AUGMENT_PSVI, true);
if(grammarBucket == null ) {
grammarBucket = new XSGrammarBucket();
}
fGrammarBucket = grammarBucket;
if(sHandler == null) {
sHandler = new SubstitutionGroupHandler(fGrammarBucket);
}
fSubGroupHandler = sHandler;
if(builder == null) {
builder = new CMBuilder(fNodeFactory);
}
fCMBuilder = builder;
fSchemaHandler = new XSDHandler(fGrammarBucket);
if (fDeclPool != null) {
fDeclPool.reset();
}
fJAXPCache = new HashMap();
fSettingsChanged = true;
}
/**
* Returns a list of feature identifiers that are recognized by
* this XMLGrammarLoader. This method may return null if no features
* are recognized.
*/
public String[] getRecognizedFeatures() {
return (String[])(RECOGNIZED_FEATURES.clone());
} // getRecognizedFeatures(): String[]
/**
* Returns the state of a feature.
*
* @param featureId The feature identifier.
*
* @throws XMLConfigurationException Thrown on configuration error.
*/
public boolean getFeature(String featureId)
throws XMLConfigurationException {
return fLoaderConfig.getFeature(featureId);
} // getFeature (String): boolean
/**
* Sets the state of a feature.
*
* @param featureId The feature identifier.
* @param state The state of the feature.
*
* @throws XMLConfigurationException Thrown when a feature is not
* recognized or cannot be set.
*/
public void setFeature(String featureId,
boolean state) throws XMLConfigurationException {
fSettingsChanged = true;
if(featureId.equals(CONTINUE_AFTER_FATAL_ERROR)) {
fErrorReporter.setFeature(CONTINUE_AFTER_FATAL_ERROR, state);
}
else if(featureId.equals(GENERATE_SYNTHETIC_ANNOTATIONS)) {
fSchemaHandler.setGenerateSyntheticAnnotations(state);
}
fLoaderConfig.setFeature(featureId, state);
} // setFeature(String, boolean)
/**
* Returns a list of property identifiers that are recognized by
* this XMLGrammarLoader. This method may return null if no properties
* are recognized.
*/
public String[] getRecognizedProperties() {
return (String[])(RECOGNIZED_PROPERTIES.clone());
} // getRecognizedProperties(): String[]
/**
* Returns the state of a property.
*
* @param propertyId The property identifier.
*
* @throws XMLConfigurationException Thrown on configuration error.
*/
public Object getProperty(String propertyId)
throws XMLConfigurationException {
return fLoaderConfig.getProperty(propertyId);
} // getProperty(String): Object
/**
* Sets the state of a property.
*
* @param propertyId The property identifier.
* @param state The state of the property.
*
* @throws XMLConfigurationException Thrown when a property is not
* recognized or cannot be set.
*/
public void setProperty(String propertyId,
Object state) throws XMLConfigurationException {
fSettingsChanged = true;
fLoaderConfig.setProperty(propertyId, state);
if (propertyId.equals(JAXP_SCHEMA_SOURCE)) {
fJAXPSource = state;
fJAXPProcessed = false;
}
else if (propertyId.equals(XMLGRAMMAR_POOL)) {
fGrammarPool = (XMLGrammarPool)state;
}
else if (propertyId.equals(SCHEMA_LOCATION)) {
fExternalSchemas = (String)state;
}
else if (propertyId.equals(SCHEMA_NONS_LOCATION)) {
fExternalNoNSSchema = (String) state;
}
else if (propertyId.equals(LOCALE)) {
setLocale((Locale) state);
}
else if (propertyId.equals(ENTITY_RESOLVER)) {
fEntityManager.setProperty(ENTITY_RESOLVER, state);
}
else if (propertyId.equals(ERROR_REPORTER)) {
fErrorReporter = (XMLErrorReporter)state;
if (fErrorReporter.getMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN) == null) {
fErrorReporter.putMessageFormatter(XSMessageFormatter.SCHEMA_DOMAIN, new XSMessageFormatter());
}
}
else if (propertyId.equals(XML_SECURITY_PROPERTY_MANAGER)) {
XMLSecurityPropertyManager spm = (XMLSecurityPropertyManager)state;
faccessExternalSchema = spm.getValue(XMLSecurityPropertyManager.Property.ACCESS_EXTERNAL_SCHEMA);
}
} // setProperty(String, Object)
/**
* Set the locale to use for messages.
*
* @param locale The locale object to use for localization of messages.
*
* @exception XNIException Thrown if the parser does not support the
* specified locale.
*/
public void setLocale(Locale locale) {
fLocale = locale;
fErrorReporter.setLocale(locale);
} // setLocale(Locale)
/** Return the Locale the XMLGrammarLoader is using. */
public Locale getLocale() {
return fLocale;
} // getLocale(): Locale
/**
* Sets the error handler.
*
* @param errorHandler The error handler.
*/
public void setErrorHandler(XMLErrorHandler errorHandler) {
fErrorReporter.setProperty(ERROR_HANDLER, errorHandler);
} // setErrorHandler(XMLErrorHandler)
/** Returns the registered error handler. */
public XMLErrorHandler getErrorHandler() {
return fErrorReporter.getErrorHandler();
} // getErrorHandler(): XMLErrorHandler
/**
* Sets the entity resolver.
*
* @param entityResolver The new entity resolver.
*/
public void setEntityResolver(XMLEntityResolver entityResolver) {
fUserEntityResolver = entityResolver;
fLoaderConfig.setProperty(ENTITY_RESOLVER, entityResolver);
fEntityManager.setProperty(ENTITY_RESOLVER, entityResolver);
} // setEntityResolver(XMLEntityResolver)
/** Returns the registered entity resolver. */
public XMLEntityResolver getEntityResolver() {
return fUserEntityResolver;
} // getEntityResolver(): XMLEntityResolver
/**
* Returns a Grammar object by parsing the contents of the
* entities pointed to by sources.
*
* @param source[] the locations of the entity which forms
* the staring point of the grammars to be constructed
* @throws IOException when a problem is encounted reading the entity
* @throws XNIException when a condition arises (such as a FatalError) that requires parsing
* of the entity be terminated
*/
public void loadGrammar(XMLInputSource source[])
throws IOException, XNIException {
int numSource = source.length;
for (int i = 0; i < numSource; ++i) {
loadGrammar(source[i]);
}
}
/**
* Returns a Grammar object by parsing the contents of the
* entity pointed to by source.
*
* @param source the location of the entity which forms
* the starting point of the grammar to be constructed.
* @throws IOException When a problem is encountered reading the entity
* XNIException When a condition arises (such as a FatalError) that requires parsing
* of the entity be terminated.
*/
public Grammar loadGrammar(XMLInputSource source)
throws IOException, XNIException {
// REVISIT: this method should have a namespace parameter specified by
// user. In this case we can easily detect if a schema asked to be loaded
// is already in the local cache.
reset(fLoaderConfig);
fSettingsChanged = false;
XSDDescription desc = new XSDDescription();
desc.fContextType = XSDDescription.CONTEXT_PREPARSE;
desc.setBaseSystemId(source.getBaseSystemId());
desc.setLiteralSystemId( source.getSystemId());
// none of the other fields make sense for preparsing
Map locationPairs = new HashMap();
// Process external schema location properties.
// We don't call tokenizeSchemaLocationStr here, because we also want
// to check whether the values are valid URI.
processExternalHints(fExternalSchemas, fExternalNoNSSchema,
locationPairs, fErrorReporter);
SchemaGrammar grammar = loadSchema(desc, source, locationPairs);
if(grammar != null && fGrammarPool != null) {
fGrammarPool.cacheGrammars(XMLGrammarDescription.XML_SCHEMA, fGrammarBucket.getGrammars());
// NOTE: we only need to verify full checking in case the schema was not provided via JAXP
// since full checking already verified for all JAXP schemas
if(fIsCheckedFully && fJAXPCache.get(grammar) != grammar) {
XSConstraints.fullSchemaChecking(fGrammarBucket, fSubGroupHandler, fCMBuilder, fErrorReporter);
}
}
return grammar;
} // loadGrammar(XMLInputSource): Grammar
/**
* This method is called either from XMLGrammarLoader.loadGrammar or from XMLSchemaValidator.
* Note: in either case, the EntityManager (or EntityResolvers) are not going to be invoked
* to resolve the location of the schema in XSDDescription
* @param desc
* @param source
* @param locationPairs
* @return An XML Schema grammar
* @throws IOException
* @throws XNIException
*/
SchemaGrammar loadSchema(XSDDescription desc, XMLInputSource source,
Map