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