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