View Javadoc

1   /*
2    * Copyright 2007 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.transform;
18  
19  import java.io.IOException;
20  import java.io.InputStream;
21  import java.io.OutputStream;
22  import java.io.Reader;
23  import java.io.Writer;
24  import javax.xml.stream.XMLEventReader;
25  import javax.xml.stream.XMLEventWriter;
26  import javax.xml.stream.XMLStreamException;
27  import javax.xml.stream.XMLStreamReader;
28  import javax.xml.stream.XMLStreamWriter;
29  import javax.xml.transform.Result;
30  import javax.xml.transform.Source;
31  import javax.xml.transform.dom.DOMResult;
32  import javax.xml.transform.dom.DOMSource;
33  import javax.xml.transform.sax.SAXResult;
34  import javax.xml.transform.sax.SAXSource;
35  import javax.xml.transform.stax.StAXResult;
36  import javax.xml.transform.stax.StAXSource;
37  import javax.xml.transform.stream.StreamResult;
38  import javax.xml.transform.stream.StreamSource;
39  
40  import org.w3c.dom.Document;
41  import org.w3c.dom.Node;
42  import org.xml.sax.ContentHandler;
43  import org.xml.sax.InputSource;
44  import org.xml.sax.SAXException;
45  import org.xml.sax.XMLReader;
46  import org.xml.sax.ext.LexicalHandler;
47  
48  import org.springframework.util.Assert;
49  import org.springframework.xml.JaxpVersion;
50  
51  /**
52   * Convenient utility methods for dealing with TrAX.
53   *
54   * @author Arjen Poutsma
55   * @since 1.5.0
56   */
57  public abstract class TraxUtils {
58  
59      /**
60       * Indicates whether the given {@link Source} is a StAX Source.
61       *
62       * @return <code>true</code> if <code>source</code> is a Spring-WS {@link StaxSource} or JAXP 1.4 {@link
63       *         StAXSource}; <code>false</code> otherwise.
64       */
65      public static boolean isStaxSource(Source source) {
66          if (source instanceof StaxSource) {
67              return true;
68          }
69          else if (JaxpVersion.isAtLeastJaxp14()) {
70              return Jaxp14StaxHandler.isStaxSource(source);
71          }
72          else {
73              return false;
74          }
75      }
76  
77      /**
78       * Indicates whether the given {@link Result} is a StAX Result.
79       *
80       * @return <code>true</code> if <code>result</code> is a Spring-WS {@link StaxResult} or JAXP 1.4 {@link
81       *         StAXResult}; <code>false</code> otherwise.
82       */
83      public static boolean isStaxResult(Result result) {
84          if (result instanceof StaxResult) {
85              return true;
86          }
87          else if (JaxpVersion.isAtLeastJaxp14()) {
88              return Jaxp14StaxHandler.isStaxResult(result);
89          }
90          else {
91              return false;
92          }
93      }
94  
95      /**
96       * Returns the {@link XMLStreamReader} for the given StAX Source.
97       *
98       * @param source a Spring-WS {@link StaxSource} or {@link StAXSource}
99       * @return the {@link XMLStreamReader}
100      * @throws IllegalArgumentException if <code>source</code> is neither a Spring-WS {@link StaxSource} or {@link
101      *                                  StAXSource}
102      */
103     public static XMLStreamReader getXMLStreamReader(Source source) {
104         if (source instanceof StaxSource) {
105             return ((StaxSource) source).getXMLStreamReader();
106         }
107         else if (JaxpVersion.isAtLeastJaxp14()) {
108             return Jaxp14StaxHandler.getXMLStreamReader(source);
109         }
110         else {
111             throw new IllegalArgumentException("Source '" + source + "' is neither StaxSource nor StAXSource");
112         }
113     }
114 
115     /**
116      * Returns the {@link XMLEventReader} for the given StAX Source.
117      *
118      * @param source a Spring-WS {@link StaxSource} or {@link StAXSource}
119      * @return the {@link XMLEventReader}
120      * @throws IllegalArgumentException if <code>source</code> is neither a Spring-WS {@link StaxSource} or {@link
121      *                                  StAXSource}
122      */
123     public static XMLEventReader getXMLEventReader(Source source) {
124         if (source instanceof StaxSource) {
125             return ((StaxSource) source).getXMLEventReader();
126         }
127         else if (JaxpVersion.isAtLeastJaxp14()) {
128             return Jaxp14StaxHandler.getXMLEventReader(source);
129         }
130         else {
131             throw new IllegalArgumentException("Source '" + source + "' is neither StaxSource nor StAXSource");
132         }
133     }
134 
135     /**
136      * Returns the {@link XMLStreamWriter} for the given StAX Result.
137      *
138      * @param result a Spring-WS {@link StaxResult} or {@link StAXResult}
139      * @return the {@link XMLStreamReader}
140      * @throws IllegalArgumentException if <code>source</code> is neither a Spring-WS {@link StaxResult} or {@link
141      *                                  StAXResult}
142      */
143     public static XMLStreamWriter getXMLStreamWriter(Result result) {
144         if (result instanceof StaxResult) {
145             return ((StaxResult) result).getXMLStreamWriter();
146         }
147         else if (JaxpVersion.isAtLeastJaxp14()) {
148             return Jaxp14StaxHandler.getXMLStreamWriter(result);
149         }
150         else {
151             throw new IllegalArgumentException("Result '" + result + "' is neither StaxResult nor StAXResult");
152         }
153     }
154 
155     /**
156      * Returns the {@link XMLEventWriter} for the given StAX Result.
157      *
158      * @param result a Spring-WS {@link StaxResult} or {@link StAXResult}
159      * @return the {@link XMLStreamReader}
160      * @throws IllegalArgumentException if <code>source</code> is neither a Spring-WS {@link StaxResult} or {@link
161      *                                  StAXResult}
162      */
163     public static XMLEventWriter getXMLEventWriter(Result result) {
164         if (result instanceof StaxResult) {
165             return ((StaxResult) result).getXMLEventWriter();
166         }
167         else if (JaxpVersion.isAtLeastJaxp14()) {
168             return Jaxp14StaxHandler.getXMLEventWriter(result);
169         }
170         else {
171             throw new IllegalArgumentException("Result '" + result + "' is neither StaxResult nor StAXResult");
172         }
173     }
174 
175     /**
176      * Creates a StAX {@link Source} for the given {@link XMLStreamReader}. Returns a {@link StAXSource} under JAXP 1.4
177      * or higher, or a {@link StaxSource} otherwise.
178      *
179      * @param streamReader the StAX stream reader
180      * @return a source wrapping <code>streamReader</code>
181      */
182     public static Source createStaxSource(XMLStreamReader streamReader) {
183         if (JaxpVersion.isAtLeastJaxp14()) {
184             return Jaxp14StaxHandler.createStaxSource(streamReader);
185         }
186         else {
187             return new StaxSource(streamReader);
188         }
189     }
190 
191     /**
192      * Creates a StAX {@link Source} for the given {@link XMLEventReader}. Returns a {@link StAXSource} under JAXP 1.4
193      * or higher, or a {@link StaxSource} otherwise.
194      *
195      * @param eventReader the StAX event reader
196      * @return a source wrapping <code>streamReader</code>
197      * @throws XMLStreamException in case of StAX errors
198      */
199     public static Source createStaxSource(XMLEventReader eventReader) throws XMLStreamException {
200         if (JaxpVersion.isAtLeastJaxp14()) {
201             return Jaxp14StaxHandler.createStaxSource(eventReader);
202         }
203         else {
204             return new StaxSource(eventReader);
205         }
206     }
207 
208     /**
209      * Returns the {@link Document} of the given {@link DOMSource}.
210      *
211      * @param source the DOM source
212      * @return the document
213      */
214     public static Document getDocument(DOMSource source) {
215         Node node = source.getNode();
216         if (node instanceof Document) {
217             return (Document) node;
218         }
219         else if (node != null) {
220             return node.getOwnerDocument();
221         }
222         else {
223             return null;
224         }
225     }
226 
227     /**
228      * Performs the given {@linkplain SourceCallback callback} operation on a {@link Source}. Supports both the JAXP 1.4
229      * {@link StAXSource} and the Spring-WS {@link StaxSource}.
230      *
231      * @param source   source to look at
232      * @param callback the callback to invoke for each kind of source
233      */
234     public static void doWithSource(Source source, SourceCallback callback)
235             throws XMLStreamException, IOException, SAXException {
236         if (source instanceof DOMSource) {
237             callback.domSource(((DOMSource) source).getNode());
238         }
239         else if (isStaxSource(source)) {
240             XMLStreamReader streamReader = getXMLStreamReader(source);
241             if (streamReader != null) {
242                 callback.staxSource(streamReader);
243             }
244             else {
245                 XMLEventReader eventReader = getXMLEventReader(source);
246                 if (eventReader != null) {
247                     callback.staxSource(eventReader);
248                 }
249                 else {
250                     throw new IllegalArgumentException(
251                             "StAX source contains neither XMLStreamReader nor XMLEventReader");
252                 }
253             }
254         }
255         else if (source instanceof SAXSource) {
256             SAXSource saxSource = (SAXSource) source;
257             callback.saxSource(saxSource.getXMLReader(), saxSource.getInputSource());
258         }
259         else if (source instanceof StreamSource) {
260             StreamSource streamSource = (StreamSource) source;
261             if (streamSource.getInputStream() != null) {
262                 callback.streamSource(streamSource.getInputStream());
263             }
264             else if (streamSource.getReader() != null) {
265                 callback.streamSource(streamSource.getReader());
266             }
267             else {
268                 throw new IllegalArgumentException("StreamSource contains neither InputStream nor Reader");
269             }
270         }
271         else {
272             throw new IllegalArgumentException("Unknown Source type: " + source.getClass());
273         }
274     }
275 
276     /**
277      * Performs the given {@linkplain ResultCallback callback} operation on a {@link Result}. Supports both the JAXP 1.4
278      * {@link StAXResult} and the Spring-WS {@link StaxResult}.
279      *
280      * @param result   result to look at
281      * @param callback the callback to invoke for each kind of result
282      */
283     public static void doWithResult(Result result, ResultCallback callback)
284             throws XMLStreamException, IOException, SAXException {
285         if (result instanceof DOMResult) {
286             callback.domResult(((DOMResult) result).getNode());
287         }
288         else if (isStaxResult(result)) {
289             XMLStreamWriter streamWriter = getXMLStreamWriter(result);
290             if (streamWriter != null) {
291                 callback.staxResult(streamWriter);
292             }
293             else {
294                 XMLEventWriter eventWriter = getXMLEventWriter(result);
295                 if (eventWriter != null) {
296                     callback.staxResult(eventWriter);
297                 }
298                 else {
299                     throw new IllegalArgumentException(
300                             "StAX result contains neither XMLStreamWriter nor XMLEventWriter");
301                 }
302             }
303         }
304         else if (result instanceof SAXResult) {
305             SAXResult saxSource = (SAXResult) result;
306             callback.saxResult(saxSource.getHandler(), saxSource.getLexicalHandler());
307         }
308         else if (result instanceof StreamResult) {
309             StreamResult streamSource = (StreamResult) result;
310             if (streamSource.getOutputStream() != null) {
311                 callback.streamResult(streamSource.getOutputStream());
312             }
313             else if (streamSource.getWriter() != null) {
314                 callback.streamResult(streamSource.getWriter());
315             }
316             else {
317                 throw new IllegalArgumentException("StreamResult contains neither OutputStream nor Writer");
318             }
319         }
320         else {
321             throw new IllegalArgumentException("Unknown Result type: " + result.getClass());
322         }
323     }
324 
325     /**
326      * Callback interface invoked on each sort of {@link Source}.
327      *
328      * @see TraxUtils#doWithSource(Source, SourceCallback)
329      */
330     public interface SourceCallback {
331 
332         /**
333          * Perform an operation on the node contained in a {@link DOMSource}.
334          *
335          * @param node the node
336          */
337         void domSource(Node node);
338 
339         /**
340          * Perform an operation on the {@code XMLReader} and {@code InputSource} contained in a {@link SAXSource}.
341          *
342          * @param reader      the reader, can be {@code null}
343          * @param inputSource the input source, can be {@code null}
344          */
345         void saxSource(XMLReader reader, InputSource inputSource) throws IOException, SAXException;
346 
347         /**
348          * Perform an operation on the {@code XMLEventReader} contained in a JAXP 1.4 {@link StAXSource} or Spring
349          * {@link StaxSource}.
350          *
351          * @param eventReader the reader
352          */
353         void staxSource(XMLEventReader eventReader) throws XMLStreamException;
354 
355         /**
356          * Perform an operation on the {@code XMLStreamReader} contained in a JAXP 1.4 {@link StAXSource} or Spring
357          * {@link StaxSource}.
358          *
359          * @param streamReader the reader
360          */
361         void staxSource(XMLStreamReader streamReader) throws XMLStreamException;
362 
363         /**
364          * Perform an operation on the {@code InputStream} contained in a {@link StreamSource}.
365          *
366          * @param inputStream the input stream
367          */
368         void streamSource(InputStream inputStream) throws IOException;
369 
370         /**
371          * Perform an operation on the {@code Reader} contained in a {@link StreamSource}.
372          *
373          * @param reader the reader
374          */
375         void streamSource(Reader reader) throws IOException;
376     }
377 
378     /**
379      * Callback interface invoked on each sort of {@link Result}.
380      *
381      * @see TraxUtils#doWithResult(Result, ResultCallback)
382      */
383     public interface ResultCallback {
384 
385         /**
386          * Perform an operation on the node contained in a {@link DOMResult}.
387          *
388          * @param node the node
389          */
390         void domResult(Node node);
391 
392         /**
393          * Perform an operation on the {@code ContentHandler} and {@code LexicalHandler} contained in a {@link
394          * SAXResult}.
395          *
396          * @param contentHandler the content handler
397          * @param lexicalHandler the lexicalHandler, can be {@code null}
398          */
399         void saxResult(ContentHandler contentHandler, LexicalHandler lexicalHandler) throws IOException, SAXException;
400 
401         /**
402          * Perform an operation on the {@code XMLEventWriter} contained in a JAXP 1.4 {@link StAXResult} or Spring
403          * {@link StaxResult}.
404          *
405          * @param eventWriter the writer
406          */
407         void staxResult(XMLEventWriter eventWriter) throws XMLStreamException;
408 
409         /**
410          * Perform an operation on the {@code XMLStreamWriter} contained in a JAXP 1.4 {@link StAXResult} or Spring
411          * {@link StaxResult}.
412          *
413          * @param streamWriter the writer
414          */
415         void staxResult(XMLStreamWriter streamWriter) throws XMLStreamException;
416 
417         /**
418          * Perform an operation on the {@code OutputStream} contained in a {@link StreamResult}.
419          *
420          * @param outputStream the output stream
421          */
422         void streamResult(OutputStream outputStream) throws IOException;
423 
424         /**
425          * Perform an operation on the {@code Writer} contained in a {@link StreamResult}.
426          *
427          * @param writer the writer
428          */
429         void streamResult(Writer writer) throws IOException;
430     }
431 
432     /** Inner class to avoid a static JAXP 1.4 dependency. */
433     private static class Jaxp14StaxHandler {
434 
435         private static Source createStaxSource(XMLStreamReader streamReader) {
436             return new StAXSource(streamReader);
437         }
438 
439         private static Source createStaxSource(XMLEventReader eventReader) throws XMLStreamException {
440             return new StAXSource(eventReader);
441         }
442 
443         private static boolean isStaxSource(Source source) {
444             return source instanceof StAXSource;
445         }
446 
447         private static boolean isStaxResult(Result result) {
448             return result instanceof StAXResult;
449         }
450 
451         private static XMLStreamReader getXMLStreamReader(Source source) {
452             Assert.isInstanceOf(StAXSource.class, source);
453             return ((StAXSource) source).getXMLStreamReader();
454         }
455 
456         private static XMLEventReader getXMLEventReader(Source source) {
457             Assert.isInstanceOf(StAXSource.class, source);
458             return ((StAXSource) source).getXMLEventReader();
459         }
460 
461         private static XMLStreamWriter getXMLStreamWriter(Result result) {
462             Assert.isInstanceOf(StAXResult.class, result);
463             return ((StAXResult) result).getXMLStreamWriter();
464         }
465 
466         private static XMLEventWriter getXMLEventWriter(Result result) {
467             Assert.isInstanceOf(StAXResult.class, result);
468             return ((StAXResult) result).getXMLEventWriter();
469         }
470     }
471 
472 
473 }