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