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