~ubuntu-branches/ubuntu/karmic/libxerces2-java/karmic

« back to all changes in this revision

Viewing changes to src/org/apache/xerces/jaxp/validation/ValidatorHandlerImpl.java

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2006-12-04 17:37:55 UTC
  • mfrom: (2.1.2 etch)
  • Revision ID: james.westby@ubuntu.com-20061204173755-hb6ybrrrk097zhx7
Tags: 2.8.1-1ubuntu1
* Merge with Debian unstable; remaining changes:
  - Build -gcj package.

Show diffs side-by-side

added added

removed removed

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