View Javadoc

1   /*
2    * Copyright 2005-2011 the original author or authors.
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.springframework.xml.validation;
18  
19  import java.io.ByteArrayInputStream;
20  import java.io.ByteArrayOutputStream;
21  import java.io.IOException;
22  import java.util.ArrayList;
23  import java.util.List;
24  import javax.xml.parsers.ParserConfigurationException;
25  import javax.xml.parsers.SAXParser;
26  import javax.xml.parsers.SAXParserFactory;
27  import javax.xml.transform.Source;
28  import javax.xml.transform.Transformer;
29  import javax.xml.transform.TransformerException;
30  import javax.xml.transform.TransformerFactory;
31  import javax.xml.transform.dom.DOMSource;
32  import javax.xml.transform.sax.SAXSource;
33  import javax.xml.transform.stream.StreamResult;
34  import javax.xml.transform.stream.StreamSource;
35  
36  import org.springframework.core.io.Resource;
37  import org.springframework.xml.sax.SaxUtils;
38  
39  import org.xml.sax.InputSource;
40  import org.xml.sax.SAXException;
41  import org.xml.sax.SAXParseException;
42  import org.xml.sax.helpers.DefaultHandler;
43  
44  /**
45   * Internal class that uses JAXP 1.0 features to create <code>XmlValidator</code> instances.
46   *
47   * @author Arjen Poutsma
48   * @since 1.0.0
49   * @deprecated  in favor of {@link Jaxp13ValidatorFactory}
50   */
51  @Deprecated
52  abstract class Jaxp10ValidatorFactory {
53  
54      private static final String SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
55  
56      private static final String SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource";
57  
58      static XmlValidator createValidator(Resource[] schemaResources, String schemaLanguage) throws IOException {
59          InputSource[] inputSources = new InputSource[schemaResources.length];
60          for (int i = 0; i < schemaResources.length; i++) {
61              inputSources[i] = SaxUtils.createInputSource(schemaResources[i]);
62          }
63          return new Jaxp10Validator(inputSources, schemaLanguage);
64      }
65  
66      private static class Jaxp10Validator implements XmlValidator {
67  
68          private SAXParserFactory parserFactory;
69  
70          private TransformerFactory transformerFactory;
71  
72          private InputSource[] schemaInputSources;
73  
74          private String schemaLanguage;
75  
76          private Jaxp10Validator(InputSource[] schemaInputSources, String schemaLanguage) {
77              this.schemaInputSources = schemaInputSources;
78              this.schemaLanguage = schemaLanguage;
79              transformerFactory = TransformerFactory.newInstance();
80              parserFactory = SAXParserFactory.newInstance();
81              parserFactory.setNamespaceAware(true);
82              parserFactory.setValidating(true);
83          }
84  
85          public SAXParseException[] validate(Source source, ValidationErrorHandler errorHandler)
86                  throws IOException {
87              return validate(source);
88          }
89  
90          public SAXParseException[] validate(Source source) throws IOException {
91              SAXParser parser = createSAXParser();
92              DefaultValidationErrorHandler errorHandler = new DefaultValidationErrorHandler();
93              try {
94                  if (source instanceof SAXSource) {
95                      validateSAXSource((SAXSource) source, parser, errorHandler);
96                  }
97                  else if (source instanceof StreamSource) {
98                      validateStreamSource((StreamSource) source, parser, errorHandler);
99                  }
100                 else if (source instanceof DOMSource) {
101                     validateDOMSource((DOMSource) source, parser, errorHandler);
102                 }
103                 else {
104                     throw new IllegalArgumentException("Source [" + source.getClass().getName() +
105                             "] is neither SAXSource, DOMSource, nor StreamSource");
106                 }
107                 return errorHandler.getErrors();
108             }
109             catch (SAXException ex) {
110                 throw new XmlValidationException("Could not validate source: " + ex.getMessage(), ex);
111             }
112         }
113 
114         private void validateDOMSource(DOMSource domSource, SAXParser parser, DefaultValidationErrorHandler errorHandler)
115                 throws IOException, SAXException {
116             try {
117                 // Sadly, JAXP 1.0 DOM doesn't implement DOM level 3, so we cannot use Document.normalizeDocument()
118                 // Instead, we write the Document to a Stream, and validate that
119                 Transformer transformer = transformerFactory.newTransformer();
120                 ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
121                 transformer.transform(domSource, new StreamResult(outputStream));
122                 ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
123                 validateStreamSource(new StreamSource(inputStream), parser, errorHandler);
124             }
125             catch (TransformerException ex) {
126                 throw new XmlValidationException("Could not validate DOM source: " + ex.getMessage(), ex);
127             }
128 
129         }
130 
131         private void validateStreamSource(StreamSource streamSource,
132                                           SAXParser parser,
133                                           DefaultValidationErrorHandler errorHandler) throws SAXException, IOException {
134             if (streamSource.getInputStream() != null) {
135                 parser.parse(streamSource.getInputStream(), errorHandler);
136             }
137             else if (streamSource.getReader() != null) {
138                 parser.parse(new InputSource(streamSource.getReader()), errorHandler);
139             }
140             else {
141                 throw new IllegalArgumentException("StreamSource contains neither InputStream nor Reader");
142             }
143         }
144 
145         private void validateSAXSource(SAXSource source, SAXParser parser, DefaultValidationErrorHandler errorHandler)
146                 throws SAXException, IOException {
147             parser.parse(source.getInputSource(), errorHandler);
148         }
149 
150         private SAXParser createSAXParser() {
151             try {
152                 SAXParser parser = parserFactory.newSAXParser();
153                 parser.setProperty(SCHEMA_LANGUAGE, schemaLanguage);
154                 parser.setProperty(SCHEMA_SOURCE, schemaInputSources);
155                 return parser;
156             }
157             catch (ParserConfigurationException ex) {
158                 throw new XmlValidationException("Could not create SAXParser: " + ex.getMessage(), ex);
159             }
160             catch (SAXException ex) {
161                 throw new XmlValidationException("Could not create SAXParser: " + ex.getMessage(), ex);
162             }
163         }
164     }
165 
166     /** <code>DefaultHandler</code> extension that stores errors and fatal errors in a list. */
167     private static class DefaultValidationErrorHandler extends DefaultHandler {
168 
169         private List<SAXParseException> errors = new ArrayList<SAXParseException>();
170 
171         private SAXParseException[] getErrors() {
172             return errors.toArray(new SAXParseException[errors.size()]);
173         }
174 
175         @Override
176         public void warning(SAXParseException ex) throws SAXException {
177         }
178 
179         @Override
180         public void error(SAXParseException ex) throws SAXException {
181             errors.add(ex);
182         }
183 
184         @Override
185         public void fatalError(SAXParseException ex) throws SAXException {
186             errors.add(ex);
187         }
188     }
189 }