001: /*
002: * Copyright 2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.xml.validation;
018:
019: import java.io.ByteArrayInputStream;
020: import java.io.ByteArrayOutputStream;
021: import java.io.IOException;
022: import java.util.ArrayList;
023: import java.util.List;
024: import javax.xml.parsers.ParserConfigurationException;
025: import javax.xml.parsers.SAXParser;
026: import javax.xml.parsers.SAXParserFactory;
027: import javax.xml.transform.Source;
028: import javax.xml.transform.Transformer;
029: import javax.xml.transform.TransformerException;
030: import javax.xml.transform.TransformerFactory;
031: import javax.xml.transform.dom.DOMSource;
032: import javax.xml.transform.sax.SAXSource;
033: import javax.xml.transform.stream.StreamResult;
034: import javax.xml.transform.stream.StreamSource;
035:
036: import org.springframework.core.io.Resource;
037: import org.xml.sax.InputSource;
038: import org.xml.sax.SAXException;
039: import org.xml.sax.SAXParseException;
040: import org.xml.sax.helpers.DefaultHandler;
041:
042: /**
043: * Internal class that uses JAXP 1.0 features to create <code>XmlValidator</code> instances.
044: *
045: * @author Arjen Poutsma
046: * @since 1.0.0
047: */
048: abstract class Jaxp10ValidatorFactory {
049:
050: private static final String SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
051:
052: private static final String SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource";
053:
054: static XmlValidator createValidator(Resource[] schemaResources,
055: String schemaLanguage) throws IOException {
056: InputSource[] inputSources = new InputSource[schemaResources.length];
057: for (int i = 0; i < schemaResources.length; i++) {
058: inputSources[i] = new InputSource(schemaResources[i]
059: .getInputStream());
060: inputSources[i].setSystemId(SchemaLoaderUtils
061: .getSystemId(schemaResources[i]));
062: }
063: return new Jaxp10Validator(inputSources, schemaLanguage);
064: }
065:
066: private static class Jaxp10Validator implements XmlValidator {
067:
068: private SAXParserFactory parserFactory;
069:
070: private TransformerFactory transformerFactory;
071:
072: private InputSource[] schemaInputSources;
073:
074: private String schemaLanguage;
075:
076: private Jaxp10Validator(InputSource[] schemaInputSources,
077: String schemaLanguage) {
078: this .schemaInputSources = schemaInputSources;
079: this .schemaLanguage = schemaLanguage;
080: transformerFactory = TransformerFactory.newInstance();
081: parserFactory = SAXParserFactory.newInstance();
082: parserFactory.setNamespaceAware(true);
083: parserFactory.setValidating(true);
084: }
085:
086: public SAXParseException[] validate(Source source)
087: throws IOException {
088: SAXParser parser = createSAXParser();
089: ValidationErrorHandler errorHandler = new ValidationErrorHandler();
090: try {
091: if (source instanceof SAXSource) {
092: validateSAXSource((SAXSource) source, parser,
093: errorHandler);
094: } else if (source instanceof StreamSource) {
095: validateStreamSource((StreamSource) source, parser,
096: errorHandler);
097: } else if (source instanceof DOMSource) {
098: validateDOMSource((DOMSource) source, parser,
099: errorHandler);
100: } else {
101: throw new IllegalArgumentException(
102: "Source ["
103: + source.getClass().getName()
104: + "] is neither SAXSource, DOMSource, nor StreamSource");
105: }
106: return errorHandler.getErrors();
107: } catch (SAXException ex) {
108: throw new XmlValidationException(
109: "Could not validate source: " + ex.getMessage(),
110: ex);
111: }
112: }
113:
114: private void validateDOMSource(DOMSource domSource,
115: SAXParser parser, ValidationErrorHandler errorHandler)
116: throws IOException, SAXException {
117: try {
118: // Sadly, JAXP 1.0 DOM doesn't implement DOM level 3, so we cannot use Document.normalizeDocument()
119: // Instead, we write the Document to a Stream, and validate that
120: Transformer transformer = transformerFactory
121: .newTransformer();
122: ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
123: transformer.transform(domSource, new StreamResult(
124: outputStream));
125: ByteArrayInputStream inputStream = new ByteArrayInputStream(
126: outputStream.toByteArray());
127: validateStreamSource(new StreamSource(inputStream),
128: parser, errorHandler);
129: } catch (TransformerException ex) {
130: throw new XmlValidationException(
131: "Could not validate DOM source: "
132: + ex.getMessage(), ex);
133: }
134:
135: }
136:
137: private void validateStreamSource(StreamSource streamSource,
138: SAXParser parser, ValidationErrorHandler errorHandler)
139: throws SAXException, IOException {
140: if (streamSource.getInputStream() != null) {
141: parser.parse(streamSource.getInputStream(),
142: errorHandler);
143: } else if (streamSource.getReader() != null) {
144: parser.parse(new InputSource(streamSource.getReader()),
145: errorHandler);
146: } else {
147: throw new IllegalArgumentException(
148: "StreamSource contains neither InputStream nor Reader");
149: }
150: }
151:
152: private void validateSAXSource(SAXSource source,
153: SAXParser parser, ValidationErrorHandler errorHandler)
154: throws SAXException, IOException {
155: parser.parse(source.getInputSource(), errorHandler);
156: }
157:
158: private SAXParser createSAXParser() {
159: try {
160: SAXParser parser = parserFactory.newSAXParser();
161: parser.setProperty(SCHEMA_LANGUAGE, schemaLanguage);
162: parser.setProperty(SCHEMA_SOURCE, schemaInputSources);
163: return parser;
164: } catch (ParserConfigurationException ex) {
165: throw new XmlValidationException(
166: "Could not create SAXParser: "
167: + ex.getMessage(), ex);
168: } catch (SAXException ex) {
169: throw new XmlValidationException(
170: "Could not create SAXParser: "
171: + ex.getMessage(), ex);
172: }
173: }
174: }
175:
176: /** <code>DefaultHandler</code> extension that stores errors and fatal errors in a list. */
177: private static class ValidationErrorHandler extends DefaultHandler {
178:
179: private List errors = new ArrayList();
180:
181: private SAXParseException[] getErrors() {
182: return (SAXParseException[]) errors
183: .toArray(new SAXParseException[errors.size()]);
184: }
185:
186: public void warning(SAXParseException ex) throws SAXException {
187: }
188:
189: public void error(SAXParseException ex) throws SAXException {
190: errors.add(ex);
191: }
192:
193: public void fatalError(SAXParseException ex)
194: throws SAXException {
195: errors.add(ex);
196: }
197: }
198: }
|