| /* |
| * reserved comment block |
| * DO NOT REMOVE OR ALTER! |
| */ |
| /* |
| * Copyright 2005 The Apache Software Foundation. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.sun.org.apache.xerces.internal.jaxp.validation; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.Reader; |
| import java.io.StringReader; |
| import java.util.HashMap; |
| |
| import javax.xml.XMLConstants; |
| import javax.xml.parsers.FactoryConfigurationError; |
| import javax.xml.parsers.SAXParserFactory; |
| import javax.xml.transform.Result; |
| import javax.xml.transform.Source; |
| import javax.xml.transform.sax.SAXResult; |
| import javax.xml.transform.sax.SAXSource; |
| import javax.xml.validation.TypeInfoProvider; |
| import javax.xml.validation.ValidatorHandler; |
| |
| import com.sun.org.apache.xerces.internal.impl.Constants; |
| import com.sun.org.apache.xerces.internal.impl.XMLEntityManager; |
| import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter; |
| import com.sun.org.apache.xerces.internal.impl.dv.XSSimpleType; |
| import com.sun.org.apache.xerces.internal.impl.validation.EntityState; |
| import com.sun.org.apache.xerces.internal.impl.validation.ValidationManager; |
| import com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator; |
| import com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl; |
| import com.sun.org.apache.xerces.internal.util.AttributesProxy; |
| import com.sun.org.apache.xerces.internal.util.SAXLocatorWrapper; |
| import com.sun.org.apache.xerces.internal.util.SAXMessageFormatter; |
| import com.sun.org.apache.xerces.internal.util.Status; |
| import com.sun.org.apache.xerces.internal.util.SymbolTable; |
| import com.sun.org.apache.xerces.internal.util.URI; |
| import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl; |
| import com.sun.org.apache.xerces.internal.util.XMLSymbols; |
| import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager; |
| import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager; |
| import com.sun.org.apache.xerces.internal.xni.Augmentations; |
| import com.sun.org.apache.xerces.internal.xni.NamespaceContext; |
| import com.sun.org.apache.xerces.internal.xni.QName; |
| import com.sun.org.apache.xerces.internal.xni.XMLAttributes; |
| import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler; |
| import com.sun.org.apache.xerces.internal.xni.XMLLocator; |
| import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier; |
| import com.sun.org.apache.xerces.internal.xni.XMLString; |
| import com.sun.org.apache.xerces.internal.xni.XNIException; |
| import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException; |
| import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentSource; |
| import com.sun.org.apache.xerces.internal.xni.parser.XMLParseException; |
| import com.sun.org.apache.xerces.internal.xs.AttributePSVI; |
| import com.sun.org.apache.xerces.internal.xs.ElementPSVI; |
| import com.sun.org.apache.xerces.internal.xs.ItemPSVI; |
| import com.sun.org.apache.xerces.internal.xs.PSVIProvider; |
| import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition; |
| import org.w3c.dom.TypeInfo; |
| import org.w3c.dom.ls.LSInput; |
| import org.w3c.dom.ls.LSResourceResolver; |
| import org.xml.sax.Attributes; |
| import org.xml.sax.ContentHandler; |
| import org.xml.sax.DTDHandler; |
| import org.xml.sax.ErrorHandler; |
| import org.xml.sax.InputSource; |
| import org.xml.sax.Locator; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.SAXNotRecognizedException; |
| import org.xml.sax.SAXNotSupportedException; |
| import org.xml.sax.XMLReader; |
| import org.xml.sax.ext.Attributes2; |
| import org.xml.sax.ext.EntityResolver2; |
| |
| /** |
| * <p>Implementation of ValidatorHandler for W3C XML Schemas and |
| * also a validator helper for <code>SAXSource</code>s.</p> |
| * |
| * @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com) |
| * @author Michael Glavassevich, IBM |
| * |
| * @version $Id: ValidatorHandlerImpl.java,v 1.10 2010-11-01 04:40:08 joehw Exp $ |
| */ |
| final class ValidatorHandlerImpl extends ValidatorHandler implements |
| DTDHandler, EntityState, PSVIProvider, ValidatorHelper, XMLDocumentHandler { |
| |
| // feature identifiers |
| |
| /** Feature identifier: namespace prefixes. */ |
| private static final String NAMESPACE_PREFIXES = |
| Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACE_PREFIXES_FEATURE; |
| |
| /** Feature identifier: string interning. */ |
| protected static final String STRING_INTERNING = |
| Constants.SAX_FEATURE_PREFIX + Constants.STRING_INTERNING_FEATURE; |
| |
| // property identifiers |
| |
| /** Property identifier: error reporter. */ |
| private static final String ERROR_REPORTER = |
| Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; |
| |
| /** Property identifier: namespace context. */ |
| private static final String NAMESPACE_CONTEXT = |
| Constants.XERCES_PROPERTY_PREFIX + Constants.NAMESPACE_CONTEXT_PROPERTY; |
| |
| /** Property identifier: XML Schema validator. */ |
| private static final String SCHEMA_VALIDATOR = |
| Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_VALIDATOR_PROPERTY; |
| |
| /** Property identifier: security manager. */ |
| private static final String SECURITY_MANAGER = |
| Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY; |
| |
| /** Property identifier: symbol table. */ |
| private static final String SYMBOL_TABLE = |
| Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; |
| |
| /** Property identifier: validation manager. */ |
| private static final String VALIDATION_MANAGER = |
| Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY; |
| |
| /** Property identifier: Security property manager. */ |
| private static final String XML_SECURITY_PROPERTY_MANAGER = |
| Constants.XML_SECURITY_PROPERTY_MANAGER; |
| |
| // |
| // Data |
| // |
| |
| /** Error reporter. */ |
| private XMLErrorReporter fErrorReporter; |
| |
| /** The namespace context of this document: stores namespaces in scope */ |
| private NamespaceContext fNamespaceContext; |
| |
| /** Schema validator. **/ |
| private XMLSchemaValidator fSchemaValidator; |
| |
| /** Symbol table **/ |
| private SymbolTable fSymbolTable; |
| |
| /** Validation manager. */ |
| private ValidationManager fValidationManager; |
| |
| /** Component manager. **/ |
| private XMLSchemaValidatorComponentManager fComponentManager; |
| |
| /** XML Locator wrapper for SAX. **/ |
| private final SAXLocatorWrapper fSAXLocatorWrapper = new SAXLocatorWrapper(); |
| |
| /** Flag used to track whether the namespace context needs to be pushed. */ |
| private boolean fNeedPushNSContext = true; |
| |
| /** Map for tracking unparsed entities. */ |
| private HashMap fUnparsedEntities = null; |
| |
| /** Flag used to track whether XML names and Namespace URIs have been internalized. */ |
| private boolean fStringsInternalized = false; |
| |
| /** Fields for start element, end element and characters. */ |
| private final QName fElementQName = new QName(); |
| private final QName fAttributeQName = new QName(); |
| private final XMLAttributesImpl fAttributes = new XMLAttributesImpl(); |
| private final AttributesProxy fAttrAdapter = new AttributesProxy(fAttributes); |
| private final XMLString fTempString = new XMLString(); |
| |
| // |
| // User Objects |
| // |
| |
| private ContentHandler fContentHandler = null; |
| |
| /* |
| * Constructors |
| */ |
| |
| public ValidatorHandlerImpl(XSGrammarPoolContainer grammarContainer) { |
| this(new XMLSchemaValidatorComponentManager(grammarContainer)); |
| fComponentManager.addRecognizedFeatures(new String [] {NAMESPACE_PREFIXES}); |
| fComponentManager.setFeature(NAMESPACE_PREFIXES, false); |
| setErrorHandler(null); |
| setResourceResolver(null); |
| } |
| |
| public ValidatorHandlerImpl(XMLSchemaValidatorComponentManager componentManager) { |
| fComponentManager = componentManager; |
| fErrorReporter = (XMLErrorReporter) fComponentManager.getProperty(ERROR_REPORTER); |
| fNamespaceContext = (NamespaceContext) fComponentManager.getProperty(NAMESPACE_CONTEXT); |
| fSchemaValidator = (XMLSchemaValidator) fComponentManager.getProperty(SCHEMA_VALIDATOR); |
| fSymbolTable = (SymbolTable) fComponentManager.getProperty(SYMBOL_TABLE); |
| fValidationManager = (ValidationManager) fComponentManager.getProperty(VALIDATION_MANAGER); |
| } |
| |
| /* |
| * ValidatorHandler methods |
| */ |
| |
| public void setContentHandler(ContentHandler receiver) { |
| fContentHandler = receiver; |
| } |
| |
| public ContentHandler getContentHandler() { |
| return fContentHandler; |
| } |
| |
| public void setErrorHandler(ErrorHandler errorHandler) { |
| fComponentManager.setErrorHandler(errorHandler); |
| } |
| |
| public ErrorHandler getErrorHandler() { |
| return fComponentManager.getErrorHandler(); |
| } |
| |
| public void setResourceResolver(LSResourceResolver resourceResolver) { |
| fComponentManager.setResourceResolver(resourceResolver); |
| } |
| |
| public LSResourceResolver getResourceResolver() { |
| return fComponentManager.getResourceResolver(); |
| } |
| |
| public TypeInfoProvider getTypeInfoProvider() { |
| return fTypeInfoProvider; |
| } |
| |
| public boolean getFeature(String name) |
| throws SAXNotRecognizedException, SAXNotSupportedException { |
| if (name == null) { |
| throw new NullPointerException(); |
| } |
| try { |
| return fComponentManager.getFeature(name); |
| } |
| catch (XMLConfigurationException e) { |
| final String identifier = e.getIdentifier(); |
| final String key = e.getType() == Status.NOT_RECOGNIZED ? |
| "feature-not-recognized" : "feature-not-supported"; |
| throw new SAXNotRecognizedException( |
| SAXMessageFormatter.formatMessage(fComponentManager.getLocale(), |
| key, new Object [] {identifier})); |
| } |
| } |
| |
| public void setFeature(String name, boolean value) |
| throws SAXNotRecognizedException, SAXNotSupportedException { |
| if (name == null) { |
| throw new NullPointerException(); |
| } |
| try { |
| fComponentManager.setFeature(name, value); |
| } |
| catch (XMLConfigurationException e) { |
| final String identifier = e.getIdentifier(); |
| final String key; |
| if (e.getType() == Status.NOT_ALLOWED) { |
| //for now, the identifier can only be (XMLConstants.FEATURE_SECURE_PROCESSING) |
| throw new SAXNotSupportedException( |
| SAXMessageFormatter.formatMessage(fComponentManager.getLocale(), |
| "jaxp-secureprocessing-feature", null)); |
| } else if (e.getType() == Status.NOT_RECOGNIZED) { |
| key = "feature-not-recognized"; |
| } else { |
| key = "feature-not-supported"; |
| } |
| throw new SAXNotRecognizedException( |
| SAXMessageFormatter.formatMessage(fComponentManager.getLocale(), |
| key, new Object [] {identifier})); |
| } |
| } |
| |
| public Object getProperty(String name) |
| throws SAXNotRecognizedException, SAXNotSupportedException { |
| if (name == null) { |
| throw new NullPointerException(); |
| } |
| try { |
| return fComponentManager.getProperty(name); |
| } |
| catch (XMLConfigurationException e) { |
| final String identifier = e.getIdentifier(); |
| final String key = e.getType() == Status.NOT_RECOGNIZED ? |
| "property-not-recognized" : "property-not-supported"; |
| throw new SAXNotRecognizedException( |
| SAXMessageFormatter.formatMessage(fComponentManager.getLocale(), |
| key, new Object [] {identifier})); |
| } |
| } |
| |
| public void setProperty(String name, Object object) |
| throws SAXNotRecognizedException, SAXNotSupportedException { |
| if (name == null) { |
| throw new NullPointerException(); |
| } |
| try { |
| fComponentManager.setProperty(name, object); |
| } |
| catch (XMLConfigurationException e) { |
| final String identifier = e.getIdentifier(); |
| final String key = e.getType() == Status.NOT_RECOGNIZED ? |
| "property-not-recognized" : "property-not-supported"; |
| throw new SAXNotRecognizedException( |
| SAXMessageFormatter.formatMessage(fComponentManager.getLocale(), |
| key, new Object [] {identifier})); |
| } |
| } |
| |
| /* |
| * EntityState methods |
| */ |
| |
| public boolean isEntityDeclared(String name) { |
| return false; |
| } |
| |
| public boolean isEntityUnparsed(String name) { |
| if (fUnparsedEntities != null) { |
| return fUnparsedEntities.containsKey(name); |
| } |
| return false; |
| } |
| |
| /* |
| * XMLDocumentHandler methods |
| */ |
| |
| public void startDocument(XMLLocator locator, String encoding, |
| NamespaceContext namespaceContext, Augmentations augs) |
| throws XNIException { |
| if (fContentHandler != null) { |
| try { |
| fContentHandler.startDocument(); |
| } |
| catch (SAXException e) { |
| throw new XNIException(e); |
| } |
| } |
| } |
| |
| public void xmlDecl(String version, String encoding, String standalone, |
| Augmentations augs) throws XNIException {} |
| |
| public void doctypeDecl(String rootElement, String publicId, |
| String systemId, Augmentations augs) throws XNIException {} |
| |
| public void comment(XMLString text, Augmentations augs) throws XNIException {} |
| |
| public void processingInstruction(String target, XMLString data, |
| Augmentations augs) throws XNIException { |
| if (fContentHandler != null) { |
| try { |
| fContentHandler.processingInstruction(target, data.toString()); |
| } |
| catch (SAXException e) { |
| throw new XNIException(e); |
| } |
| } |
| } |
| |
| public void startElement(QName element, XMLAttributes attributes, |
| Augmentations augs) throws XNIException { |
| if (fContentHandler != null) { |
| try { |
| fTypeInfoProvider.beginStartElement(augs, attributes); |
| fContentHandler.startElement((element.uri != null) ? element.uri : XMLSymbols.EMPTY_STRING, |
| element.localpart, element.rawname, fAttrAdapter); |
| } |
| catch (SAXException e) { |
| throw new XNIException(e); |
| } |
| finally { |
| fTypeInfoProvider.finishStartElement(); |
| } |
| } |
| } |
| |
| public void emptyElement(QName element, XMLAttributes attributes, |
| Augmentations augs) throws XNIException { |
| /** Split empty element event. **/ |
| startElement(element, attributes, augs); |
| endElement(element, augs); |
| } |
| |
| public void startGeneralEntity(String name, |
| XMLResourceIdentifier identifier, String encoding, |
| Augmentations augs) throws XNIException {} |
| |
| public void textDecl(String version, String encoding, Augmentations augs) |
| throws XNIException {} |
| |
| public void endGeneralEntity(String name, Augmentations augs) |
| throws XNIException {} |
| |
| public void characters(XMLString text, Augmentations augs) |
| throws XNIException { |
| if (fContentHandler != null) { |
| // if the type is union it is possible that we receive |
| // a character call with empty data |
| if (text.length == 0) { |
| return; |
| } |
| try { |
| fContentHandler.characters(text.ch, text.offset, text.length); |
| } |
| catch (SAXException e) { |
| throw new XNIException(e); |
| } |
| } |
| } |
| |
| public void ignorableWhitespace(XMLString text, Augmentations augs) |
| throws XNIException { |
| if (fContentHandler != null) { |
| try { |
| fContentHandler.ignorableWhitespace(text.ch, text.offset, text.length); |
| } |
| catch (SAXException e) { |
| throw new XNIException(e); |
| } |
| } |
| } |
| |
| public void endElement(QName element, Augmentations augs) |
| throws XNIException { |
| if (fContentHandler != null) { |
| try { |
| fTypeInfoProvider.beginEndElement(augs); |
| fContentHandler.endElement((element.uri != null) ? element.uri : XMLSymbols.EMPTY_STRING, |
| element.localpart, element.rawname); |
| } |
| catch (SAXException e) { |
| throw new XNIException(e); |
| } |
| finally { |
| fTypeInfoProvider.finishEndElement(); |
| } |
| } |
| } |
| |
| public void startCDATA(Augmentations augs) throws XNIException {} |
| |
| public void endCDATA(Augmentations augs) throws XNIException {} |
| |
| public void endDocument(Augmentations augs) throws XNIException { |
| if (fContentHandler != null) { |
| try { |
| fContentHandler.endDocument(); |
| } |
| catch (SAXException e) { |
| throw new XNIException(e); |
| } |
| } |
| } |
| |
| // NO-OP |
| public void setDocumentSource(XMLDocumentSource source) {} |
| |
| public XMLDocumentSource getDocumentSource() { |
| return fSchemaValidator; |
| } |
| |
| /* |
| * ContentHandler methods |
| */ |
| |
| public void setDocumentLocator(Locator locator) { |
| fSAXLocatorWrapper.setLocator(locator); |
| if (fContentHandler != null) { |
| fContentHandler.setDocumentLocator(locator); |
| } |
| } |
| |
| public void startDocument() throws SAXException { |
| fComponentManager.reset(); |
| fSchemaValidator.setDocumentHandler(this); |
| fValidationManager.setEntityState(this); |
| fTypeInfoProvider.finishStartElement(); // cleans up TypeInfoProvider |
| fNeedPushNSContext = true; |
| if (fUnparsedEntities != null && !fUnparsedEntities.isEmpty()) { |
| // should only clear this if the last document contained unparsed entities |
| fUnparsedEntities.clear(); |
| } |
| fErrorReporter.setDocumentLocator(fSAXLocatorWrapper); |
| try { |
| fSchemaValidator.startDocument(fSAXLocatorWrapper, fSAXLocatorWrapper.getEncoding(), fNamespaceContext, null); |
| } |
| catch (XMLParseException e) { |
| throw Util.toSAXParseException(e); |
| } |
| catch (XNIException e) { |
| throw Util.toSAXException(e); |
| } |
| } |
| |
| public void endDocument() throws SAXException { |
| fSAXLocatorWrapper.setLocator(null); |
| try { |
| fSchemaValidator.endDocument(null); |
| } |
| catch (XMLParseException e) { |
| throw Util.toSAXParseException(e); |
| } |
| catch (XNIException e) { |
| throw Util.toSAXException(e); |
| } |
| } |
| |
| public void startPrefixMapping(String prefix, String uri) |
| throws SAXException { |
| String prefixSymbol; |
| String uriSymbol; |
| if (!fStringsInternalized) { |
| prefixSymbol = (prefix != null) ? fSymbolTable.addSymbol(prefix) : XMLSymbols.EMPTY_STRING; |
| uriSymbol = (uri != null && uri.length() > 0) ? fSymbolTable.addSymbol(uri) : null; |
| } |
| else { |
| prefixSymbol = (prefix != null) ? prefix : XMLSymbols.EMPTY_STRING; |
| uriSymbol = (uri != null && uri.length() > 0) ? uri : null; |
| } |
| if (fNeedPushNSContext) { |
| fNeedPushNSContext = false; |
| fNamespaceContext.pushContext(); |
| } |
| fNamespaceContext.declarePrefix(prefixSymbol, uriSymbol); |
| if (fContentHandler != null) { |
| fContentHandler.startPrefixMapping(prefix, uri); |
| } |
| } |
| |
| public void endPrefixMapping(String prefix) throws SAXException { |
| if (fContentHandler != null) { |
| fContentHandler.endPrefixMapping(prefix); |
| } |
| } |
| |
| public void startElement(String uri, String localName, String qName, |
| Attributes atts) throws SAXException { |
| if (fNeedPushNSContext) { |
| fNamespaceContext.pushContext(); |
| } |
| fNeedPushNSContext = true; |
| |
| // Fill element QName |
| fillQName(fElementQName, uri, localName, qName); |
| |
| // Fill XMLAttributes |
| if (atts instanceof Attributes2) { |
| fillXMLAttributes2((Attributes2) atts); |
| } |
| else { |
| fillXMLAttributes(atts); |
| } |
| |
| try { |
| fSchemaValidator.startElement(fElementQName, fAttributes, null); |
| } |
| catch (XMLParseException e) { |
| throw Util.toSAXParseException(e); |
| } |
| catch (XNIException e) { |
| throw Util.toSAXException(e); |
| } |
| } |
| |
| public void endElement(String uri, String localName, String qName) |
| throws SAXException { |
| fillQName(fElementQName, uri, localName, qName); |
| try { |
| fSchemaValidator.endElement(fElementQName, null); |
| } |
| catch (XMLParseException e) { |
| throw Util.toSAXParseException(e); |
| } |
| catch (XNIException e) { |
| throw Util.toSAXException(e); |
| } |
| finally { |
| fNamespaceContext.popContext(); |
| } |
| } |
| |
| public void characters(char[] ch, int start, int length) |
| throws SAXException { |
| try { |
| fTempString.setValues(ch, start, length); |
| fSchemaValidator.characters(fTempString, null); |
| } |
| catch (XMLParseException e) { |
| throw Util.toSAXParseException(e); |
| } |
| catch (XNIException e) { |
| throw Util.toSAXException(e); |
| } |
| } |
| |
| public void ignorableWhitespace(char[] ch, int start, int length) |
| throws SAXException { |
| try { |
| fTempString.setValues(ch, start, length); |
| fSchemaValidator.ignorableWhitespace(fTempString, null); |
| } |
| catch (XMLParseException e) { |
| throw Util.toSAXParseException(e); |
| } |
| catch (XNIException e) { |
| throw Util.toSAXException(e); |
| } |
| } |
| |
| public void processingInstruction(String target, String data) |
| throws SAXException { |
| /** |
| * Processing instructions do not participate in schema validation, |
| * so just forward the event to the application's content |
| * handler. |
| */ |
| if (fContentHandler != null) { |
| fContentHandler.processingInstruction(target, data); |
| } |
| } |
| |
| public void skippedEntity(String name) throws SAXException { |
| // there seems to be no corresponding method on XMLDocumentFilter. |
| // just pass it down to the output, if any. |
| if (fContentHandler != null) { |
| fContentHandler.skippedEntity(name); |
| } |
| } |
| |
| /* |
| * DTDHandler methods |
| */ |
| |
| public void notationDecl(String name, String publicId, |
| String systemId) throws SAXException {} |
| |
| public void unparsedEntityDecl(String name, String publicId, |
| String systemId, String notationName) throws SAXException { |
| if (fUnparsedEntities == null) { |
| fUnparsedEntities = new HashMap(); |
| } |
| fUnparsedEntities.put(name, name); |
| } |
| |
| /* |
| * ValidatorHelper methods |
| */ |
| |
| public void validate(Source source, Result result) |
| throws SAXException, IOException { |
| if (result instanceof SAXResult || result == null) { |
| final SAXSource saxSource = (SAXSource) source; |
| final SAXResult saxResult = (SAXResult) result; |
| |
| if (result != null) { |
| setContentHandler(saxResult.getHandler()); |
| } |
| |
| try { |
| XMLReader reader = saxSource.getXMLReader(); |
| if( reader==null ) { |
| // create one now |
| SAXParserFactory spf = fComponentManager.getFeature(Constants.ORACLE_FEATURE_SERVICE_MECHANISM) ? |
| SAXParserFactory.newInstance() : new SAXParserFactoryImpl(); |
| spf.setNamespaceAware(true); |
| try { |
| spf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, |
| fComponentManager.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING)); |
| reader = spf.newSAXParser().getXMLReader(); |
| // If this is a Xerces SAX parser, set the security manager if there is one |
| if (reader instanceof com.sun.org.apache.xerces.internal.parsers.SAXParser) { |
| XMLSecurityManager securityManager = (XMLSecurityManager) fComponentManager.getProperty(SECURITY_MANAGER); |
| if (securityManager != null) { |
| try { |
| reader.setProperty(SECURITY_MANAGER, securityManager); |
| } |
| // Ignore the exception if the security manager cannot be set. |
| catch (SAXException exc) {} |
| } |
| try { |
| XMLSecurityPropertyManager spm = (XMLSecurityPropertyManager) |
| fComponentManager.getProperty(XML_SECURITY_PROPERTY_MANAGER); |
| reader.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, |
| spm.getValue(XMLSecurityPropertyManager.Property.ACCESS_EXTERNAL_DTD)); |
| } catch (SAXException exc) { |
| System.err.println("Warning: " + reader.getClass().getName() + ": " + |
| exc.getMessage()); |
| } |
| } |
| } catch( Exception e ) { |
| // this is impossible, but better safe than sorry |
| throw new FactoryConfigurationError(e); |
| } |
| } |
| |
| // If XML names and Namespace URIs are already internalized we |
| // can avoid running them through the SymbolTable. |
| try { |
| fStringsInternalized = reader.getFeature(STRING_INTERNING); |
| } |
| catch (SAXException exc) { |
| // The feature isn't recognized or getting it is not supported. |
| // In either case, assume that strings are not internalized. |
| fStringsInternalized = false; |
| } |
| |
| ErrorHandler errorHandler = fComponentManager.getErrorHandler(); |
| reader.setErrorHandler(errorHandler != null ? errorHandler : DraconianErrorHandler.getInstance()); |
| reader.setEntityResolver(fResolutionForwarder); |
| fResolutionForwarder.setEntityResolver(fComponentManager.getResourceResolver()); |
| reader.setContentHandler(this); |
| reader.setDTDHandler(this); |
| |
| InputSource is = saxSource.getInputSource(); |
| reader.parse(is); |
| } |
| finally { |
| // release the reference to user's handler ASAP |
| setContentHandler(null); |
| } |
| return; |
| } |
| throw new IllegalArgumentException(JAXPValidationMessageFormatter.formatMessage(fComponentManager.getLocale(), |
| "SourceResultMismatch", |
| new Object [] {source.getClass().getName(), result.getClass().getName()})); |
| } |
| |
| /* |
| * PSVIProvider methods |
| */ |
| |
| public ElementPSVI getElementPSVI() { |
| return fTypeInfoProvider.getElementPSVI(); |
| } |
| |
| public AttributePSVI getAttributePSVI(int index) { |
| return fTypeInfoProvider.getAttributePSVI(index); |
| } |
| |
| public AttributePSVI getAttributePSVIByName(String uri, String localname) { |
| return fTypeInfoProvider.getAttributePSVIByName(uri, localname); |
| } |
| |
| // |
| // |
| // helper methods |
| // |
| // |
| |
| /** Fills in a QName object. */ |
| private void fillQName(QName toFill, String uri, String localpart, String raw) { |
| if (!fStringsInternalized) { |
| uri = (uri != null && uri.length() > 0) ? fSymbolTable.addSymbol(uri) : null; |
| localpart = (localpart != null) ? fSymbolTable.addSymbol(localpart) : XMLSymbols.EMPTY_STRING; |
| raw = (raw != null) ? fSymbolTable.addSymbol(raw) : XMLSymbols.EMPTY_STRING; |
| } |
| else { |
| if (uri != null && uri.length() == 0) { |
| uri = null; |
| } |
| if (localpart == null) { |
| localpart = XMLSymbols.EMPTY_STRING; |
| } |
| if (raw == null) { |
| raw = XMLSymbols.EMPTY_STRING; |
| } |
| } |
| String prefix = XMLSymbols.EMPTY_STRING; |
| int prefixIdx = raw.indexOf(':'); |
| if (prefixIdx != -1) { |
| prefix = fSymbolTable.addSymbol(raw.substring(0, prefixIdx)); |
| } |
| toFill.setValues(prefix, localpart, raw, uri); |
| } |
| |
| /** Fills in the XMLAttributes object. */ |
| private void fillXMLAttributes(Attributes att) { |
| fAttributes.removeAllAttributes(); |
| final int len = att.getLength(); |
| for (int i = 0; i < len; ++i) { |
| fillXMLAttribute(att, i); |
| fAttributes.setSpecified(i, true); |
| } |
| } |
| |
| /** Fills in the XMLAttributes object. */ |
| private void fillXMLAttributes2(Attributes2 att) { |
| fAttributes.removeAllAttributes(); |
| final int len = att.getLength(); |
| for (int i = 0; i < len; ++i) { |
| fillXMLAttribute(att, i); |
| fAttributes.setSpecified(i, att.isSpecified(i)); |
| if (att.isDeclared(i)) { |
| fAttributes.getAugmentations(i).putItem(Constants.ATTRIBUTE_DECLARED, Boolean.TRUE); |
| } |
| } |
| } |
| |
| /** Adds an attribute to the XMLAttributes object. */ |
| private void fillXMLAttribute(Attributes att, int index) { |
| fillQName(fAttributeQName, att.getURI(index), att.getLocalName(index), att.getQName(index)); |
| String type = att.getType(index); |
| fAttributes.addAttributeNS(fAttributeQName, (type != null) ? type : XMLSymbols.fCDATASymbol, att.getValue(index)); |
| } |
| |
| /** |
| * {@link TypeInfoProvider} implementation. |
| * |
| * REVISIT: I'm not sure if this code should belong here. |
| */ |
| private final XMLSchemaTypeInfoProvider fTypeInfoProvider = new XMLSchemaTypeInfoProvider(); |
| private class XMLSchemaTypeInfoProvider extends TypeInfoProvider { |
| |
| /** Element augmentations: contains ElementPSVI. **/ |
| private Augmentations fElementAugs; |
| |
| /** Attributes: augmentations for each attribute contain AttributePSVI. **/ |
| private XMLAttributes fAttributes; |
| |
| /** In start element. **/ |
| private boolean fInStartElement = false; |
| |
| /** In end element. **/ |
| private boolean fInEndElement = false; |
| |
| /** Initializes the TypeInfoProvider with type information for the current element. **/ |
| void beginStartElement(Augmentations elementAugs, XMLAttributes attributes) { |
| fInStartElement = true; |
| fElementAugs = elementAugs; |
| fAttributes = attributes; |
| } |
| |
| /** Cleanup at the end of start element. **/ |
| void finishStartElement() { |
| fInStartElement = false; |
| fElementAugs = null; |
| fAttributes = null; |
| } |
| |
| /** Initializes the TypeInfoProvider with type information for the current element. **/ |
| void beginEndElement(Augmentations elementAugs) { |
| fInEndElement = true; |
| fElementAugs = elementAugs; |
| } |
| |
| /** Cleanup at the end of end element. **/ |
| void finishEndElement() { |
| fInEndElement = false; |
| fElementAugs = null; |
| } |
| |
| /** |
| * Throws a {@link IllegalStateException} if we are not in |
| * the startElement callback. the JAXP API requires this |
| * for most of the public methods. |
| */ |
| private void checkState(boolean forElementInfo) { |
| if (! (fInStartElement || (fInEndElement && forElementInfo))) { |
| throw new IllegalStateException(JAXPValidationMessageFormatter.formatMessage(fComponentManager.getLocale(), |
| "TypeInfoProviderIllegalState", null)); |
| } |
| } |
| |
| public TypeInfo getAttributeTypeInfo(int index) { |
| checkState(false); |
| return getAttributeType(index); |
| } |
| |
| private TypeInfo getAttributeType( int index ) { |
| checkState(false); |
| if( index<0 || fAttributes.getLength()<=index ) |
| throw new IndexOutOfBoundsException(Integer.toString(index)); |
| Augmentations augs = fAttributes.getAugmentations(index); |
| if (augs == null) return null; |
| AttributePSVI psvi = (AttributePSVI)augs.getItem(Constants.ATTRIBUTE_PSVI); |
| return getTypeInfoFromPSVI(psvi); |
| } |
| |
| public TypeInfo getAttributeTypeInfo(String attributeUri, String attributeLocalName) { |
| checkState(false); |
| return getAttributeTypeInfo(fAttributes.getIndex(attributeUri,attributeLocalName)); |
| } |
| |
| public TypeInfo getAttributeTypeInfo(String attributeQName) { |
| checkState(false); |
| return getAttributeTypeInfo(fAttributes.getIndex(attributeQName)); |
| } |
| |
| public TypeInfo getElementTypeInfo() { |
| checkState(true); |
| if (fElementAugs == null) return null; |
| ElementPSVI psvi = (ElementPSVI)fElementAugs.getItem(Constants.ELEMENT_PSVI); |
| return getTypeInfoFromPSVI(psvi); |
| } |
| |
| private TypeInfo getTypeInfoFromPSVI( ItemPSVI psvi ) { |
| if(psvi==null) return null; |
| |
| // TODO: make sure if this is correct. |
| // TODO: since the number of types in a schema is quite limited, |
| // TypeInfoImpl should be pooled. Even better, it should be a part |
| // of the element decl. |
| if( psvi.getValidity()== ElementPSVI.VALIDITY_VALID ) { |
| XSTypeDefinition t = psvi.getMemberTypeDefinition(); |
| if (t != null) { |
| return (t instanceof TypeInfo) ? (TypeInfo) t : null; |
| } |
| } |
| |
| XSTypeDefinition t = psvi.getTypeDefinition(); |
| // TODO: can t be null? |
| if (t != null) { |
| return (t instanceof TypeInfo) ? (TypeInfo) t : null; |
| } |
| return null; |
| } |
| |
| public boolean isIdAttribute(int index) { |
| checkState(false); |
| XSSimpleType type = (XSSimpleType)getAttributeType(index); |
| if(type==null) return false; |
| return type.isIDType(); |
| } |
| |
| public boolean isSpecified(int index) { |
| checkState(false); |
| return fAttributes.isSpecified(index); |
| } |
| |
| /* |
| * Other methods |
| */ |
| |
| // PSVIProvider support |
| ElementPSVI getElementPSVI() { |
| return (fElementAugs != null) ? (ElementPSVI) fElementAugs.getItem(Constants.ELEMENT_PSVI) : null; |
| } |
| |
| AttributePSVI getAttributePSVI(int index) { |
| if (fAttributes != null) { |
| Augmentations augs = fAttributes.getAugmentations(index); |
| if (augs != null) { |
| return (AttributePSVI) augs.getItem(Constants.ATTRIBUTE_PSVI); |
| } |
| } |
| return null; |
| } |
| |
| AttributePSVI getAttributePSVIByName(String uri, String localname) { |
| if (fAttributes != null) { |
| Augmentations augs = fAttributes.getAugmentations(uri, localname); |
| if (augs != null) { |
| return (AttributePSVI) augs.getItem(Constants.ATTRIBUTE_PSVI); |
| } |
| } |
| return null; |
| } |
| } |
| |
| /** SAX adapter for an LSResourceResolver. */ |
| private final ResolutionForwarder fResolutionForwarder = new ResolutionForwarder(null); |
| static final class ResolutionForwarder |
| implements EntityResolver2 { |
| |
| // |
| // Data |
| // |
| |
| /** XML 1.0 type constant according to DOM L3 LS REC spec "http://www.w3.org/TR/2004/REC-DOM-Level-3-LS-20040407/" */ |
| private static final String XML_TYPE = "http://www.w3.org/TR/REC-xml"; |
| |
| /** The DOM entity resolver. */ |
| protected LSResourceResolver fEntityResolver; |
| |
| // |
| // Constructors |
| // |
| |
| /** Default constructor. */ |
| public ResolutionForwarder() {} |
| |
| /** Wraps the specified DOM entity resolver. */ |
| public ResolutionForwarder(LSResourceResolver entityResolver) { |
| setEntityResolver(entityResolver); |
| } |
| |
| // |
| // Public methods |
| // |
| |
| /** Sets the DOM entity resolver. */ |
| public void setEntityResolver(LSResourceResolver entityResolver) { |
| fEntityResolver = entityResolver; |
| } // setEntityResolver(LSResourceResolver) |
| |
| /** Returns the DOM entity resolver. */ |
| public LSResourceResolver getEntityResolver() { |
| return fEntityResolver; |
| } // getEntityResolver():LSResourceResolver |
| |
| /** |
| * Always returns <code>null</code>. An LSResourceResolver has no corresponding method. |
| */ |
| public InputSource getExternalSubset(String name, String baseURI) |
| throws SAXException, IOException { |
| return null; |
| } |
| |
| /** |
| * Resolves the given resource and adapts the <code>LSInput</code> |
| * returned into an <code>InputSource</code>. |
| */ |
| public InputSource resolveEntity(String name, String publicId, |
| String baseURI, String systemId) throws SAXException, IOException { |
| if (fEntityResolver != null) { |
| LSInput lsInput = fEntityResolver.resolveResource(XML_TYPE, null, publicId, systemId, baseURI); |
| if (lsInput != null) { |
| final String pubId = lsInput.getPublicId(); |
| final String sysId = lsInput.getSystemId(); |
| final String baseSystemId = lsInput.getBaseURI(); |
| final Reader charStream = lsInput.getCharacterStream(); |
| final InputStream byteStream = lsInput.getByteStream(); |
| final String data = lsInput.getStringData(); |
| final String encoding = lsInput.getEncoding(); |
| |
| /** |
| * An LSParser looks at inputs specified in LSInput in |
| * the following order: characterStream, byteStream, |
| * stringData, systemId, publicId. For consistency |
| * with the DOM Level 3 Load and Save Recommendation |
| * use the same lookup order here. |
| */ |
| InputSource inputSource = new InputSource(); |
| inputSource.setPublicId(pubId); |
| inputSource.setSystemId((baseSystemId != null) ? resolveSystemId(systemId, baseSystemId) : systemId); |
| |
| if (charStream != null) { |
| inputSource.setCharacterStream(charStream); |
| } |
| else if (byteStream != null) { |
| inputSource.setByteStream(byteStream); |
| } |
| else if (data != null && data.length() != 0) { |
| inputSource.setCharacterStream(new StringReader(data)); |
| } |
| inputSource.setEncoding(encoding); |
| return inputSource; |
| } |
| } |
| return null; |
| } |
| |
| /** Delegates to EntityResolver2.resolveEntity(String, String, String, String). */ |
| public InputSource resolveEntity(String publicId, String systemId) |
| throws SAXException, IOException { |
| return resolveEntity(null, publicId, null, systemId); |
| } |
| |
| /** Resolves a system identifier against a base URI. */ |
| private String resolveSystemId(String systemId, String baseURI) { |
| try { |
| return XMLEntityManager.expandSystemId(systemId, baseURI, false); |
| } |
| // In the event that resolution failed against the |
| // base URI, just return the system id as is. There's not |
| // much else we can do. |
| catch (URI.MalformedURIException ex) { |
| return systemId; |
| } |
| } |
| } |
| } |