0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017:
0018: package org.apache.xerces.jaxp.validation;
0019:
0020: import java.io.IOException;
0021: import java.io.InputStream;
0022: import java.io.Reader;
0023: import java.io.StringReader;
0024: import java.util.HashMap;
0025: import java.util.Locale;
0026:
0027: import javax.xml.parsers.FactoryConfigurationError;
0028: import javax.xml.parsers.SAXParserFactory;
0029: import javax.xml.transform.Result;
0030: import javax.xml.transform.Source;
0031: import javax.xml.transform.sax.SAXResult;
0032: import javax.xml.transform.sax.SAXSource;
0033: import javax.xml.validation.TypeInfoProvider;
0034: import javax.xml.validation.ValidatorHandler;
0035:
0036: import org.apache.xerces.impl.Constants;
0037: import org.apache.xerces.impl.XMLEntityManager;
0038: import org.apache.xerces.impl.XMLErrorReporter;
0039: import org.apache.xerces.impl.dv.XSSimpleType;
0040: import org.apache.xerces.impl.validation.EntityState;
0041: import org.apache.xerces.impl.validation.ValidationManager;
0042: import org.apache.xerces.impl.xs.XMLSchemaValidator;
0043: import org.apache.xerces.util.AttributesProxy;
0044: import org.apache.xerces.util.SAXLocatorWrapper;
0045: import org.apache.xerces.util.SAXMessageFormatter;
0046: import org.apache.xerces.util.SymbolTable;
0047: import org.apache.xerces.util.URI;
0048: import org.apache.xerces.util.XMLAttributesImpl;
0049: import org.apache.xerces.util.XMLSymbols;
0050: import org.apache.xerces.xni.Augmentations;
0051: import org.apache.xerces.xni.NamespaceContext;
0052: import org.apache.xerces.xni.QName;
0053: import org.apache.xerces.xni.XMLAttributes;
0054: import org.apache.xerces.xni.XMLDocumentHandler;
0055: import org.apache.xerces.xni.XMLLocator;
0056: import org.apache.xerces.xni.XMLResourceIdentifier;
0057: import org.apache.xerces.xni.XMLString;
0058: import org.apache.xerces.xni.XNIException;
0059: import org.apache.xerces.xni.parser.XMLConfigurationException;
0060: import org.apache.xerces.xni.parser.XMLDocumentSource;
0061: import org.apache.xerces.xni.parser.XMLParseException;
0062: import org.apache.xerces.xs.AttributePSVI;
0063: import org.apache.xerces.xs.ElementPSVI;
0064: import org.apache.xerces.xs.ItemPSVI;
0065: import org.apache.xerces.xs.PSVIProvider;
0066: import org.apache.xerces.xs.XSTypeDefinition;
0067: import org.w3c.dom.TypeInfo;
0068: import org.w3c.dom.ls.LSInput;
0069: import org.w3c.dom.ls.LSResourceResolver;
0070: import org.xml.sax.Attributes;
0071: import org.xml.sax.ContentHandler;
0072: import org.xml.sax.DTDHandler;
0073: import org.xml.sax.ErrorHandler;
0074: import org.xml.sax.InputSource;
0075: import org.xml.sax.Locator;
0076: import org.xml.sax.SAXException;
0077: import org.xml.sax.SAXNotRecognizedException;
0078: import org.xml.sax.SAXNotSupportedException;
0079: import org.xml.sax.XMLReader;
0080: import org.xml.sax.ext.Attributes2;
0081: import org.xml.sax.ext.EntityResolver2;
0082: import org.xml.sax.ext.LexicalHandler;
0083:
0084: /**
0085: * <p>Implementation of ValidatorHandler for W3C XML Schemas and
0086: * also a validator helper for <code>SAXSource</code>s.</p>
0087: *
0088: * @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
0089: * @author Michael Glavassevich, IBM
0090: *
0091: * @version $Id: ValidatorHandlerImpl.java 542519 2007-05-29 13:54:42Z mrglavas $
0092: */
0093: final class ValidatorHandlerImpl extends ValidatorHandler implements
0094: DTDHandler, EntityState, PSVIProvider, ValidatorHelper,
0095: XMLDocumentHandler {
0096:
0097: // feature identifiers
0098:
0099: /** Feature identifier: namespace prefixes. */
0100: private static final String NAMESPACE_PREFIXES = Constants.SAX_FEATURE_PREFIX
0101: + Constants.NAMESPACE_PREFIXES_FEATURE;
0102:
0103: /** Feature identifier: string interning. */
0104: protected static final String STRING_INTERNING = Constants.SAX_FEATURE_PREFIX
0105: + Constants.STRING_INTERNING_FEATURE;
0106:
0107: // property identifiers
0108:
0109: /** Property identifier: error reporter. */
0110: private static final String ERROR_REPORTER = Constants.XERCES_PROPERTY_PREFIX
0111: + Constants.ERROR_REPORTER_PROPERTY;
0112:
0113: /** Property identifier: lexical handler. */
0114: private static final String LEXICAL_HANDLER = Constants.SAX_PROPERTY_PREFIX
0115: + Constants.LEXICAL_HANDLER_PROPERTY;
0116:
0117: /** Property identifier: namespace context. */
0118: private static final String NAMESPACE_CONTEXT = Constants.XERCES_PROPERTY_PREFIX
0119: + Constants.NAMESPACE_CONTEXT_PROPERTY;
0120:
0121: /** Property identifier: XML Schema validator. */
0122: private static final String SCHEMA_VALIDATOR = Constants.XERCES_PROPERTY_PREFIX
0123: + Constants.SCHEMA_VALIDATOR_PROPERTY;
0124:
0125: /** Property identifier: security manager. */
0126: private static final String SECURITY_MANAGER = Constants.XERCES_PROPERTY_PREFIX
0127: + Constants.SECURITY_MANAGER_PROPERTY;
0128:
0129: /** Property identifier: symbol table. */
0130: private static final String SYMBOL_TABLE = Constants.XERCES_PROPERTY_PREFIX
0131: + Constants.SYMBOL_TABLE_PROPERTY;
0132:
0133: /** Property identifier: validation manager. */
0134: private static final String VALIDATION_MANAGER = Constants.XERCES_PROPERTY_PREFIX
0135: + Constants.VALIDATION_MANAGER_PROPERTY;
0136:
0137: //
0138: // Data
0139: //
0140:
0141: /** Error reporter. */
0142: private final XMLErrorReporter fErrorReporter;
0143:
0144: /** The namespace context of this document: stores namespaces in scope */
0145: private final NamespaceContext fNamespaceContext;
0146:
0147: /** Schema validator. **/
0148: private final XMLSchemaValidator fSchemaValidator;
0149:
0150: /** Symbol table **/
0151: private final SymbolTable fSymbolTable;
0152:
0153: /** Validation manager. */
0154: private final ValidationManager fValidationManager;
0155:
0156: /** Component manager. **/
0157: private final XMLSchemaValidatorComponentManager fComponentManager;
0158:
0159: /** XML Locator wrapper for SAX. **/
0160: private final SAXLocatorWrapper fSAXLocatorWrapper = new SAXLocatorWrapper();
0161:
0162: /** Flag used to track whether the namespace context needs to be pushed. */
0163: private boolean fNeedPushNSContext = true;
0164:
0165: /** Map for tracking unparsed entities. */
0166: private HashMap fUnparsedEntities = null;
0167:
0168: /** Flag used to track whether XML names and Namespace URIs have been internalized. */
0169: private boolean fStringsInternalized = false;
0170:
0171: /** Fields for start element, end element and characters. */
0172: private final QName fElementQName = new QName();
0173: private final QName fAttributeQName = new QName();
0174: private final XMLAttributesImpl fAttributes = new XMLAttributesImpl();
0175: private final AttributesProxy fAttrAdapter = new AttributesProxy(
0176: fAttributes);
0177: private final XMLString fTempString = new XMLString();
0178:
0179: //
0180: // User Objects
0181: //
0182:
0183: private ContentHandler fContentHandler = null;
0184:
0185: /*
0186: * Constructors
0187: */
0188:
0189: public ValidatorHandlerImpl(XSGrammarPoolContainer grammarContainer) {
0190: this (new XMLSchemaValidatorComponentManager(grammarContainer));
0191: fComponentManager
0192: .addRecognizedFeatures(new String[] { NAMESPACE_PREFIXES });
0193: fComponentManager.setFeature(NAMESPACE_PREFIXES, false);
0194: setErrorHandler(null);
0195: setResourceResolver(null);
0196: }
0197:
0198: public ValidatorHandlerImpl(
0199: XMLSchemaValidatorComponentManager componentManager) {
0200: fComponentManager = componentManager;
0201: fErrorReporter = (XMLErrorReporter) fComponentManager
0202: .getProperty(ERROR_REPORTER);
0203: fNamespaceContext = (NamespaceContext) fComponentManager
0204: .getProperty(NAMESPACE_CONTEXT);
0205: fSchemaValidator = (XMLSchemaValidator) fComponentManager
0206: .getProperty(SCHEMA_VALIDATOR);
0207: fSymbolTable = (SymbolTable) fComponentManager
0208: .getProperty(SYMBOL_TABLE);
0209: fValidationManager = (ValidationManager) fComponentManager
0210: .getProperty(VALIDATION_MANAGER);
0211: }
0212:
0213: /*
0214: * ValidatorHandler methods
0215: */
0216:
0217: public void setContentHandler(ContentHandler receiver) {
0218: fContentHandler = receiver;
0219: }
0220:
0221: public ContentHandler getContentHandler() {
0222: return fContentHandler;
0223: }
0224:
0225: public void setErrorHandler(ErrorHandler errorHandler) {
0226: fComponentManager.setErrorHandler(errorHandler);
0227: }
0228:
0229: public ErrorHandler getErrorHandler() {
0230: return fComponentManager.getErrorHandler();
0231: }
0232:
0233: public void setResourceResolver(LSResourceResolver resourceResolver) {
0234: fComponentManager.setResourceResolver(resourceResolver);
0235: }
0236:
0237: public LSResourceResolver getResourceResolver() {
0238: return fComponentManager.getResourceResolver();
0239: }
0240:
0241: public TypeInfoProvider getTypeInfoProvider() {
0242: return fTypeInfoProvider;
0243: }
0244:
0245: public boolean getFeature(String name)
0246: throws SAXNotRecognizedException, SAXNotSupportedException {
0247: if (name == null) {
0248: throw new NullPointerException();
0249: }
0250: try {
0251: return fComponentManager.getFeature(name);
0252: } catch (XMLConfigurationException e) {
0253: final String identifier = e.getIdentifier();
0254: final String key = e.getType() == XMLConfigurationException.NOT_RECOGNIZED ? "feature-not-recognized"
0255: : "feature-not-supported";
0256: throw new SAXNotRecognizedException(SAXMessageFormatter
0257: .formatMessage(Locale.getDefault(), key,
0258: new Object[] { identifier }));
0259: }
0260: }
0261:
0262: public void setFeature(String name, boolean value)
0263: throws SAXNotRecognizedException, SAXNotSupportedException {
0264: if (name == null) {
0265: throw new NullPointerException();
0266: }
0267: try {
0268: fComponentManager.setFeature(name, value);
0269: } catch (XMLConfigurationException e) {
0270: final String identifier = e.getIdentifier();
0271: final String key = e.getType() == XMLConfigurationException.NOT_RECOGNIZED ? "feature-not-recognized"
0272: : "feature-not-supported";
0273: throw new SAXNotRecognizedException(SAXMessageFormatter
0274: .formatMessage(Locale.getDefault(), key,
0275: new Object[] { identifier }));
0276: }
0277: }
0278:
0279: public Object getProperty(String name)
0280: throws SAXNotRecognizedException, SAXNotSupportedException {
0281: if (name == null) {
0282: throw new NullPointerException();
0283: }
0284: try {
0285: return fComponentManager.getProperty(name);
0286: } catch (XMLConfigurationException e) {
0287: final String identifier = e.getIdentifier();
0288: final String key = e.getType() == XMLConfigurationException.NOT_RECOGNIZED ? "property-not-recognized"
0289: : "property-not-supported";
0290: throw new SAXNotRecognizedException(SAXMessageFormatter
0291: .formatMessage(Locale.getDefault(), key,
0292: new Object[] { identifier }));
0293: }
0294: }
0295:
0296: public void setProperty(String name, Object object)
0297: throws SAXNotRecognizedException, SAXNotSupportedException {
0298: if (name == null) {
0299: throw new NullPointerException();
0300: }
0301: try {
0302: fComponentManager.setProperty(name, object);
0303: } catch (XMLConfigurationException e) {
0304: final String identifier = e.getIdentifier();
0305: final String key = e.getType() == XMLConfigurationException.NOT_RECOGNIZED ? "property-not-recognized"
0306: : "property-not-supported";
0307: throw new SAXNotRecognizedException(SAXMessageFormatter
0308: .formatMessage(Locale.getDefault(), key,
0309: new Object[] { identifier }));
0310: }
0311: }
0312:
0313: /*
0314: * EntityState methods
0315: */
0316:
0317: public boolean isEntityDeclared(String name) {
0318: return false;
0319: }
0320:
0321: public boolean isEntityUnparsed(String name) {
0322: if (fUnparsedEntities != null) {
0323: return fUnparsedEntities.containsKey(name);
0324: }
0325: return false;
0326: }
0327:
0328: /*
0329: * XMLDocumentHandler methods
0330: */
0331:
0332: public void startDocument(XMLLocator locator, String encoding,
0333: NamespaceContext namespaceContext, Augmentations augs)
0334: throws XNIException {
0335: if (fContentHandler != null) {
0336: try {
0337: fContentHandler.startDocument();
0338: } catch (SAXException e) {
0339: throw new XNIException(e);
0340: }
0341: }
0342: }
0343:
0344: public void xmlDecl(String version, String encoding,
0345: String standalone, Augmentations augs) throws XNIException {
0346: }
0347:
0348: public void doctypeDecl(String rootElement, String publicId,
0349: String systemId, Augmentations augs) throws XNIException {
0350: }
0351:
0352: public void comment(XMLString text, Augmentations augs)
0353: throws XNIException {
0354: }
0355:
0356: public void processingInstruction(String target, XMLString data,
0357: Augmentations augs) throws XNIException {
0358: if (fContentHandler != null) {
0359: try {
0360: fContentHandler.processingInstruction(target, data
0361: .toString());
0362: } catch (SAXException e) {
0363: throw new XNIException(e);
0364: }
0365: }
0366: }
0367:
0368: public void startElement(QName element, XMLAttributes attributes,
0369: Augmentations augs) throws XNIException {
0370: if (fContentHandler != null) {
0371: try {
0372: fTypeInfoProvider.beginStartElement(augs, attributes);
0373: fContentHandler.startElement(
0374: (element.uri != null) ? element.uri
0375: : XMLSymbols.EMPTY_STRING,
0376: element.localpart, element.rawname,
0377: fAttrAdapter);
0378: } catch (SAXException e) {
0379: throw new XNIException(e);
0380: } finally {
0381: fTypeInfoProvider.finishStartElement();
0382: }
0383: }
0384: }
0385:
0386: public void emptyElement(QName element, XMLAttributes attributes,
0387: Augmentations augs) throws XNIException {
0388: /** Split empty element event. **/
0389: startElement(element, attributes, augs);
0390: endElement(element, augs);
0391: }
0392:
0393: public void startGeneralEntity(String name,
0394: XMLResourceIdentifier identifier, String encoding,
0395: Augmentations augs) throws XNIException {
0396: }
0397:
0398: public void textDecl(String version, String encoding,
0399: Augmentations augs) throws XNIException {
0400: }
0401:
0402: public void endGeneralEntity(String name, Augmentations augs)
0403: throws XNIException {
0404: }
0405:
0406: public void characters(XMLString text, Augmentations augs)
0407: throws XNIException {
0408: if (fContentHandler != null) {
0409: // if the type is union it is possible that we receive
0410: // a character call with empty data
0411: if (text.length == 0) {
0412: return;
0413: }
0414: try {
0415: fContentHandler.characters(text.ch, text.offset,
0416: text.length);
0417: } catch (SAXException e) {
0418: throw new XNIException(e);
0419: }
0420: }
0421: }
0422:
0423: public void ignorableWhitespace(XMLString text, Augmentations augs)
0424: throws XNIException {
0425: if (fContentHandler != null) {
0426: try {
0427: fContentHandler.ignorableWhitespace(text.ch,
0428: text.offset, text.length);
0429: } catch (SAXException e) {
0430: throw new XNIException(e);
0431: }
0432: }
0433: }
0434:
0435: public void endElement(QName element, Augmentations augs)
0436: throws XNIException {
0437: if (fContentHandler != null) {
0438: try {
0439: fTypeInfoProvider.beginEndElement(augs);
0440: fContentHandler.endElement(
0441: (element.uri != null) ? element.uri
0442: : XMLSymbols.EMPTY_STRING,
0443: element.localpart, element.rawname);
0444: } catch (SAXException e) {
0445: throw new XNIException(e);
0446: } finally {
0447: fTypeInfoProvider.finishEndElement();
0448: }
0449: }
0450: }
0451:
0452: public void startCDATA(Augmentations augs) throws XNIException {
0453: }
0454:
0455: public void endCDATA(Augmentations augs) throws XNIException {
0456: }
0457:
0458: public void endDocument(Augmentations augs) throws XNIException {
0459: if (fContentHandler != null) {
0460: try {
0461: fContentHandler.endDocument();
0462: } catch (SAXException e) {
0463: throw new XNIException(e);
0464: }
0465: }
0466: }
0467:
0468: // NO-OP
0469: public void setDocumentSource(XMLDocumentSource source) {
0470: }
0471:
0472: public XMLDocumentSource getDocumentSource() {
0473: return fSchemaValidator;
0474: }
0475:
0476: /*
0477: * ContentHandler methods
0478: */
0479:
0480: public void setDocumentLocator(Locator locator) {
0481: fSAXLocatorWrapper.setLocator(locator);
0482: if (fContentHandler != null) {
0483: fContentHandler.setDocumentLocator(locator);
0484: }
0485: }
0486:
0487: public void startDocument() throws SAXException {
0488: fComponentManager.reset();
0489: fSchemaValidator.setDocumentHandler(this );
0490: fValidationManager.setEntityState(this );
0491: fTypeInfoProvider.finishStartElement(); // cleans up TypeInfoProvider
0492: fNeedPushNSContext = true;
0493: if (fUnparsedEntities != null && !fUnparsedEntities.isEmpty()) {
0494: // should only clear this if the last document contained unparsed entities
0495: fUnparsedEntities.clear();
0496: }
0497: fErrorReporter.setDocumentLocator(fSAXLocatorWrapper);
0498: try {
0499: fSchemaValidator.startDocument(fSAXLocatorWrapper,
0500: fSAXLocatorWrapper.getEncoding(),
0501: fNamespaceContext, null);
0502: } catch (XMLParseException e) {
0503: throw Util.toSAXParseException(e);
0504: } catch (XNIException e) {
0505: throw Util.toSAXException(e);
0506: }
0507: }
0508:
0509: public void endDocument() throws SAXException {
0510: fSAXLocatorWrapper.setLocator(null);
0511: try {
0512: fSchemaValidator.endDocument(null);
0513: } catch (XMLParseException e) {
0514: throw Util.toSAXParseException(e);
0515: } catch (XNIException e) {
0516: throw Util.toSAXException(e);
0517: }
0518: }
0519:
0520: public void startPrefixMapping(String prefix, String uri)
0521: throws SAXException {
0522: String prefixSymbol;
0523: String uriSymbol;
0524: if (!fStringsInternalized) {
0525: prefixSymbol = (prefix != null) ? fSymbolTable
0526: .addSymbol(prefix) : XMLSymbols.EMPTY_STRING;
0527: uriSymbol = (uri != null && uri.length() > 0) ? fSymbolTable
0528: .addSymbol(uri)
0529: : null;
0530: } else {
0531: prefixSymbol = (prefix != null) ? prefix
0532: : XMLSymbols.EMPTY_STRING;
0533: uriSymbol = (uri != null && uri.length() > 0) ? uri : null;
0534: }
0535: if (fNeedPushNSContext) {
0536: fNeedPushNSContext = false;
0537: fNamespaceContext.pushContext();
0538: }
0539: fNamespaceContext.declarePrefix(prefixSymbol, uriSymbol);
0540: if (fContentHandler != null) {
0541: fContentHandler.startPrefixMapping(prefix, uri);
0542: }
0543: }
0544:
0545: public void endPrefixMapping(String prefix) throws SAXException {
0546: if (fContentHandler != null) {
0547: fContentHandler.endPrefixMapping(prefix);
0548: }
0549: }
0550:
0551: public void startElement(String uri, String localName,
0552: String qName, Attributes atts) throws SAXException {
0553: if (fNeedPushNSContext) {
0554: fNamespaceContext.pushContext();
0555: }
0556: fNeedPushNSContext = true;
0557:
0558: // Fill element QName
0559: fillQName(fElementQName, uri, localName, qName);
0560:
0561: // Fill XMLAttributes
0562: if (atts instanceof Attributes2) {
0563: fillXMLAttributes2((Attributes2) atts);
0564: } else {
0565: fillXMLAttributes(atts);
0566: }
0567:
0568: try {
0569: fSchemaValidator.startElement(fElementQName, fAttributes,
0570: null);
0571: } catch (XMLParseException e) {
0572: throw Util.toSAXParseException(e);
0573: } catch (XNIException e) {
0574: throw Util.toSAXException(e);
0575: }
0576: }
0577:
0578: public void endElement(String uri, String localName, String qName)
0579: throws SAXException {
0580: fillQName(fElementQName, uri, localName, qName);
0581: try {
0582: fSchemaValidator.endElement(fElementQName, null);
0583: } catch (XMLParseException e) {
0584: throw Util.toSAXParseException(e);
0585: } catch (XNIException e) {
0586: throw Util.toSAXException(e);
0587: } finally {
0588: fNamespaceContext.popContext();
0589: }
0590: }
0591:
0592: public void characters(char[] ch, int start, int length)
0593: throws SAXException {
0594: try {
0595: fTempString.setValues(ch, start, length);
0596: fSchemaValidator.characters(fTempString, null);
0597: } catch (XMLParseException e) {
0598: throw Util.toSAXParseException(e);
0599: } catch (XNIException e) {
0600: throw Util.toSAXException(e);
0601: }
0602: }
0603:
0604: public void ignorableWhitespace(char[] ch, int start, int length)
0605: throws SAXException {
0606: try {
0607: fTempString.setValues(ch, start, length);
0608: fSchemaValidator.ignorableWhitespace(fTempString, null);
0609: } catch (XMLParseException e) {
0610: throw Util.toSAXParseException(e);
0611: } catch (XNIException e) {
0612: throw Util.toSAXException(e);
0613: }
0614: }
0615:
0616: public void processingInstruction(String target, String data)
0617: throws SAXException {
0618: /**
0619: * Processing instructions do not participate in schema validation,
0620: * so just forward the event to the application's content
0621: * handler.
0622: */
0623: if (fContentHandler != null) {
0624: fContentHandler.processingInstruction(target, data);
0625: }
0626: }
0627:
0628: public void skippedEntity(String name) throws SAXException {
0629: // there seems to be no corresponding method on XMLDocumentFilter.
0630: // just pass it down to the output, if any.
0631: if (fContentHandler != null) {
0632: fContentHandler.skippedEntity(name);
0633: }
0634: }
0635:
0636: /*
0637: * DTDHandler methods
0638: */
0639:
0640: public void notationDecl(String name, String publicId,
0641: String systemId) throws SAXException {
0642: }
0643:
0644: public void unparsedEntityDecl(String name, String publicId,
0645: String systemId, String notationName) throws SAXException {
0646: if (fUnparsedEntities == null) {
0647: fUnparsedEntities = new HashMap();
0648: }
0649: fUnparsedEntities.put(name, name);
0650: }
0651:
0652: /*
0653: * ValidatorHelper methods
0654: */
0655:
0656: public void validate(Source source, Result result)
0657: throws SAXException, IOException {
0658: if (result instanceof SAXResult || result == null) {
0659: final SAXSource saxSource = (SAXSource) source;
0660: final SAXResult saxResult = (SAXResult) result;
0661:
0662: LexicalHandler lh = null;
0663: if (result != null) {
0664: ContentHandler ch = saxResult.getHandler();
0665: lh = saxResult.getLexicalHandler();
0666: /** If the lexical handler is not set try casting the ContentHandler. **/
0667: if (lh == null && ch instanceof LexicalHandler) {
0668: lh = (LexicalHandler) ch;
0669: }
0670: setContentHandler(ch);
0671: }
0672:
0673: try {
0674: XMLReader reader = saxSource.getXMLReader();
0675: if (reader == null) {
0676: // create one now
0677: SAXParserFactory spf = SAXParserFactory
0678: .newInstance();
0679: spf.setNamespaceAware(true);
0680: try {
0681: reader = spf.newSAXParser().getXMLReader();
0682: // If this is a Xerces SAX parser, set the security manager if there is one
0683: if (reader instanceof org.apache.xerces.parsers.SAXParser) {
0684: SecurityManager securityManager = (SecurityManager) fComponentManager
0685: .getProperty(SECURITY_MANAGER);
0686: if (securityManager != null) {
0687: try {
0688: reader.setProperty(
0689: SECURITY_MANAGER,
0690: securityManager);
0691: }
0692: // Ignore the exception if the security manager cannot be set.
0693: catch (SAXException exc) {
0694: }
0695: }
0696: }
0697: } catch (Exception e) {
0698: // this is impossible, but better safe than sorry
0699: throw new FactoryConfigurationError(e);
0700: }
0701: }
0702:
0703: // If XML names and Namespace URIs are already internalized we
0704: // can avoid running them through the SymbolTable.
0705: try {
0706: fStringsInternalized = reader
0707: .getFeature(STRING_INTERNING);
0708: } catch (SAXException exc) {
0709: // The feature isn't recognized or getting it is not supported.
0710: // In either case, assume that strings are not internalized.
0711: fStringsInternalized = false;
0712: }
0713:
0714: ErrorHandler errorHandler = fComponentManager
0715: .getErrorHandler();
0716: reader
0717: .setErrorHandler(errorHandler != null ? errorHandler
0718: : DraconianErrorHandler.getInstance());
0719: reader.setEntityResolver(fResolutionForwarder);
0720: fResolutionForwarder
0721: .setEntityResolver(fComponentManager
0722: .getResourceResolver());
0723: reader.setContentHandler(this );
0724: reader.setDTDHandler(this );
0725: try {
0726: reader.setProperty(LEXICAL_HANDLER, lh);
0727: }
0728: // Ignore the exception if the lexical handler cannot be set.
0729: catch (SAXException exc) {
0730: }
0731:
0732: InputSource is = saxSource.getInputSource();
0733: reader.parse(is);
0734: } finally {
0735: // release the reference to user's handler ASAP
0736: setContentHandler(null);
0737: }
0738: return;
0739: }
0740: throw new IllegalArgumentException(
0741: JAXPValidationMessageFormatter.formatMessage(Locale
0742: .getDefault(), "SourceResultMismatch",
0743: new Object[] { source.getClass().getName(),
0744: result.getClass().getName() }));
0745: }
0746:
0747: /*
0748: * PSVIProvider methods
0749: */
0750:
0751: public ElementPSVI getElementPSVI() {
0752: return fTypeInfoProvider.getElementPSVI();
0753: }
0754:
0755: public AttributePSVI getAttributePSVI(int index) {
0756: return fTypeInfoProvider.getAttributePSVI(index);
0757: }
0758:
0759: public AttributePSVI getAttributePSVIByName(String uri,
0760: String localname) {
0761: return fTypeInfoProvider.getAttributePSVIByName(uri, localname);
0762: }
0763:
0764: //
0765: //
0766: // helper methods
0767: //
0768: //
0769:
0770: /** Fills in a QName object. */
0771: private void fillQName(QName toFill, String uri, String localpart,
0772: String raw) {
0773: if (!fStringsInternalized) {
0774: uri = (uri != null && uri.length() > 0) ? fSymbolTable
0775: .addSymbol(uri) : null;
0776: localpart = (localpart != null) ? fSymbolTable
0777: .addSymbol(localpart) : XMLSymbols.EMPTY_STRING;
0778: raw = (raw != null) ? fSymbolTable.addSymbol(raw)
0779: : XMLSymbols.EMPTY_STRING;
0780: } else {
0781: if (uri != null && uri.length() == 0) {
0782: uri = null;
0783: }
0784: if (localpart == null) {
0785: localpart = XMLSymbols.EMPTY_STRING;
0786: }
0787: if (raw == null) {
0788: raw = XMLSymbols.EMPTY_STRING;
0789: }
0790: }
0791: String prefix = XMLSymbols.EMPTY_STRING;
0792: int prefixIdx = raw.indexOf(':');
0793: if (prefixIdx != -1) {
0794: prefix = fSymbolTable
0795: .addSymbol(raw.substring(0, prefixIdx));
0796: }
0797: toFill.setValues(prefix, localpart, raw, uri);
0798: }
0799:
0800: /** Fills in the XMLAttributes object. */
0801: private void fillXMLAttributes(Attributes att) {
0802: fAttributes.removeAllAttributes();
0803: final int len = att.getLength();
0804: for (int i = 0; i < len; ++i) {
0805: fillXMLAttribute(att, i);
0806: fAttributes.setSpecified(i, true);
0807: }
0808: }
0809:
0810: /** Fills in the XMLAttributes object. */
0811: private void fillXMLAttributes2(Attributes2 att) {
0812: fAttributes.removeAllAttributes();
0813: final int len = att.getLength();
0814: for (int i = 0; i < len; ++i) {
0815: fillXMLAttribute(att, i);
0816: fAttributes.setSpecified(i, att.isSpecified(i));
0817: if (att.isDeclared(i)) {
0818: fAttributes.getAugmentations(i).putItem(
0819: Constants.ATTRIBUTE_DECLARED, Boolean.TRUE);
0820: }
0821: }
0822: }
0823:
0824: /** Adds an attribute to the XMLAttributes object. */
0825: private void fillXMLAttribute(Attributes att, int index) {
0826: fillQName(fAttributeQName, att.getURI(index), att
0827: .getLocalName(index), att.getQName(index));
0828: String type = att.getType(index);
0829: fAttributes.addAttributeNS(fAttributeQName,
0830: (type != null) ? type : XMLSymbols.fCDATASymbol, att
0831: .getValue(index));
0832: }
0833:
0834: /**
0835: * {@link TypeInfoProvider} implementation.
0836: *
0837: * REVISIT: I'm not sure if this code should belong here.
0838: */
0839: private final XMLSchemaTypeInfoProvider fTypeInfoProvider = new XMLSchemaTypeInfoProvider();
0840:
0841: private static class XMLSchemaTypeInfoProvider extends
0842: TypeInfoProvider {
0843:
0844: /** Element augmentations: contains ElementPSVI. **/
0845: private Augmentations fElementAugs;
0846:
0847: /** Attributes: augmentations for each attribute contain AttributePSVI. **/
0848: private XMLAttributes fAttributes;
0849:
0850: /** In start element. **/
0851: private boolean fInStartElement = false;
0852:
0853: /** Initializes the TypeInfoProvider with type information for the current element. **/
0854: void beginStartElement(Augmentations elementAugs,
0855: XMLAttributes attributes) {
0856: fInStartElement = true;
0857: fElementAugs = elementAugs;
0858: fAttributes = attributes;
0859: }
0860:
0861: /** Cleanup at the end of start element. **/
0862: void finishStartElement() {
0863: fInStartElement = false;
0864: fElementAugs = null;
0865: fAttributes = null;
0866: }
0867:
0868: /** Initializes the TypeInfoProvider with type information for the current element. **/
0869: void beginEndElement(Augmentations elementAugs) {
0870: fElementAugs = elementAugs;
0871: }
0872:
0873: /** Cleanup at the end of end element. **/
0874: void finishEndElement() {
0875: fElementAugs = null;
0876: }
0877:
0878: /**
0879: * Throws a {@link IllegalStateException} if we are not in
0880: * the startElement callback. the JAXP API requires this
0881: * for most of the public methods.
0882: */
0883: private void checkState() {
0884: if (!fInStartElement) {
0885: throw new IllegalStateException(
0886: JAXPValidationMessageFormatter.formatMessage(
0887: Locale.getDefault(),
0888: "TypeInfoProviderIllegalState", null));
0889: }
0890: }
0891:
0892: public TypeInfo getAttributeTypeInfo(int index) {
0893: checkState();
0894: return getAttributeType(index);
0895: }
0896:
0897: private TypeInfo getAttributeType(int index) {
0898: checkState();
0899: if (index < 0 || fAttributes.getLength() <= index)
0900: throw new IndexOutOfBoundsException(Integer
0901: .toString(index));
0902: Augmentations augs = fAttributes.getAugmentations(index);
0903: if (augs == null)
0904: return null;
0905: AttributePSVI psvi = (AttributePSVI) augs
0906: .getItem(Constants.ATTRIBUTE_PSVI);
0907: return getTypeInfoFromPSVI(psvi);
0908: }
0909:
0910: public TypeInfo getAttributeTypeInfo(String attributeUri,
0911: String attributeLocalName) {
0912: checkState();
0913: return getAttributeTypeInfo(fAttributes.getIndex(
0914: attributeUri, attributeLocalName));
0915: }
0916:
0917: public TypeInfo getAttributeTypeInfo(String attributeQName) {
0918: checkState();
0919: return getAttributeTypeInfo(fAttributes
0920: .getIndex(attributeQName));
0921: }
0922:
0923: public TypeInfo getElementTypeInfo() {
0924: checkState();
0925: if (fElementAugs == null)
0926: return null;
0927: ElementPSVI psvi = (ElementPSVI) fElementAugs
0928: .getItem(Constants.ELEMENT_PSVI);
0929: return getTypeInfoFromPSVI(psvi);
0930: }
0931:
0932: private TypeInfo getTypeInfoFromPSVI(ItemPSVI psvi) {
0933: if (psvi == null)
0934: return null;
0935:
0936: // TODO: make sure if this is correct.
0937: // TODO: since the number of types in a schema is quite limited,
0938: // TypeInfoImpl should be pooled. Even better, it should be a part
0939: // of the element decl.
0940: if (psvi.getValidity() == ElementPSVI.VALIDITY_VALID) {
0941: XSTypeDefinition t = psvi.getMemberTypeDefinition();
0942: if (t != null) {
0943: return (t instanceof TypeInfo) ? (TypeInfo) t
0944: : null;
0945: }
0946: }
0947:
0948: XSTypeDefinition t = psvi.getTypeDefinition();
0949: // TODO: can t be null?
0950: if (t != null) {
0951: return (t instanceof TypeInfo) ? (TypeInfo) t : null;
0952: }
0953: return null;
0954: }
0955:
0956: public boolean isIdAttribute(int index) {
0957: checkState();
0958: XSSimpleType type = (XSSimpleType) getAttributeType(index);
0959: if (type == null)
0960: return false;
0961: return type.isIDType();
0962: }
0963:
0964: public boolean isSpecified(int index) {
0965: checkState();
0966: return fAttributes.isSpecified(index);
0967: }
0968:
0969: /*
0970: * Other methods
0971: */
0972:
0973: // PSVIProvider support
0974: ElementPSVI getElementPSVI() {
0975: return (fElementAugs != null) ? (ElementPSVI) fElementAugs
0976: .getItem(Constants.ELEMENT_PSVI) : null;
0977: }
0978:
0979: AttributePSVI getAttributePSVI(int index) {
0980: if (fAttributes != null) {
0981: Augmentations augs = fAttributes
0982: .getAugmentations(index);
0983: if (augs != null) {
0984: return (AttributePSVI) augs
0985: .getItem(Constants.ATTRIBUTE_PSVI);
0986: }
0987: }
0988: return null;
0989: }
0990:
0991: AttributePSVI getAttributePSVIByName(String uri,
0992: String localname) {
0993: if (fAttributes != null) {
0994: Augmentations augs = fAttributes.getAugmentations(uri,
0995: localname);
0996: if (augs != null) {
0997: return (AttributePSVI) augs
0998: .getItem(Constants.ATTRIBUTE_PSVI);
0999: }
1000: }
1001: return null;
1002: }
1003: }
1004:
1005: /** SAX adapter for an LSResourceResolver. */
1006: private final ResolutionForwarder fResolutionForwarder = new ResolutionForwarder(
1007: null);
1008:
1009: static final class ResolutionForwarder implements EntityResolver2 {
1010:
1011: //
1012: // Data
1013: //
1014:
1015: /** XML 1.0 type constant according to DOM L3 LS REC spec "http://www.w3.org/TR/2004/REC-DOM-Level-3-LS-20040407/" */
1016: private static final String XML_TYPE = "http://www.w3.org/TR/REC-xml";
1017:
1018: /** The DOM entity resolver. */
1019: protected LSResourceResolver fEntityResolver;
1020:
1021: //
1022: // Constructors
1023: //
1024:
1025: /** Default constructor. */
1026: public ResolutionForwarder() {
1027: }
1028:
1029: /** Wraps the specified DOM entity resolver. */
1030: public ResolutionForwarder(LSResourceResolver entityResolver) {
1031: setEntityResolver(entityResolver);
1032: }
1033:
1034: //
1035: // Public methods
1036: //
1037:
1038: /** Sets the DOM entity resolver. */
1039: public void setEntityResolver(LSResourceResolver entityResolver) {
1040: fEntityResolver = entityResolver;
1041: } // setEntityResolver(LSResourceResolver)
1042:
1043: /** Returns the DOM entity resolver. */
1044: public LSResourceResolver getEntityResolver() {
1045: return fEntityResolver;
1046: } // getEntityResolver():LSResourceResolver
1047:
1048: /**
1049: * Always returns <code>null</code>. An LSResourceResolver has no corresponding method.
1050: */
1051: public InputSource getExternalSubset(String name, String baseURI)
1052: throws SAXException, IOException {
1053: return null;
1054: }
1055:
1056: /**
1057: * Resolves the given resource and adapts the <code>LSInput</code>
1058: * returned into an <code>InputSource</code>.
1059: */
1060: public InputSource resolveEntity(String name, String publicId,
1061: String baseURI, String systemId) throws SAXException,
1062: IOException {
1063: if (fEntityResolver != null) {
1064: LSInput lsInput = fEntityResolver.resolveResource(
1065: XML_TYPE, null, publicId, systemId, baseURI);
1066: if (lsInput != null) {
1067: final String pubId = lsInput.getPublicId();
1068: final String sysId = lsInput.getSystemId();
1069: final String baseSystemId = lsInput.getBaseURI();
1070: final Reader charStream = lsInput
1071: .getCharacterStream();
1072: final InputStream byteStream = lsInput
1073: .getByteStream();
1074: final String data = lsInput.getStringData();
1075: final String encoding = lsInput.getEncoding();
1076:
1077: /**
1078: * An LSParser looks at inputs specified in LSInput in
1079: * the following order: characterStream, byteStream,
1080: * stringData, systemId, publicId. For consistency
1081: * with the DOM Level 3 Load and Save Recommendation
1082: * use the same lookup order here.
1083: */
1084: InputSource inputSource = new InputSource();
1085: inputSource.setPublicId(pubId);
1086: inputSource
1087: .setSystemId((baseSystemId != null) ? resolveSystemId(
1088: sysId, baseSystemId)
1089: : sysId);
1090:
1091: if (charStream != null) {
1092: inputSource.setCharacterStream(charStream);
1093: } else if (byteStream != null) {
1094: inputSource.setByteStream(byteStream);
1095: } else if (data != null && data.length() != 0) {
1096: inputSource
1097: .setCharacterStream(new StringReader(
1098: data));
1099: }
1100: inputSource.setEncoding(encoding);
1101: return inputSource;
1102: }
1103: }
1104: return null;
1105: }
1106:
1107: /** Delegates to EntityResolver2.resolveEntity(String, String, String, String). */
1108: public InputSource resolveEntity(String publicId,
1109: String systemId) throws SAXException, IOException {
1110: return resolveEntity(null, publicId, null, systemId);
1111: }
1112:
1113: /** Resolves a system identifier against a base URI. */
1114: private String resolveSystemId(String systemId, String baseURI) {
1115: try {
1116: return XMLEntityManager.expandSystemId(systemId,
1117: baseURI, false);
1118: }
1119: // In the event that resolution failed against the
1120: // base URI, just return the system id as is. There's not
1121: // much else we can do.
1122: catch (URI.MalformedURIException ex) {
1123: return systemId;
1124: }
1125: }
1126: }
1127: }
|