1 /* 2 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 3 */ 4 /* 5 * Copyright 2005 The Apache Software Foundation. 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 */ 19 20 package com.sun.org.apache.xerces.internal.jaxp.validation; 21 22 import java.io.IOException; 23 import java.io.InputStream; 24 import java.io.Reader; 25 26 import javax.xml.XMLConstants; 27 import javax.xml.stream.XMLEventReader; 28 import javax.xml.transform.Source; 29 import javax.xml.transform.dom.DOMSource; 30 import javax.xml.transform.sax.SAXSource; 31 import javax.xml.transform.stax.StAXSource; 32 import javax.xml.transform.stream.StreamSource; 33 import javax.xml.validation.Schema; 34 import javax.xml.validation.SchemaFactory; 35 import jdk.xml.internal.JdkXmlFeatures; 36 import jdk.xml.internal.JdkXmlUtils; 37 38 import com.sun.org.apache.xerces.internal.impl.Constants; 39 import com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader; 40 import com.sun.org.apache.xerces.internal.util.DOMEntityResolverWrapper; 41 import com.sun.org.apache.xerces.internal.util.DOMInputSource; 42 import com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper; 43 import com.sun.org.apache.xerces.internal.util.SAXInputSource; 44 import com.sun.org.apache.xerces.internal.util.SAXMessageFormatter; 45 import com.sun.org.apache.xerces.internal.util.StAXInputSource; 46 import com.sun.org.apache.xerces.internal.util.Status; 47 import com.sun.org.apache.xerces.internal.util.XMLGrammarPoolImpl; 48 import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager; 49 import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager; 50 import com.sun.org.apache.xerces.internal.xni.XNIException; 51 import com.sun.org.apache.xerces.internal.xni.grammars.Grammar; 52 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarDescription; 53 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarPool; 54 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException; 55 import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource; 56 import org.w3c.dom.Node; 57 import org.w3c.dom.ls.LSResourceResolver; 58 import org.xml.sax.ErrorHandler; 59 import org.xml.sax.InputSource; 60 import org.xml.sax.SAXException; 61 import org.xml.sax.SAXNotRecognizedException; 62 import org.xml.sax.SAXNotSupportedException; 63 import org.xml.sax.SAXParseException; 64 65 /** 66 * {@link SchemaFactory} for XML Schema. 67 * 68 * @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com) 69 * @version $Id: XMLSchemaFactory.java,v 1.11 2010-11-01 04:40:08 joehw Exp $ 70 */ 71 public final class XMLSchemaFactory extends SchemaFactory { 72 73 // property identifiers 74 75 /** Feature identifier: schema full checking. */ 76 private static final String SCHEMA_FULL_CHECKING = 77 Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_FULL_CHECKING; 78 79 /** Property identifier: grammar pool. */ 80 private static final String XMLGRAMMAR_POOL = 81 Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY; 82 83 /** Property identifier: XMLSecurityManager. */ 84 private static final String SECURITY_MANAGER = 85 Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY; 86 87 /** Property identifier: Security property manager. */ 88 private static final String XML_SECURITY_PROPERTY_MANAGER = 89 Constants.XML_SECURITY_PROPERTY_MANAGER; 90 91 92 // 93 // Data 94 // 95 96 /** The XMLSchemaLoader */ 97 private final XMLSchemaLoader fXMLSchemaLoader = new XMLSchemaLoader(); 98 99 /** User-specified ErrorHandler; can be null. */ 100 private ErrorHandler fErrorHandler; 101 102 /** The LSResrouceResolver */ 103 private LSResourceResolver fLSResourceResolver; 104 105 /** The DOMEntityResolverWrapper */ 106 private final DOMEntityResolverWrapper fDOMEntityResolverWrapper; 107 108 /** The ErrorHandlerWrapper */ 109 private ErrorHandlerWrapper fErrorHandlerWrapper; 110 111 /** The SecurityManager. */ 112 private XMLSecurityManager fSecurityManager; 113 114 /** The Security property manager. */ 115 private XMLSecurityPropertyManager fSecurityPropertyMgr; 116 117 /** The container for the real grammar pool. */ 118 private XMLGrammarPoolWrapper fXMLGrammarPoolWrapper; 119 120 private final JdkXmlFeatures fXmlFeatures; 121 /** 122 * Indicates whether 3rd party parser may be used to override the system-default 123 * Note the default value (false) is the safe option. 124 * Note same as the old property useServicesMechanism 125 */ 126 private final boolean fOverrideDefaultParser; 127 128 129 public XMLSchemaFactory() { 130 fErrorHandlerWrapper = new ErrorHandlerWrapper(DraconianErrorHandler.getInstance()); 131 fDOMEntityResolverWrapper = new DOMEntityResolverWrapper(); 132 fXMLGrammarPoolWrapper = new XMLGrammarPoolWrapper(); 133 fXMLSchemaLoader.setFeature(SCHEMA_FULL_CHECKING, true); 134 fXMLSchemaLoader.setProperty(XMLGRAMMAR_POOL, fXMLGrammarPoolWrapper); 135 fXMLSchemaLoader.setEntityResolver(fDOMEntityResolverWrapper); 136 fXMLSchemaLoader.setErrorHandler(fErrorHandlerWrapper); 137 138 // Enable secure processing feature by default 139 fSecurityManager = new XMLSecurityManager(true); 140 fXMLSchemaLoader.setProperty(SECURITY_MANAGER, fSecurityManager); 141 142 fSecurityPropertyMgr = new XMLSecurityPropertyManager(); 143 fXMLSchemaLoader.setProperty(XML_SECURITY_PROPERTY_MANAGER, 144 fSecurityPropertyMgr); 145 fXmlFeatures = new JdkXmlFeatures(fSecurityManager.isSecureProcessing()); 146 fOverrideDefaultParser = fXmlFeatures.getFeature( 147 JdkXmlFeatures.XmlFeature.JDK_OVERRIDE_PARSER); 148 fXMLSchemaLoader.setFeature(JdkXmlUtils.OVERRIDE_PARSER, fOverrideDefaultParser); 149 } 150 151 /** 152 * <p>Is specified schema supported by this <code>SchemaFactory</code>?</p> 153 * 154 * @param schemaLanguage Specifies the schema language which the returned <code>SchemaFactory</code> will understand. 155 * <code>schemaLanguage</code> must specify a <a href="#schemaLanguage">valid</a> schema language. 156 * 157 * @return <code>true</code> if <code>SchemaFactory</code> supports <code>schemaLanguage</code>, else <code>false</code>. 158 * 159 * @throws NullPointerException If <code>schemaLanguage</code> is <code>null</code>. 160 * @throws IllegalArgumentException If <code>schemaLanguage.length() == 0</code> 161 * or <code>schemaLanguage</code> does not specify a <a href="#schemaLanguage">valid</a> schema language. 162 */ 163 public boolean isSchemaLanguageSupported(String schemaLanguage) { 164 if (schemaLanguage == null) { 165 throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 166 "SchemaLanguageNull", null)); 167 } 168 if (schemaLanguage.length() == 0) { 169 throw new IllegalArgumentException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 170 "SchemaLanguageLengthZero", null)); 171 } 172 // only W3C XML Schema 1.0 is supported 173 return schemaLanguage.equals(XMLConstants.W3C_XML_SCHEMA_NS_URI); 174 } 175 176 public LSResourceResolver getResourceResolver() { 177 return fLSResourceResolver; 178 } 179 180 public void setResourceResolver(LSResourceResolver resourceResolver) { 181 fLSResourceResolver = resourceResolver; 182 fDOMEntityResolverWrapper.setEntityResolver(resourceResolver); 183 fXMLSchemaLoader.setEntityResolver(fDOMEntityResolverWrapper); 184 } 185 186 public ErrorHandler getErrorHandler() { 187 return fErrorHandler; 188 } 189 190 public void setErrorHandler(ErrorHandler errorHandler) { 191 fErrorHandler = errorHandler; 192 fErrorHandlerWrapper.setErrorHandler(errorHandler != null ? errorHandler : DraconianErrorHandler.getInstance()); 193 fXMLSchemaLoader.setErrorHandler(fErrorHandlerWrapper); 194 } 195 196 public Schema newSchema( Source[] schemas ) throws SAXException { 197 198 // this will let the loader store parsed Grammars into the pool. 199 XMLGrammarPoolImplExtension pool = new XMLGrammarPoolImplExtension(); 200 fXMLGrammarPoolWrapper.setGrammarPool(pool); 201 202 XMLInputSource[] xmlInputSources = new XMLInputSource[schemas.length]; 203 InputStream inputStream; 204 Reader reader; 205 for( int i=0; i<schemas.length; i++ ) { 206 Source source = schemas[i]; 207 if (source instanceof StreamSource) { 208 StreamSource streamSource = (StreamSource) source; 209 String publicId = streamSource.getPublicId(); 210 String systemId = streamSource.getSystemId(); 211 inputStream = streamSource.getInputStream(); 212 reader = streamSource.getReader(); 213 xmlInputSources[i] = new XMLInputSource(publicId, systemId, null); 214 xmlInputSources[i].setByteStream(inputStream); 215 xmlInputSources[i].setCharacterStream(reader); 216 } 217 else if (source instanceof SAXSource) { 218 SAXSource saxSource = (SAXSource) source; 219 InputSource inputSource = saxSource.getInputSource(); 220 if (inputSource == null) { 221 throw new SAXException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 222 "SAXSourceNullInputSource", null)); 223 } 224 xmlInputSources[i] = new SAXInputSource(saxSource.getXMLReader(), inputSource); 225 } 226 else if (source instanceof DOMSource) { 227 DOMSource domSource = (DOMSource) source; 228 Node node = domSource.getNode(); 229 String systemID = domSource.getSystemId(); 230 xmlInputSources[i] = new DOMInputSource(node, systemID); 231 } 232 else if (source instanceof StAXSource) { 233 StAXSource staxSource = (StAXSource) source; 234 XMLEventReader eventReader = staxSource.getXMLEventReader(); 235 if (eventReader != null) { 236 xmlInputSources[i] = new StAXInputSource(eventReader); 237 } 238 else { 239 xmlInputSources[i] = new StAXInputSource(staxSource.getXMLStreamReader()); 240 } 241 } 242 else if (source == null) { 243 throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 244 "SchemaSourceArrayMemberNull", null)); 245 } 246 else { 247 throw new IllegalArgumentException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 248 "SchemaFactorySourceUnrecognized", 249 new Object [] {source.getClass().getName()})); 250 } 251 } 252 253 try { 254 fXMLSchemaLoader.loadGrammar(xmlInputSources); 255 } 256 catch (XNIException e) { 257 // this should have been reported to users already. 258 throw Util.toSAXException(e); 259 } 260 catch (IOException e) { 261 // this hasn't been reported, so do so now. 262 SAXParseException se = new SAXParseException(e.getMessage(),null,e); 263 fErrorHandler.error(se); 264 throw se; // and we must throw it. 265 } 266 267 // Clear reference to grammar pool. 268 fXMLGrammarPoolWrapper.setGrammarPool(null); 269 270 // Select Schema implementation based on grammar count. 271 final int grammarCount = pool.getGrammarCount(); 272 AbstractXMLSchema schema = null; 273 if (grammarCount > 1) { 274 schema = new XMLSchema(new ReadOnlyGrammarPool(pool)); 275 } 276 else if (grammarCount == 1) { 277 Grammar[] grammars = pool.retrieveInitialGrammarSet(XMLGrammarDescription.XML_SCHEMA); 278 schema = new SimpleXMLSchema(grammars[0]); 279 } 280 else { 281 schema = new EmptyXMLSchema(); 282 } 283 propagateFeatures(schema); 284 propagateProperties(schema); 285 return schema; 286 } 287 288 public Schema newSchema() throws SAXException { 289 // Use a Schema that uses the system id as the equality source. 290 AbstractXMLSchema schema = new WeakReferenceXMLSchema(); 291 propagateFeatures(schema); 292 propagateProperties(schema); 293 return schema; 294 } 295 296 public boolean getFeature(String name) 297 throws SAXNotRecognizedException, SAXNotSupportedException { 298 if (name == null) { 299 throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 300 "FeatureNameNull", null)); 301 } 302 if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) { 303 return (fSecurityManager != null && fSecurityManager.isSecureProcessing()); 304 } 305 try { 306 return fXMLSchemaLoader.getFeature(name); 307 } 308 catch (XMLConfigurationException e) { 309 String identifier = e.getIdentifier(); 310 if (e.getType() == Status.NOT_RECOGNIZED) { 311 throw new SAXNotRecognizedException( 312 SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 313 "feature-not-recognized", new Object [] {identifier})); 314 } 315 else { 316 throw new SAXNotSupportedException( 317 SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 318 "feature-not-supported", new Object [] {identifier})); 319 } 320 } 321 } 322 323 public Object getProperty(String name) 324 throws SAXNotRecognizedException, SAXNotSupportedException { 325 if (name == null) { 326 throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 327 "ProperyNameNull", null)); 328 } 329 if (name.equals(SECURITY_MANAGER)) { 330 return fSecurityManager; 331 } 332 else if (name.equals(XMLGRAMMAR_POOL)) { 333 throw new SAXNotSupportedException( 334 SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 335 "property-not-supported", new Object [] {name})); 336 } 337 /** Check to see if the property is managed by the JdkXmlFeatues **/ 338 int index = fXmlFeatures.getIndex(name); 339 if (index > -1) { 340 return fXmlFeatures.getFeature(index); 341 } 342 try { 343 return fXMLSchemaLoader.getProperty(name); 344 } 345 catch (XMLConfigurationException e) { 346 String identifier = e.getIdentifier(); 347 if (e.getType() == Status.NOT_RECOGNIZED) { 348 throw new SAXNotRecognizedException( 349 SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 350 "property-not-recognized", new Object [] {identifier})); 351 } 352 else { 353 throw new SAXNotSupportedException( 354 SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 355 "property-not-supported", new Object [] {identifier})); 356 } 357 } 358 } 359 360 public void setFeature(String name, boolean value) 361 throws SAXNotRecognizedException, SAXNotSupportedException { 362 if (name == null) { 363 throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 364 "FeatureNameNull", null)); 365 } 366 if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) { 367 if (System.getSecurityManager() != null && (!value)) { 368 throw new SAXNotSupportedException( 369 SAXMessageFormatter.formatMessage(null, 370 "jaxp-secureprocessing-feature", null)); 371 } 372 373 fSecurityManager.setSecureProcessing(value); 374 if (value) { 375 if (Constants.IS_JDK8_OR_ABOVE) { 376 fSecurityPropertyMgr.setValue(XMLSecurityPropertyManager.Property.ACCESS_EXTERNAL_DTD, 377 XMLSecurityPropertyManager.State.FSP, Constants.EXTERNAL_ACCESS_DEFAULT_FSP); 378 fSecurityPropertyMgr.setValue(XMLSecurityPropertyManager.Property.ACCESS_EXTERNAL_SCHEMA, 379 XMLSecurityPropertyManager.State.FSP, Constants.EXTERNAL_ACCESS_DEFAULT_FSP); 380 } 381 } 382 383 fXMLSchemaLoader.setProperty(SECURITY_MANAGER, fSecurityManager); 384 return; 385 } else if (name.equals(Constants.ORACLE_FEATURE_SERVICE_MECHANISM)) { 386 //in secure mode, let useServicesMechanism be determined by the constructor 387 if (System.getSecurityManager() != null) 388 return; 389 } 390 391 if ((fXmlFeatures != null) && 392 fXmlFeatures.setFeature(name, JdkXmlFeatures.State.APIPROPERTY, value)) { 393 if (name.equals(JdkXmlUtils.OVERRIDE_PARSER) 394 || name.equals(Constants.ORACLE_FEATURE_SERVICE_MECHANISM)) { 395 fXMLSchemaLoader.setFeature(name, value); 396 } 397 return; 398 } 399 try { 400 fXMLSchemaLoader.setFeature(name, value); 401 } 402 catch (XMLConfigurationException e) { 403 String identifier = e.getIdentifier(); 404 if (e.getType() == Status.NOT_RECOGNIZED) { 405 throw new SAXNotRecognizedException( 406 SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 407 "feature-not-recognized", new Object [] {identifier})); 408 } 409 else { 410 throw new SAXNotSupportedException( 411 SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 412 "feature-not-supported", new Object [] {identifier})); 413 } 414 } 415 } 416 417 public void setProperty(String name, Object object) 418 throws SAXNotRecognizedException, SAXNotSupportedException { 419 if (name == null) { 420 throw new NullPointerException(JAXPValidationMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 421 "ProperyNameNull", null)); 422 } 423 if (name.equals(SECURITY_MANAGER)) { 424 fSecurityManager = XMLSecurityManager.convert(object, fSecurityManager); 425 fXMLSchemaLoader.setProperty(SECURITY_MANAGER, fSecurityManager); 426 return; 427 } else if (name.equals(Constants.XML_SECURITY_PROPERTY_MANAGER)) { 428 if (object == null) { 429 fSecurityPropertyMgr = new XMLSecurityPropertyManager(); 430 } else { 431 fSecurityPropertyMgr = (XMLSecurityPropertyManager)object; 432 } 433 fXMLSchemaLoader.setProperty(Constants.XML_SECURITY_PROPERTY_MANAGER, fSecurityPropertyMgr); 434 return; 435 } 436 else if (name.equals(XMLGRAMMAR_POOL)) { 437 throw new SAXNotSupportedException( 438 SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 439 "property-not-supported", new Object [] {name})); 440 } 441 try { 442 //check if the property is managed by security manager 443 if (fSecurityManager == null || 444 !fSecurityManager.setLimit(name, XMLSecurityManager.State.APIPROPERTY, object)) { 445 //check if the property is managed by security property manager 446 if (fSecurityPropertyMgr == null || 447 !fSecurityPropertyMgr.setValue(name, XMLSecurityPropertyManager.State.APIPROPERTY, object)) { 448 //fall back to the existing property manager 449 fXMLSchemaLoader.setProperty(name, object); 450 } 451 } 452 } 453 catch (XMLConfigurationException e) { 454 String identifier = e.getIdentifier(); 455 if (e.getType() == Status.NOT_RECOGNIZED) { 456 throw new SAXNotRecognizedException( 457 SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 458 "property-not-recognized", new Object [] {identifier})); 459 } 460 else { 461 throw new SAXNotSupportedException( 462 SAXMessageFormatter.formatMessage(fXMLSchemaLoader.getLocale(), 463 "property-not-supported", new Object [] {identifier})); 464 } 465 } 466 } 467 468 private void propagateFeatures(AbstractXMLSchema schema) { 469 schema.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, 470 (fSecurityManager != null && fSecurityManager.isSecureProcessing())); 471 schema.setFeature(JdkXmlUtils.OVERRIDE_PARSER, fOverrideDefaultParser); 472 String[] features = fXMLSchemaLoader.getRecognizedFeatures(); 473 for (int i = 0; i < features.length; ++i) { 474 boolean state = fXMLSchemaLoader.getFeature(features[i]); 475 schema.setFeature(features[i], state); 476 } 477 } 478 479 private void propagateProperties(AbstractXMLSchema schema) { 480 String[] properties = fXMLSchemaLoader.getRecognizedProperties(); 481 for (int i = 0; i < properties.length; ++i) { 482 Object state = fXMLSchemaLoader.getProperty(properties[i]); 483 schema.setProperty(properties[i], state); 484 } 485 } 486 487 488 /** 489 * Extension of XMLGrammarPoolImpl which exposes the number of 490 * grammars stored in the grammar pool. 491 */ 492 static class XMLGrammarPoolImplExtension extends XMLGrammarPoolImpl { 493 494 /** Constructs a grammar pool with a default number of buckets. */ 495 public XMLGrammarPoolImplExtension() { 496 super(); 497 } 498 499 /** Constructs a grammar pool with a specified number of buckets. */ 500 public XMLGrammarPoolImplExtension(int initialCapacity) { 501 super(initialCapacity); 502 } 503 504 /** Returns the number of grammars contained in this pool. */ 505 int getGrammarCount() { 506 return fGrammarCount; 507 } 508 509 } // XMLSchemaFactory.XMLGrammarPoolImplExtension 510 511 /** 512 * A grammar pool which wraps another. 513 */ 514 static class XMLGrammarPoolWrapper implements XMLGrammarPool { 515 516 private XMLGrammarPool fGrammarPool; 517 518 /* 519 * XMLGrammarPool methods 520 */ 521 522 public Grammar[] retrieveInitialGrammarSet(String grammarType) { 523 return fGrammarPool.retrieveInitialGrammarSet(grammarType); 524 } 525 526 public void cacheGrammars(String grammarType, Grammar[] grammars) { 527 fGrammarPool.cacheGrammars(grammarType, grammars); 528 } 529 530 public Grammar retrieveGrammar(XMLGrammarDescription desc) { 531 return fGrammarPool.retrieveGrammar(desc); 532 } 533 534 public void lockPool() { 535 fGrammarPool.lockPool(); 536 } 537 538 public void unlockPool() { 539 fGrammarPool.unlockPool(); 540 } 541 542 public void clear() { 543 fGrammarPool.clear(); 544 } 545 546 /* 547 * Other methods 548 */ 549 550 void setGrammarPool(XMLGrammarPool grammarPool) { 551 fGrammarPool = grammarPool; 552 } 553 554 XMLGrammarPool getGrammarPool() { 555 return fGrammarPool; 556 } 557 558 } // XMLSchemaFactory.XMLGrammarPoolWrapper 559 560 } // XMLSchemaFactory