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