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                            reader.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, 
 679                                    fComponentManager.getProperty(XMLConstants.ACCESS_EXTERNAL_DTD));
 680                         // If this is a Xerces SAX parser, set the security manager if there is one
 681                         if (reader instanceof com.sun.org.apache.xerces.internal.parsers.SAXParser) {
 682                            SecurityManager securityManager = (SecurityManager) fComponentManager.getProperty(SECURITY_MANAGER);
 683                            if (securityManager != null) {
 684                                try {
 685                                    reader.setProperty(SECURITY_MANAGER, securityManager);
 686                                }
 687                                // Ignore the exception if the security manager cannot be set.
 688                                catch (SAXException exc) {}
 689                            }
 690                            reader.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, 
 691                                    fComponentManager.getProperty(XMLConstants.ACCESS_EXTERNAL_DTD));
 692                         }
 693                     } catch( Exception e ) {
 694                         // this is impossible, but better safe than sorry
 695                         throw new FactoryConfigurationError(e);
 696                     }
 697                 }
 698 
 699                 // If XML names and Namespace URIs are already internalized we
 700                 // can avoid running them through the SymbolTable.
 701                 try {
 702                     fStringsInternalized = reader.getFeature(STRING_INTERNING);
 703                 }
 704                 catch (SAXException exc) {
 705                     // The feature isn't recognized or getting it is not supported.
 706                     // In either case, assume that strings are not internalized.
 707                     fStringsInternalized = false;
 708                 }
 709 
 710                 ErrorHandler errorHandler = fComponentManager.getErrorHandler();
 711                 reader.setErrorHandler(errorHandler != null ? errorHandler : DraconianErrorHandler.getInstance());
 712                 reader.setEntityResolver(fResolutionForwarder);
 713                 fResolutionForwarder.setEntityResolver(fComponentManager.getResourceResolver());
 714                 reader.setContentHandler(this);
 715                 reader.setDTDHandler(this);
 716 
 717                 InputSource is = saxSource.getInputSource();
 718                 reader.parse(is);
 719             }
 720             finally {
 721                 // release the reference to user's handler ASAP
 722                 setContentHandler(null);
 723             }
 724             return;
 725         }
 726         throw new IllegalArgumentException(JAXPValidationMessageFormatter.formatMessage(fComponentManager.getLocale(),
 727                 "SourceResultMismatch",
 728                 new Object [] {source.getClass().getName(), result.getClass().getName()}));
 729     }
 730 
 731     /*
 732      * PSVIProvider methods
 733      */
 734 
 735     public ElementPSVI getElementPSVI() {
 736         return fTypeInfoProvider.getElementPSVI();
 737     }
 738 
 739     public AttributePSVI getAttributePSVI(int index) {
 740         return fTypeInfoProvider.getAttributePSVI(index);
 741     }
 742 
 743     public AttributePSVI getAttributePSVIByName(String uri, String localname) {
 744         return fTypeInfoProvider.getAttributePSVIByName(uri, localname);
 745     }
 746 
 747     //
 748     //
 749     // helper methods
 750     //
 751     //
 752 
 753     /** Fills in a QName object. */
 754     private void fillQName(QName toFill, String uri, String localpart, String raw) {
 755         if (!fStringsInternalized) {
 756             uri = (uri != null && uri.length() > 0) ? fSymbolTable.addSymbol(uri) : null;
 757             localpart = (localpart != null) ? fSymbolTable.addSymbol(localpart) : XMLSymbols.EMPTY_STRING;
 758             raw = (raw != null) ? fSymbolTable.addSymbol(raw) : XMLSymbols.EMPTY_STRING;
 759         }
 760         else {
 761             if (uri != null && uri.length() == 0) {
 762                 uri = null;
 763             }
 764             if (localpart == null) {
 765                 localpart = XMLSymbols.EMPTY_STRING;
 766             }
 767             if (raw == null) {
 768                 raw = XMLSymbols.EMPTY_STRING;
 769             }
 770         }
 771         String prefix = XMLSymbols.EMPTY_STRING;
 772         int prefixIdx = raw.indexOf(':');
 773         if (prefixIdx != -1) {
 774             prefix = fSymbolTable.addSymbol(raw.substring(0, prefixIdx));
 775         }
 776         toFill.setValues(prefix, localpart, raw, uri);
 777     }
 778 
 779     /** Fills in the XMLAttributes object. */
 780     private void fillXMLAttributes(Attributes att) {
 781         fAttributes.removeAllAttributes();
 782         final int len = att.getLength();
 783         for (int i = 0; i < len; ++i) {
 784             fillXMLAttribute(att, i);
 785             fAttributes.setSpecified(i, true);
 786         }
 787     }
 788 
 789     /** Fills in the XMLAttributes object. */
 790     private void fillXMLAttributes2(Attributes2 att) {
 791         fAttributes.removeAllAttributes();
 792         final int len = att.getLength();
 793         for (int i = 0; i < len; ++i) {
 794             fillXMLAttribute(att, i);
 795             fAttributes.setSpecified(i, att.isSpecified(i));
 796             if (att.isDeclared(i)) {
 797                 fAttributes.getAugmentations(i).putItem(Constants.ATTRIBUTE_DECLARED, Boolean.TRUE);
 798             }
 799         }
 800     }
 801 
 802     /** Adds an attribute to the XMLAttributes object. */
 803     private void fillXMLAttribute(Attributes att, int index) {
 804         fillQName(fAttributeQName, att.getURI(index), att.getLocalName(index), att.getQName(index));
 805         String type = att.getType(index);
 806         fAttributes.addAttributeNS(fAttributeQName, (type != null) ? type : XMLSymbols.fCDATASymbol, att.getValue(index));
 807     }
 808 
 809     /**
 810      * {@link TypeInfoProvider} implementation.
 811      *
 812      * REVISIT: I'm not sure if this code should belong here.
 813      */
 814     private final XMLSchemaTypeInfoProvider fTypeInfoProvider = new XMLSchemaTypeInfoProvider();
 815     private class XMLSchemaTypeInfoProvider extends TypeInfoProvider {
 816 
 817         /** Element augmentations: contains ElementPSVI. **/
 818         private Augmentations fElementAugs;
 819 
 820         /** Attributes: augmentations for each attribute contain AttributePSVI. **/
 821         private XMLAttributes fAttributes;
 822 
 823         /** In start element. **/
 824         private boolean fInStartElement = false;
 825 
 826         /** In end element. **/
 827         private boolean fInEndElement = false;
 828 
 829         /** Initializes the TypeInfoProvider with type information for the current element. **/
 830         void beginStartElement(Augmentations elementAugs, XMLAttributes attributes) {
 831             fInStartElement = true;
 832             fElementAugs = elementAugs;
 833             fAttributes = attributes;
 834         }
 835 
 836         /** Cleanup at the end of start element. **/
 837         void finishStartElement() {
 838             fInStartElement = false;
 839             fElementAugs = null;
 840             fAttributes = null;
 841         }
 842 
 843         /** Initializes the TypeInfoProvider with type information for the current element. **/
 844         void beginEndElement(Augmentations elementAugs) {
 845             fInEndElement = true;
 846             fElementAugs = elementAugs;
 847         }
 848 
 849         /** Cleanup at the end of end element. **/
 850         void finishEndElement() {
 851             fInEndElement = false;
 852             fElementAugs = null;
 853         }
 854 
 855         /**
 856          * Throws a {@link IllegalStateException} if we are not in
 857          * the startElement callback. the JAXP API requires this
 858          * for most of the public methods.
 859          */
 860         private void checkState(boolean forElementInfo) {
 861             if (! (fInStartElement || (fInEndElement && forElementInfo))) {
 862                 throw new IllegalStateException(JAXPValidationMessageFormatter.formatMessage(fComponentManager.getLocale(),
 863                         "TypeInfoProviderIllegalState", null));
 864             }
 865         }
 866 
 867         public TypeInfo getAttributeTypeInfo(int index) {
 868             checkState(false);
 869             return getAttributeType(index);
 870         }
 871 
 872         private TypeInfo getAttributeType( int index ) {
 873             checkState(false);
 874             if( index<0 || fAttributes.getLength()<=index )
 875                 throw new IndexOutOfBoundsException(Integer.toString(index));
 876             Augmentations augs = fAttributes.getAugmentations(index);
 877             if (augs == null) return null;
 878             AttributePSVI psvi = (AttributePSVI)augs.getItem(Constants.ATTRIBUTE_PSVI);
 879             return getTypeInfoFromPSVI(psvi);
 880         }
 881 
 882         public TypeInfo getAttributeTypeInfo(String attributeUri, String attributeLocalName) {
 883             checkState(false);
 884             return getAttributeTypeInfo(fAttributes.getIndex(attributeUri,attributeLocalName));
 885         }
 886 
 887         public TypeInfo getAttributeTypeInfo(String attributeQName) {
 888             checkState(false);
 889             return getAttributeTypeInfo(fAttributes.getIndex(attributeQName));
 890         }
 891 
 892         public TypeInfo getElementTypeInfo() {
 893             checkState(true);
 894             if (fElementAugs == null) return null;
 895             ElementPSVI psvi = (ElementPSVI)fElementAugs.getItem(Constants.ELEMENT_PSVI);
 896             return getTypeInfoFromPSVI(psvi);
 897         }
 898 
 899         private TypeInfo getTypeInfoFromPSVI( ItemPSVI psvi ) {
 900             if(psvi==null)  return null;
 901 
 902             // TODO: make sure if this is correct.
 903             // TODO: since the number of types in a schema is quite limited,
 904             // TypeInfoImpl should be pooled. Even better, it should be a part
 905             // of the element decl.
 906             if( psvi.getValidity()== ElementPSVI.VALIDITY_VALID ) {
 907                 XSTypeDefinition t = psvi.getMemberTypeDefinition();
 908                 if (t != null) {
 909                     return (t instanceof TypeInfo) ? (TypeInfo) t : null;
 910                 }
 911             }
 912 
 913             XSTypeDefinition t = psvi.getTypeDefinition();
 914             // TODO: can t be null?
 915             if (t != null) {
 916                 return (t instanceof TypeInfo) ? (TypeInfo) t : null;
 917             }
 918             return null;
 919         }
 920 
 921         public boolean isIdAttribute(int index) {
 922             checkState(false);
 923             XSSimpleType type = (XSSimpleType)getAttributeType(index);
 924             if(type==null)  return false;
 925             return type.isIDType();
 926         }
 927 
 928         public boolean isSpecified(int index) {
 929             checkState(false);
 930             return fAttributes.isSpecified(index);
 931         }
 932 
 933         /*
 934          * Other methods
 935          */
 936 
 937         // PSVIProvider support
 938         ElementPSVI getElementPSVI() {
 939             return (fElementAugs != null) ? (ElementPSVI) fElementAugs.getItem(Constants.ELEMENT_PSVI) : null;
 940         }
 941 
 942         AttributePSVI getAttributePSVI(int index) {
 943             if (fAttributes != null) {
 944                 Augmentations augs = fAttributes.getAugmentations(index);
 945                 if (augs != null) {
 946                     return (AttributePSVI) augs.getItem(Constants.ATTRIBUTE_PSVI);
 947                 }
 948             }
 949             return null;
 950         }
 951 
 952         AttributePSVI getAttributePSVIByName(String uri, String localname) {
 953             if (fAttributes != null) {
 954                 Augmentations augs = fAttributes.getAugmentations(uri, localname);
 955                 if (augs != null) {
 956                     return (AttributePSVI) augs.getItem(Constants.ATTRIBUTE_PSVI);
 957                 }
 958             }
 959             return null;
 960         }
 961     }
 962 
 963     /** SAX adapter for an LSResourceResolver. */
 964     private final ResolutionForwarder fResolutionForwarder = new ResolutionForwarder(null);
 965     static final class ResolutionForwarder
 966         implements EntityResolver2 {
 967 
 968         //
 969         // Data
 970         //
 971 
 972         /** XML 1.0 type constant according to DOM L3 LS REC spec "http://www.w3.org/TR/2004/REC-DOM-Level-3-LS-20040407/" */
 973         private static final String XML_TYPE = "http://www.w3.org/TR/REC-xml";
 974 
 975         /** The DOM entity resolver. */
 976         protected LSResourceResolver fEntityResolver;
 977 
 978         //
 979         // Constructors
 980         //
 981 
 982         /** Default constructor. */
 983         public ResolutionForwarder() {}
 984 
 985         /** Wraps the specified DOM entity resolver. */
 986         public ResolutionForwarder(LSResourceResolver entityResolver) {
 987             setEntityResolver(entityResolver);
 988         }
 989 
 990         //
 991         // Public methods
 992         //
 993 
 994         /** Sets the DOM entity resolver. */
 995         public void setEntityResolver(LSResourceResolver entityResolver) {
 996             fEntityResolver = entityResolver;
 997         } // setEntityResolver(LSResourceResolver)
 998 
 999         /** Returns the DOM entity resolver. */
1000         public LSResourceResolver getEntityResolver() {
1001             return fEntityResolver;
1002         } // getEntityResolver():LSResourceResolver
1003 
1004         /**
1005          * Always returns <code>null</code>. An LSResourceResolver has no corresponding method.
1006          */
1007         public InputSource getExternalSubset(String name, String baseURI)
1008                 throws SAXException, IOException {
1009             return null;
1010         }
1011 
1012         /**
1013          * Resolves the given resource and adapts the <code>LSInput</code>
1014          * returned into an <code>InputSource</code>.
1015          */
1016         public InputSource resolveEntity(String name, String publicId,
1017                 String baseURI, String systemId) throws SAXException, IOException {
1018             if (fEntityResolver != null) {
1019                 LSInput lsInput = fEntityResolver.resolveResource(XML_TYPE, null, publicId, systemId, baseURI);
1020                 if (lsInput != null) {
1021                     final String pubId = lsInput.getPublicId();
1022                     final String sysId = lsInput.getSystemId();
1023                     final String baseSystemId = lsInput.getBaseURI();
1024                     final Reader charStream = lsInput.getCharacterStream();
1025                     final InputStream byteStream = lsInput.getByteStream();
1026                     final String data = lsInput.getStringData();
1027                     final String encoding = lsInput.getEncoding();
1028 
1029                     /**
1030                      * An LSParser looks at inputs specified in LSInput in
1031                      * the following order: characterStream, byteStream,
1032                      * stringData, systemId, publicId. For consistency
1033                      * with the DOM Level 3 Load and Save Recommendation
1034                      * use the same lookup order here.
1035                      */
1036                     InputSource inputSource = new InputSource();
1037                     inputSource.setPublicId(pubId);
1038                     inputSource.setSystemId((baseSystemId != null) ? resolveSystemId(systemId, baseSystemId) : systemId);
1039 
1040                     if (charStream != null) {
1041                         inputSource.setCharacterStream(charStream);
1042                     }
1043                     else if (byteStream != null) {
1044                         inputSource.setByteStream(byteStream);
1045                     }
1046                     else if (data != null && data.length() != 0) {
1047                         inputSource.setCharacterStream(new StringReader(data));
1048                     }
1049                     inputSource.setEncoding(encoding);
1050                     return inputSource;
1051                 }
1052             }
1053             return null;
1054         }
1055 
1056         /** Delegates to EntityResolver2.resolveEntity(String, String, String, String). */
1057         public InputSource resolveEntity(String publicId, String systemId)
1058                 throws SAXException, IOException {
1059             return resolveEntity(null, publicId, null, systemId);
1060         }
1061 
1062         /** Resolves a system identifier against a base URI. */
1063         private String resolveSystemId(String systemId, String baseURI) {
1064             try {
1065                 return XMLEntityManager.expandSystemId(systemId, baseURI, false);
1066             }
1067             // In the event that resolution failed against the
1068             // base URI, just return the system id as is. There's not
1069             // much else we can do.
1070             catch (URI.MalformedURIException ex) {
1071                 return systemId;
1072             }
1073         }
1074     }
1075 }