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