1 /*
   2  * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * @LastModified: Oct 2017
   4  */
   5 /*
   6  * Licensed to the Apache Software Foundation (ASF) under one or more
   7  * contributor license agreements.  See the NOTICE file distributed with
   8  * this work for additional information regarding copyright ownership.
   9  * The ASF licenses this file to You under the Apache License, Version 2.0
  10  * (the "License"); you may not use this file except in compliance with
  11  * the License.  You may obtain a copy of the License at
  12  *
  13  *      http://www.apache.org/licenses/LICENSE-2.0
  14  *
  15  * Unless required by applicable law or agreed to in writing, software
  16  * distributed under the License is distributed on an "AS IS" BASIS,
  17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18  * See the License for the specific language governing permissions and
  19  * limitations under the License.
  20  */
  21 
  22 package com.sun.org.apache.xerces.internal.jaxp.validation;
  23 
  24 import com.sun.org.apache.xerces.internal.impl.Constants;
  25 import com.sun.org.apache.xerces.internal.impl.XMLEntityManager;
  26 import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter;
  27 import com.sun.org.apache.xerces.internal.impl.dv.XSSimpleType;
  28 import com.sun.org.apache.xerces.internal.impl.validation.EntityState;
  29 import com.sun.org.apache.xerces.internal.impl.validation.ValidationManager;
  30 import com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator;
  31 import com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl;
  32 import com.sun.org.apache.xerces.internal.util.AttributesProxy;
  33 import com.sun.org.apache.xerces.internal.util.SAXLocatorWrapper;
  34 import com.sun.org.apache.xerces.internal.util.SAXMessageFormatter;
  35 import com.sun.org.apache.xerces.internal.util.Status;
  36 import com.sun.org.apache.xerces.internal.util.SymbolTable;
  37 import com.sun.org.apache.xerces.internal.util.URI;
  38 import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl;
  39 import com.sun.org.apache.xerces.internal.util.XMLSymbols;
  40 import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager;
  41 import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager;
  42 import com.sun.org.apache.xerces.internal.xni.Augmentations;
  43 import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
  44 import com.sun.org.apache.xerces.internal.xni.QName;
  45 import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
  46 import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler;
  47 import com.sun.org.apache.xerces.internal.xni.XMLLocator;
  48 import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
  49 import com.sun.org.apache.xerces.internal.xni.XMLString;
  50 import com.sun.org.apache.xerces.internal.xni.XNIException;
  51 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
  52 import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentSource;
  53 import com.sun.org.apache.xerces.internal.xni.parser.XMLParseException;
  54 import com.sun.org.apache.xerces.internal.xs.AttributePSVI;
  55 import com.sun.org.apache.xerces.internal.xs.ElementPSVI;
  56 import com.sun.org.apache.xerces.internal.xs.ItemPSVI;
  57 import com.sun.org.apache.xerces.internal.xs.PSVIProvider;
  58 import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition;
  59 import java.io.IOException;
  60 import java.io.InputStream;
  61 import java.io.Reader;
  62 import java.io.StringReader;
  63 import java.util.HashMap;
  64 import java.util.Map;
  65 import javax.xml.XMLConstants;
  66 import javax.xml.parsers.FactoryConfigurationError;
  67 import javax.xml.parsers.SAXParserFactory;
  68 import javax.xml.transform.Result;
  69 import javax.xml.transform.Source;
  70 import javax.xml.transform.sax.SAXResult;
  71 import javax.xml.transform.sax.SAXSource;
  72 import javax.xml.validation.TypeInfoProvider;
  73 import javax.xml.validation.ValidatorHandler;
  74 import jdk.xml.internal.JdkXmlUtils;
  75 import org.w3c.dom.TypeInfo;
  76 import org.w3c.dom.ls.LSInput;
  77 import org.w3c.dom.ls.LSResourceResolver;
  78 import org.xml.sax.Attributes;
  79 import org.xml.sax.ContentHandler;
  80 import org.xml.sax.DTDHandler;
  81 import org.xml.sax.ErrorHandler;
  82 import org.xml.sax.InputSource;
  83 import org.xml.sax.Locator;
  84 import org.xml.sax.SAXException;
  85 import org.xml.sax.SAXNotRecognizedException;
  86 import org.xml.sax.SAXNotSupportedException;
  87 import org.xml.sax.XMLReader;
  88 import org.xml.sax.ext.Attributes2;
  89 import org.xml.sax.ext.EntityResolver2;
  90 
  91 /**
  92  * <p>Implementation of ValidatorHandler for W3C XML Schemas and
  93  * also a validator helper for <code>SAXSource</code>s.</p>
  94  *
  95  * @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
  96  * @author Michael Glavassevich, IBM
  97  *
  98  */
  99 final class ValidatorHandlerImpl extends ValidatorHandler implements
 100     DTDHandler, EntityState, PSVIProvider, ValidatorHelper, XMLDocumentHandler {
 101 
 102     // feature identifiers
 103 
 104     /** Feature identifier: namespace prefixes. */
 105     private static final String NAMESPACE_PREFIXES =
 106         Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACE_PREFIXES_FEATURE;
 107 
 108     /** Feature identifier: string interning. */
 109     protected static final String STRING_INTERNING =
 110         Constants.SAX_FEATURE_PREFIX + Constants.STRING_INTERNING_FEATURE;
 111 
 112     // property identifiers
 113 
 114     /** Property identifier: error reporter. */
 115     private static final String ERROR_REPORTER =
 116         Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY;
 117 
 118     /** Property identifier: namespace context. */
 119     private static final String NAMESPACE_CONTEXT =
 120         Constants.XERCES_PROPERTY_PREFIX + Constants.NAMESPACE_CONTEXT_PROPERTY;
 121 
 122     /** Property identifier: XML Schema validator. */
 123     private static final String SCHEMA_VALIDATOR =
 124         Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_VALIDATOR_PROPERTY;
 125 
 126     /** Property identifier: security manager. */
 127     private static final String SECURITY_MANAGER =
 128         Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY;
 129 
 130     /** Property identifier: symbol table. */
 131     private static final String SYMBOL_TABLE =
 132         Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
 133 
 134     /** Property identifier: validation manager. */
 135     private static final String VALIDATION_MANAGER =
 136         Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY;
 137 
 138     /** Property identifier: Security property manager. */
 139     private static final String XML_SECURITY_PROPERTY_MANAGER =
 140             Constants.XML_SECURITY_PROPERTY_MANAGER;
 141 
 142     //
 143     // Data
 144     //
 145 
 146     /** Error reporter. */
 147     private XMLErrorReporter fErrorReporter;
 148 
 149     /** The namespace context of this document: stores namespaces in scope */
 150     private NamespaceContext fNamespaceContext;
 151 
 152     /** Schema validator. **/
 153     private XMLSchemaValidator fSchemaValidator;
 154 
 155     /** Symbol table **/
 156     private SymbolTable fSymbolTable;
 157 
 158     /** Validation manager. */
 159     private ValidationManager fValidationManager;
 160 
 161     /** Component manager. **/
 162     private XMLSchemaValidatorComponentManager fComponentManager;
 163 
 164     /** XML Locator wrapper for SAX. **/
 165     private final SAXLocatorWrapper fSAXLocatorWrapper = new SAXLocatorWrapper();
 166 
 167     /** Flag used to track whether the namespace context needs to be pushed. */
 168     private boolean fNeedPushNSContext = true;
 169 
 170     /** Map for tracking unparsed entities. */
 171     private Map<String, String> fUnparsedEntities = null;
 172 
 173     /** Flag used to track whether XML names and Namespace URIs have been internalized. */
 174     private boolean fStringsInternalized = false;
 175 
 176     /** Fields for start element, end element and characters. */
 177     private final QName fElementQName = new QName();
 178     private final QName fAttributeQName = new QName();
 179     private final XMLAttributesImpl fAttributes = new XMLAttributesImpl();
 180     private final AttributesProxy fAttrAdapter = new AttributesProxy(fAttributes);
 181     private final XMLString fTempString = new XMLString();
 182 
 183     //
 184     // User Objects
 185     //
 186 
 187     private ContentHandler fContentHandler = null;
 188 
 189     /*
 190      * Constructors
 191      */
 192 
 193     public ValidatorHandlerImpl(XSGrammarPoolContainer grammarContainer) {
 194         this(new XMLSchemaValidatorComponentManager(grammarContainer));
 195         fComponentManager.addRecognizedFeatures(new String [] {NAMESPACE_PREFIXES});
 196         fComponentManager.setFeature(NAMESPACE_PREFIXES, false);
 197         setErrorHandler(null);
 198         setResourceResolver(null);
 199     }
 200 
 201     public ValidatorHandlerImpl(XMLSchemaValidatorComponentManager componentManager) {
 202         fComponentManager = componentManager;
 203         fErrorReporter = (XMLErrorReporter) fComponentManager.getProperty(ERROR_REPORTER);
 204         fNamespaceContext = (NamespaceContext) fComponentManager.getProperty(NAMESPACE_CONTEXT);
 205         fSchemaValidator = (XMLSchemaValidator) fComponentManager.getProperty(SCHEMA_VALIDATOR);
 206         fSymbolTable = (SymbolTable) fComponentManager.getProperty(SYMBOL_TABLE);
 207         fValidationManager = (ValidationManager) fComponentManager.getProperty(VALIDATION_MANAGER);
 208     }
 209 
 210     /*
 211      * ValidatorHandler methods
 212      */
 213 
 214     public void setContentHandler(ContentHandler receiver) {
 215         fContentHandler = receiver;
 216     }
 217 
 218     public ContentHandler getContentHandler() {
 219         return fContentHandler;
 220     }
 221 
 222     public void setErrorHandler(ErrorHandler errorHandler) {
 223         fComponentManager.setErrorHandler(errorHandler);
 224     }
 225 
 226     public ErrorHandler getErrorHandler() {
 227         return fComponentManager.getErrorHandler();
 228     }
 229 
 230     public void setResourceResolver(LSResourceResolver resourceResolver) {
 231         fComponentManager.setResourceResolver(resourceResolver);
 232     }
 233 
 234     public LSResourceResolver getResourceResolver() {
 235         return fComponentManager.getResourceResolver();
 236     }
 237 
 238     public TypeInfoProvider getTypeInfoProvider() {
 239         return fTypeInfoProvider;
 240     }
 241 
 242     public boolean getFeature(String name)
 243         throws SAXNotRecognizedException, SAXNotSupportedException {
 244         if (name == null) {
 245             throw new NullPointerException();
 246         }
 247         try {
 248             return fComponentManager.getFeature(name);
 249         }
 250         catch (XMLConfigurationException e) {
 251             final String identifier = e.getIdentifier();
 252             final String key = e.getType() == Status.NOT_RECOGNIZED ?
 253                     "feature-not-recognized" : "feature-not-supported";
 254             throw new SAXNotRecognizedException(
 255                     SAXMessageFormatter.formatMessage(fComponentManager.getLocale(),
 256                     key, new Object [] {identifier}));
 257         }
 258     }
 259 
 260     public void setFeature(String name, boolean value)
 261         throws SAXNotRecognizedException, SAXNotSupportedException {
 262         if (name == null) {
 263             throw new NullPointerException();
 264         }
 265         try {
 266             fComponentManager.setFeature(name, value);
 267         }
 268         catch (XMLConfigurationException e) {
 269             final String identifier = e.getIdentifier();
 270             final String key;
 271             if (e.getType() == Status.NOT_ALLOWED) {
 272                 //for now, the identifier can only be (XMLConstants.FEATURE_SECURE_PROCESSING)
 273                 throw new SAXNotSupportedException(
 274                     SAXMessageFormatter.formatMessage(fComponentManager.getLocale(),
 275                     "jaxp-secureprocessing-feature", null));
 276             } else if (e.getType() == Status.NOT_RECOGNIZED) {
 277                 key = "feature-not-recognized";
 278             } else {
 279                 key = "feature-not-supported";
 280             }
 281             throw new SAXNotRecognizedException(
 282                     SAXMessageFormatter.formatMessage(fComponentManager.getLocale(),
 283                     key, new Object [] {identifier}));
 284         }
 285     }
 286 
 287     public Object getProperty(String name)
 288         throws SAXNotRecognizedException, SAXNotSupportedException {
 289         if (name == null) {
 290             throw new NullPointerException();
 291         }
 292         try {
 293             return fComponentManager.getProperty(name);
 294         }
 295         catch (XMLConfigurationException e) {
 296             final String identifier = e.getIdentifier();
 297             final String key = e.getType() == Status.NOT_RECOGNIZED ?
 298                     "property-not-recognized" : "property-not-supported";
 299             throw new SAXNotRecognizedException(
 300                     SAXMessageFormatter.formatMessage(fComponentManager.getLocale(),
 301                     key, new Object [] {identifier}));
 302         }
 303     }
 304 
 305     public void setProperty(String name, Object object)
 306         throws SAXNotRecognizedException, SAXNotSupportedException {
 307         if (name == null) {
 308             throw new NullPointerException();
 309         }
 310         try {
 311             fComponentManager.setProperty(name, object);
 312         }
 313         catch (XMLConfigurationException e) {
 314             final String identifier = e.getIdentifier();
 315             final String key = e.getType() == Status.NOT_RECOGNIZED ?
 316                     "property-not-recognized" : "property-not-supported";
 317             throw new SAXNotRecognizedException(
 318                     SAXMessageFormatter.formatMessage(fComponentManager.getLocale(),
 319                     key, new Object [] {identifier}));
 320         }
 321     }
 322 
 323     /*
 324      * EntityState methods
 325      */
 326 
 327     public boolean isEntityDeclared(String name) {
 328         return false;
 329     }
 330 
 331     public boolean isEntityUnparsed(String name) {
 332         if (fUnparsedEntities != null) {
 333             return fUnparsedEntities.containsKey(name);
 334         }
 335         return false;
 336     }
 337 
 338     /*
 339      * XMLDocumentHandler methods
 340      */
 341 
 342     public void startDocument(XMLLocator locator, String encoding,
 343             NamespaceContext namespaceContext, Augmentations augs)
 344             throws XNIException {
 345         if (fContentHandler != null) {
 346             try {
 347                 fContentHandler.startDocument();
 348             }
 349             catch (SAXException e) {
 350                 throw new XNIException(e);
 351             }
 352         }
 353     }
 354 
 355     public void xmlDecl(String version, String encoding, String standalone,
 356             Augmentations augs) throws XNIException {}
 357 
 358     public void doctypeDecl(String rootElement, String publicId,
 359             String systemId, Augmentations augs) throws XNIException {}
 360 
 361     public void comment(XMLString text, Augmentations augs) throws XNIException {}
 362 
 363     public void processingInstruction(String target, XMLString data,
 364             Augmentations augs) throws XNIException {
 365         if (fContentHandler != null) {
 366             try {
 367                 fContentHandler.processingInstruction(target, data.toString());
 368             }
 369             catch (SAXException e) {
 370                 throw new XNIException(e);
 371             }
 372         }
 373     }
 374 
 375     public void startElement(QName element, XMLAttributes attributes,
 376             Augmentations augs) throws XNIException {
 377         if (fContentHandler != null) {
 378             try {
 379                 fTypeInfoProvider.beginStartElement(augs, attributes);
 380                 fContentHandler.startElement((element.uri != null) ? element.uri : XMLSymbols.EMPTY_STRING,
 381                         element.localpart, element.rawname, fAttrAdapter);
 382             }
 383             catch (SAXException e) {
 384                 throw new XNIException(e);
 385             }
 386             finally {
 387                 fTypeInfoProvider.finishStartElement();
 388             }
 389         }
 390     }
 391 
 392     public void emptyElement(QName element, XMLAttributes attributes,
 393             Augmentations augs) throws XNIException {
 394         /** Split empty element event. **/
 395         startElement(element, attributes, augs);
 396         endElement(element, augs);
 397     }
 398 
 399     public void startGeneralEntity(String name,
 400             XMLResourceIdentifier identifier, String encoding,
 401             Augmentations augs) throws XNIException {}
 402 
 403     public void textDecl(String version, String encoding, Augmentations augs)
 404             throws XNIException {}
 405 
 406     public void endGeneralEntity(String name, Augmentations augs)
 407             throws XNIException {}
 408 
 409     public void characters(XMLString text, Augmentations augs)
 410             throws XNIException {
 411         if (fContentHandler != null) {
 412             // if the type is union it is possible that we receive
 413             // a character call with empty data
 414             if (text.length == 0) {
 415                 return;
 416             }
 417             try {
 418                 fContentHandler.characters(text.ch, text.offset, text.length);
 419             }
 420             catch (SAXException e) {
 421                 throw new XNIException(e);
 422             }
 423         }
 424     }
 425 
 426     public void ignorableWhitespace(XMLString text, Augmentations augs)
 427             throws XNIException {
 428         if (fContentHandler != null) {
 429             try {
 430                 fContentHandler.ignorableWhitespace(text.ch, text.offset, text.length);
 431             }
 432             catch (SAXException e) {
 433                 throw new XNIException(e);
 434             }
 435         }
 436     }
 437 
 438     public void endElement(QName element, Augmentations augs)
 439             throws XNIException {
 440         if (fContentHandler != null) {
 441             try {
 442                 fTypeInfoProvider.beginEndElement(augs);
 443                 fContentHandler.endElement((element.uri != null) ? element.uri : XMLSymbols.EMPTY_STRING,
 444                         element.localpart, element.rawname);
 445             }
 446             catch (SAXException e) {
 447                 throw new XNIException(e);
 448             }
 449             finally {
 450                 fTypeInfoProvider.finishEndElement();
 451             }
 452         }
 453     }
 454 
 455     public void startCDATA(Augmentations augs) throws XNIException {}
 456 
 457     public void endCDATA(Augmentations augs) throws XNIException {}
 458 
 459     public void endDocument(Augmentations augs) throws XNIException {
 460         if (fContentHandler != null) {
 461             try {
 462                 fContentHandler.endDocument();
 463             }
 464             catch (SAXException e) {
 465                 throw new XNIException(e);
 466             }
 467         }
 468     }
 469 
 470     // NO-OP
 471     public void setDocumentSource(XMLDocumentSource source) {}
 472 
 473     public XMLDocumentSource getDocumentSource() {
 474         return fSchemaValidator;
 475     }
 476 
 477     /*
 478      * ContentHandler methods
 479      */
 480 
 481     public void setDocumentLocator(Locator locator) {
 482         fSAXLocatorWrapper.setLocator(locator);
 483         if (fContentHandler != null) {
 484             fContentHandler.setDocumentLocator(locator);
 485         }
 486     }
 487 
 488     public void startDocument() throws SAXException {
 489         fComponentManager.reset();
 490         fSchemaValidator.setDocumentHandler(this);
 491         fValidationManager.setEntityState(this);
 492         fTypeInfoProvider.finishStartElement(); // cleans up TypeInfoProvider
 493         fNeedPushNSContext = true;
 494         if (fUnparsedEntities != null && !fUnparsedEntities.isEmpty()) {
 495             // should only clear this if the last document contained unparsed entities
 496             fUnparsedEntities.clear();
 497         }
 498         fErrorReporter.setDocumentLocator(fSAXLocatorWrapper);
 499         try {
 500             fSchemaValidator.startDocument(fSAXLocatorWrapper, fSAXLocatorWrapper.getEncoding(), fNamespaceContext, null);
 501         }
 502         catch (XMLParseException e) {
 503             throw Util.toSAXParseException(e);
 504         }
 505         catch (XNIException e) {
 506             throw Util.toSAXException(e);
 507         }
 508     }
 509 
 510     public void endDocument() throws SAXException {
 511         fSAXLocatorWrapper.setLocator(null);
 512         try {
 513             fSchemaValidator.endDocument(null);
 514         }
 515         catch (XMLParseException e) {
 516             throw Util.toSAXParseException(e);
 517         }
 518         catch (XNIException e) {
 519             throw Util.toSAXException(e);
 520         }
 521     }
 522 
 523     public void startPrefixMapping(String prefix, String uri)
 524             throws SAXException {
 525         String prefixSymbol;
 526         String uriSymbol;
 527         if (!fStringsInternalized) {
 528             prefixSymbol = (prefix != null) ? fSymbolTable.addSymbol(prefix) : XMLSymbols.EMPTY_STRING;
 529             uriSymbol = (uri != null && uri.length() > 0) ? fSymbolTable.addSymbol(uri) : null;
 530         }
 531         else {
 532             prefixSymbol = (prefix != null) ? prefix : XMLSymbols.EMPTY_STRING;
 533             uriSymbol = (uri != null && uri.length() > 0) ? uri : null;
 534         }
 535         if (fNeedPushNSContext) {
 536             fNeedPushNSContext = false;
 537             fNamespaceContext.pushContext();
 538         }
 539         fNamespaceContext.declarePrefix(prefixSymbol, uriSymbol);
 540         if (fContentHandler != null) {
 541             fContentHandler.startPrefixMapping(prefix, uri);
 542         }
 543     }
 544 
 545     public void endPrefixMapping(String prefix) throws SAXException {
 546         if (fContentHandler != null) {
 547             fContentHandler.endPrefixMapping(prefix);
 548         }
 549     }
 550 
 551     public void startElement(String uri, String localName, String qName,
 552             Attributes atts) throws SAXException {
 553         if (fNeedPushNSContext) {
 554             fNamespaceContext.pushContext();
 555         }
 556         fNeedPushNSContext = true;
 557 
 558         // Fill element QName
 559         fillQName(fElementQName, uri, localName, qName);
 560 
 561         // Fill XMLAttributes
 562         if (atts instanceof Attributes2) {
 563             fillXMLAttributes2((Attributes2) atts);
 564         }
 565         else {
 566             fillXMLAttributes(atts);
 567         }
 568 
 569         try {
 570             fSchemaValidator.startElement(fElementQName, fAttributes, null);
 571         }
 572         catch (XMLParseException e) {
 573             throw Util.toSAXParseException(e);
 574         }
 575         catch (XNIException e) {
 576             throw Util.toSAXException(e);
 577         }
 578     }
 579 
 580     public void endElement(String uri, String localName, String qName)
 581             throws SAXException {
 582         fillQName(fElementQName, uri, localName, qName);
 583         try {
 584             fSchemaValidator.endElement(fElementQName, null);
 585         }
 586         catch (XMLParseException e) {
 587             throw Util.toSAXParseException(e);
 588         }
 589         catch (XNIException e) {
 590             throw Util.toSAXException(e);
 591         }
 592         finally {
 593             fNamespaceContext.popContext();
 594         }
 595     }
 596 
 597     public void characters(char[] ch, int start, int length)
 598             throws SAXException {
 599         try {
 600             fTempString.setValues(ch, start, length);
 601             fSchemaValidator.characters(fTempString, null);
 602         }
 603         catch (XMLParseException e) {
 604             throw Util.toSAXParseException(e);
 605         }
 606         catch (XNIException e) {
 607             throw Util.toSAXException(e);
 608         }
 609     }
 610 
 611     public void ignorableWhitespace(char[] ch, int start, int length)
 612             throws SAXException {
 613         try {
 614             fTempString.setValues(ch, start, length);
 615             fSchemaValidator.ignorableWhitespace(fTempString, null);
 616         }
 617         catch (XMLParseException e) {
 618             throw Util.toSAXParseException(e);
 619         }
 620         catch (XNIException e) {
 621             throw Util.toSAXException(e);
 622         }
 623     }
 624 
 625     public void processingInstruction(String target, String data)
 626             throws SAXException {
 627         /**
 628          * Processing instructions do not participate in schema validation,
 629          * so just forward the event to the application's content
 630          * handler.
 631          */
 632         if (fContentHandler != null) {
 633             fContentHandler.processingInstruction(target, data);
 634         }
 635     }
 636 
 637     public void skippedEntity(String name) throws SAXException {
 638         // there seems to be no corresponding method on XMLDocumentFilter.
 639         // just pass it down to the output, if any.
 640         if (fContentHandler != null) {
 641             fContentHandler.skippedEntity(name);
 642         }
 643     }
 644 
 645     /*
 646      * DTDHandler methods
 647      */
 648 
 649     public void notationDecl(String name, String publicId,
 650             String systemId) throws SAXException {}
 651 
 652     public void unparsedEntityDecl(String name, String publicId,
 653             String systemId, String notationName) throws SAXException {
 654         if (fUnparsedEntities == null) {
 655             fUnparsedEntities = new HashMap<>();
 656         }
 657         fUnparsedEntities.put(name, name);
 658     }
 659 
 660     /*
 661      * ValidatorHelper methods
 662      */
 663 
 664     public void validate(Source source, Result result)
 665         throws SAXException, IOException {
 666         if (result instanceof SAXResult || result == null) {
 667             final SAXSource saxSource = (SAXSource) source;
 668             final SAXResult saxResult = (SAXResult) result;
 669 
 670             if (result != null) {
 671                 setContentHandler(saxResult.getHandler());
 672             }
 673 
 674             try {
 675                 XMLReader reader = saxSource.getXMLReader();
 676                 if( reader==null ) {
 677                     // create one now
 678                     SAXParserFactory spf = fComponentManager.getFeature(Constants.ORACLE_FEATURE_SERVICE_MECHANISM) ?
 679                                     SAXParserFactory.newInstance() : new SAXParserFactoryImpl();
 680                     spf.setNamespaceAware(true);
 681                     try {
 682                         spf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING,
 683                                 fComponentManager.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING));
 684                         reader = spf.newSAXParser().getXMLReader();
 685                         // If this is a Xerces SAX parser, set the security manager if there is one
 686                         if (reader instanceof com.sun.org.apache.xerces.internal.parsers.SAXParser) {
 687                            XMLSecurityManager securityManager = (XMLSecurityManager) fComponentManager.getProperty(SECURITY_MANAGER);
 688                            if (securityManager != null) {
 689                                try {
 690                                    reader.setProperty(SECURITY_MANAGER, securityManager);
 691                                }
 692                                // Ignore the exception if the security manager cannot be set.
 693                                catch (SAXException exc) {}
 694                            }
 695                            try {
 696                                XMLSecurityPropertyManager spm = (XMLSecurityPropertyManager)
 697                                        fComponentManager.getProperty(XML_SECURITY_PROPERTY_MANAGER);
 698                                reader.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD,
 699                                        spm.getValue(XMLSecurityPropertyManager.Property.ACCESS_EXTERNAL_DTD));
 700                            } catch (SAXException exc) {
 701                                XMLSecurityManager.printWarning(reader.getClass().getName(),
 702                                        XMLConstants.ACCESS_EXTERNAL_DTD, exc);
 703                            }
 704                         }
 705 
 706                         // Passing on the CatalogFeatures settings from a configuration object to the reader
 707                         JdkXmlUtils.catalogFeaturesConfig2Reader(fComponentManager, reader);
 708                     } catch( Exception e ) {
 709                         // this is impossible, but better safe than sorry
 710                         throw new FactoryConfigurationError(e);
 711                     }
 712                 }
 713 
 714                 // If XML names and Namespace URIs are already internalized we
 715                 // can avoid running them through the SymbolTable.
 716                 try {
 717                     fStringsInternalized = reader.getFeature(STRING_INTERNING);
 718                 }
 719                 catch (SAXException exc) {
 720                     // The feature isn't recognized or getting it is not supported.
 721                     // In either case, assume that strings are not internalized.
 722                     fStringsInternalized = false;
 723                 }
 724 
 725                 ErrorHandler errorHandler = fComponentManager.getErrorHandler();
 726                 reader.setErrorHandler(errorHandler != null ? errorHandler : DraconianErrorHandler.getInstance());
 727                 reader.setEntityResolver(fResolutionForwarder);
 728                 fResolutionForwarder.setEntityResolver(fComponentManager.getResourceResolver());
 729                 reader.setContentHandler(this);
 730                 reader.setDTDHandler(this);
 731 
 732                 InputSource is = saxSource.getInputSource();
 733                 reader.parse(is);
 734             }
 735             finally {
 736                 // release the reference to user's handler ASAP
 737                 setContentHandler(null);
 738             }
 739             return;
 740         }
 741         throw new IllegalArgumentException(JAXPValidationMessageFormatter.formatMessage(fComponentManager.getLocale(),
 742                 "SourceResultMismatch",
 743                 new Object [] {source.getClass().getName(), result.getClass().getName()}));
 744     }
 745 
 746     /*
 747      * PSVIProvider methods
 748      */
 749 
 750     public ElementPSVI getElementPSVI() {
 751         return fTypeInfoProvider.getElementPSVI();
 752     }
 753 
 754     public AttributePSVI getAttributePSVI(int index) {
 755         return fTypeInfoProvider.getAttributePSVI(index);
 756     }
 757 
 758     public AttributePSVI getAttributePSVIByName(String uri, String localname) {
 759         return fTypeInfoProvider.getAttributePSVIByName(uri, localname);
 760     }
 761 
 762     //
 763     //
 764     // helper methods
 765     //
 766     //
 767 
 768     /** Fills in a QName object. */
 769     private void fillQName(QName toFill, String uri, String localpart, String raw) {
 770         if (!fStringsInternalized) {
 771             uri = (uri != null && uri.length() > 0) ? fSymbolTable.addSymbol(uri) : null;
 772             localpart = (localpart != null) ? fSymbolTable.addSymbol(localpart) : XMLSymbols.EMPTY_STRING;
 773             raw = (raw != null) ? fSymbolTable.addSymbol(raw) : XMLSymbols.EMPTY_STRING;
 774         }
 775         else {
 776             if (uri != null && uri.length() == 0) {
 777                 uri = null;
 778             }
 779             if (localpart == null) {
 780                 localpart = XMLSymbols.EMPTY_STRING;
 781             }
 782             if (raw == null) {
 783                 raw = XMLSymbols.EMPTY_STRING;
 784             }
 785         }
 786         String prefix = XMLSymbols.EMPTY_STRING;
 787         int prefixIdx = raw.indexOf(':');
 788         if (prefixIdx != -1) {
 789             prefix = fSymbolTable.addSymbol(raw.substring(0, prefixIdx));
 790         }
 791         toFill.setValues(prefix, localpart, raw, uri);
 792     }
 793 
 794     /** Fills in the XMLAttributes object. */
 795     private void fillXMLAttributes(Attributes att) {
 796         fAttributes.removeAllAttributes();
 797         final int len = att.getLength();
 798         for (int i = 0; i < len; ++i) {
 799             fillXMLAttribute(att, i);
 800             fAttributes.setSpecified(i, true);
 801         }
 802     }
 803 
 804     /** Fills in the XMLAttributes object. */
 805     private void fillXMLAttributes2(Attributes2 att) {
 806         fAttributes.removeAllAttributes();
 807         final int len = att.getLength();
 808         for (int i = 0; i < len; ++i) {
 809             fillXMLAttribute(att, i);
 810             fAttributes.setSpecified(i, att.isSpecified(i));
 811             if (att.isDeclared(i)) {
 812                 fAttributes.getAugmentations(i).putItem(Constants.ATTRIBUTE_DECLARED, Boolean.TRUE);
 813             }
 814         }
 815     }
 816 
 817     /** Adds an attribute to the XMLAttributes object. */
 818     private void fillXMLAttribute(Attributes att, int index) {
 819         fillQName(fAttributeQName, att.getURI(index), att.getLocalName(index), att.getQName(index));
 820         String type = att.getType(index);
 821         fAttributes.addAttributeNS(fAttributeQName, (type != null) ? type : XMLSymbols.fCDATASymbol, att.getValue(index));
 822     }
 823 
 824     /**
 825      * {@link TypeInfoProvider} implementation.
 826      *
 827      * REVISIT: I'm not sure if this code should belong here.
 828      */
 829     private final XMLSchemaTypeInfoProvider fTypeInfoProvider = new XMLSchemaTypeInfoProvider();
 830     private class XMLSchemaTypeInfoProvider extends TypeInfoProvider {
 831 
 832         /** Element augmentations: contains ElementPSVI. **/
 833         private Augmentations fElementAugs;
 834 
 835         /** Attributes: augmentations for each attribute contain AttributePSVI. **/
 836         private XMLAttributes fAttributes;
 837 
 838         /** In start element. **/
 839         private boolean fInStartElement = false;
 840 
 841         /** In end element. **/
 842         private boolean fInEndElement = false;
 843 
 844         /** Initializes the TypeInfoProvider with type information for the current element. **/
 845         void beginStartElement(Augmentations elementAugs, XMLAttributes attributes) {
 846             fInStartElement = true;
 847             fElementAugs = elementAugs;
 848             fAttributes = attributes;
 849         }
 850 
 851         /** Cleanup at the end of start element. **/
 852         void finishStartElement() {
 853             fInStartElement = false;
 854             fElementAugs = null;
 855             fAttributes = null;
 856         }
 857 
 858         /** Initializes the TypeInfoProvider with type information for the current element. **/
 859         void beginEndElement(Augmentations elementAugs) {
 860             fInEndElement = true;
 861             fElementAugs = elementAugs;
 862         }
 863 
 864         /** Cleanup at the end of end element. **/
 865         void finishEndElement() {
 866             fInEndElement = false;
 867             fElementAugs = null;
 868         }
 869 
 870         /**
 871          * Throws a {@link IllegalStateException} if we are not in
 872          * the startElement callback. the JAXP API requires this
 873          * for most of the public methods.
 874          */
 875         private void checkState(boolean forElementInfo) {
 876             if (! (fInStartElement || (fInEndElement && forElementInfo))) {
 877                 throw new IllegalStateException(JAXPValidationMessageFormatter.formatMessage(fComponentManager.getLocale(),
 878                         "TypeInfoProviderIllegalState", null));
 879             }
 880         }
 881 
 882         public TypeInfo getAttributeTypeInfo(int index) {
 883             checkState(false);
 884             return getAttributeType(index);
 885         }
 886 
 887         private TypeInfo getAttributeType( int index ) {
 888             checkState(false);
 889             if( index<0 || fAttributes.getLength()<=index )
 890                 throw new IndexOutOfBoundsException(Integer.toString(index));
 891             Augmentations augs = fAttributes.getAugmentations(index);
 892             if (augs == null) return null;
 893             AttributePSVI psvi = (AttributePSVI)augs.getItem(Constants.ATTRIBUTE_PSVI);
 894             return getTypeInfoFromPSVI(psvi);
 895         }
 896 
 897         public TypeInfo getAttributeTypeInfo(String attributeUri, String attributeLocalName) {
 898             checkState(false);
 899             return getAttributeTypeInfo(fAttributes.getIndex(attributeUri,attributeLocalName));
 900         }
 901 
 902         public TypeInfo getAttributeTypeInfo(String attributeQName) {
 903             checkState(false);
 904             return getAttributeTypeInfo(fAttributes.getIndex(attributeQName));
 905         }
 906 
 907         public TypeInfo getElementTypeInfo() {
 908             checkState(true);
 909             if (fElementAugs == null) return null;
 910             ElementPSVI psvi = (ElementPSVI)fElementAugs.getItem(Constants.ELEMENT_PSVI);
 911             return getTypeInfoFromPSVI(psvi);
 912         }
 913 
 914         private TypeInfo getTypeInfoFromPSVI( ItemPSVI psvi ) {
 915             if(psvi==null)  return null;
 916 
 917             // TODO: make sure if this is correct.
 918             // TODO: since the number of types in a schema is quite limited,
 919             // TypeInfoImpl should be pooled. Even better, it should be a part
 920             // of the element decl.
 921             if( psvi.getValidity()== ElementPSVI.VALIDITY_VALID ) {
 922                 XSTypeDefinition t = psvi.getMemberTypeDefinition();
 923                 if (t != null) {
 924                     return (t instanceof TypeInfo) ? (TypeInfo) t : null;
 925                 }
 926             }
 927 
 928             XSTypeDefinition t = psvi.getTypeDefinition();
 929             // TODO: can t be null?
 930             if (t != null) {
 931                 return (t instanceof TypeInfo) ? (TypeInfo) t : null;
 932             }
 933             return null;
 934         }
 935 
 936         public boolean isIdAttribute(int index) {
 937             checkState(false);
 938             XSSimpleType type = (XSSimpleType)getAttributeType(index);
 939             if(type==null)  return false;
 940             return type.isIDType();
 941         }
 942 
 943         public boolean isSpecified(int index) {
 944             checkState(false);
 945             return fAttributes.isSpecified(index);
 946         }
 947 
 948         /*
 949          * Other methods
 950          */
 951 
 952         // PSVIProvider support
 953         ElementPSVI getElementPSVI() {
 954             return (fElementAugs != null) ? (ElementPSVI) fElementAugs.getItem(Constants.ELEMENT_PSVI) : null;
 955         }
 956 
 957         AttributePSVI getAttributePSVI(int index) {
 958             if (fAttributes != null) {
 959                 Augmentations augs = fAttributes.getAugmentations(index);
 960                 if (augs != null) {
 961                     return (AttributePSVI) augs.getItem(Constants.ATTRIBUTE_PSVI);
 962                 }
 963             }
 964             return null;
 965         }
 966 
 967         AttributePSVI getAttributePSVIByName(String uri, String localname) {
 968             if (fAttributes != null) {
 969                 Augmentations augs = fAttributes.getAugmentations(uri, localname);
 970                 if (augs != null) {
 971                     return (AttributePSVI) augs.getItem(Constants.ATTRIBUTE_PSVI);
 972                 }
 973             }
 974             return null;
 975         }
 976     }
 977 
 978     /** SAX adapter for an LSResourceResolver. */
 979     private final ResolutionForwarder fResolutionForwarder = new ResolutionForwarder(null);
 980     static final class ResolutionForwarder
 981         implements EntityResolver2 {
 982 
 983         //
 984         // Data
 985         //
 986 
 987         /** XML 1.0 type constant according to DOM L3 LS REC spec "http://www.w3.org/TR/2004/REC-DOM-Level-3-LS-20040407/" */
 988         private static final String XML_TYPE = "http://www.w3.org/TR/REC-xml";
 989 
 990         /** The DOM entity resolver. */
 991         protected LSResourceResolver fEntityResolver;
 992 
 993         //
 994         // Constructors
 995         //
 996 
 997         /** Default constructor. */
 998         public ResolutionForwarder() {}
 999 
1000         /** Wraps the specified DOM entity resolver. */
1001         public ResolutionForwarder(LSResourceResolver entityResolver) {
1002             setEntityResolver(entityResolver);
1003         }
1004 
1005         //
1006         // Public methods
1007         //
1008 
1009         /** Sets the DOM entity resolver. */
1010         public void setEntityResolver(LSResourceResolver entityResolver) {
1011             fEntityResolver = entityResolver;
1012         } // setEntityResolver(LSResourceResolver)
1013 
1014         /** Returns the DOM entity resolver. */
1015         public LSResourceResolver getEntityResolver() {
1016             return fEntityResolver;
1017         } // getEntityResolver():LSResourceResolver
1018 
1019         /**
1020          * Always returns <code>null</code>. An LSResourceResolver has no corresponding method.
1021          */
1022         public InputSource getExternalSubset(String name, String baseURI)
1023                 throws SAXException, IOException {
1024             return null;
1025         }
1026 
1027         /**
1028          * Resolves the given resource and adapts the <code>LSInput</code>
1029          * returned into an <code>InputSource</code>.
1030          */
1031         public InputSource resolveEntity(String name, String publicId,
1032                 String baseURI, String systemId) throws SAXException, IOException {
1033             if (fEntityResolver != null) {
1034                 LSInput lsInput = fEntityResolver.resolveResource(XML_TYPE, null, publicId, systemId, baseURI);
1035                 if (lsInput != null) {
1036                     final String pubId = lsInput.getPublicId();
1037                     final String sysId = lsInput.getSystemId();
1038                     final String baseSystemId = lsInput.getBaseURI();
1039                     final Reader charStream = lsInput.getCharacterStream();
1040                     final InputStream byteStream = lsInput.getByteStream();
1041                     final String data = lsInput.getStringData();
1042                     final String encoding = lsInput.getEncoding();
1043 
1044                     /**
1045                      * An LSParser looks at inputs specified in LSInput in
1046                      * the following order: characterStream, byteStream,
1047                      * stringData, systemId, publicId. For consistency
1048                      * with the DOM Level 3 Load and Save Recommendation
1049                      * use the same lookup order here.
1050                      */
1051                     InputSource inputSource = new InputSource();
1052                     inputSource.setPublicId(pubId);
1053                     inputSource.setSystemId((baseSystemId != null) ? resolveSystemId(sysId, baseSystemId) : sysId);
1054 
1055                     if (charStream != null) {
1056                         inputSource.setCharacterStream(charStream);
1057                     }
1058                     else if (byteStream != null) {
1059                         inputSource.setByteStream(byteStream);
1060                     }
1061                     else if (data != null && data.length() != 0) {
1062                         inputSource.setCharacterStream(new StringReader(data));
1063                     }
1064                     inputSource.setEncoding(encoding);
1065                     return inputSource;
1066                 }
1067             }
1068             return null;
1069         }
1070 
1071         /** Delegates to EntityResolver2.resolveEntity(String, String, String, String). */
1072         public InputSource resolveEntity(String publicId, String systemId)
1073                 throws SAXException, IOException {
1074             return resolveEntity(null, publicId, null, systemId);
1075         }
1076 
1077         /** Resolves a system identifier against a base URI. */
1078         private String resolveSystemId(String systemId, String baseURI) {
1079             try {
1080                 return XMLEntityManager.expandSystemId(systemId, baseURI, false);
1081             }
1082             // In the event that resolution failed against the
1083             // base URI, just return the system id as is. There's not
1084             // much else we can do.
1085             catch (URI.MalformedURIException ex) {
1086                 return systemId;
1087             }
1088         }
1089     }
1090 }