From 389fe5dd13c2aeb0de29a76e5542ba929e019b30 Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Tue, 22 Jul 2008 10:49:53 +0000 Subject: [PATCH] SWS-402 --- .../xml/transform/TraxUtils.java | 220 +++++++++++++++++ .../xml/transform/TraxUtilsTest.java | 225 ++++++++++++++++++ 2 files changed, 445 insertions(+) diff --git a/xml/src/main/java/org/springframework/xml/transform/TraxUtils.java b/xml/src/main/java/org/springframework/xml/transform/TraxUtils.java index d972cff3..ffb85d42 100644 --- a/xml/src/main/java/org/springframework/xml/transform/TraxUtils.java +++ b/xml/src/main/java/org/springframework/xml/transform/TraxUtils.java @@ -16,6 +16,11 @@ package org.springframework.xml.transform; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLEventWriter; import javax.xml.stream.XMLStreamException; @@ -23,12 +28,22 @@ import javax.xml.stream.XMLStreamReader; import javax.xml.stream.XMLStreamWriter; import javax.xml.transform.Result; import javax.xml.transform.Source; +import javax.xml.transform.dom.DOMResult; import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.sax.SAXResult; +import javax.xml.transform.sax.SAXSource; import javax.xml.transform.stax.StAXResult; import javax.xml.transform.stax.StAXSource; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; import org.w3c.dom.Document; import org.w3c.dom.Node; +import org.xml.sax.ContentHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.ext.LexicalHandler; import org.springframework.util.Assert; import org.springframework.xml.JaxpVersion; @@ -209,6 +224,211 @@ public abstract class TraxUtils { } } + /** + * Performs the given {@linkplain SourceCallback callback} operation on a {@link Source}. Supports both the JAXP 1.4 + * {@link StAXSource} and the Spring-WS {@link StaxSource}. + * + * @param source source to look at + * @param callback the callback to invoke for each kind of source + */ + public static void doWithSource(Source source, SourceCallback callback) + throws XMLStreamException, IOException, SAXException { + if (source instanceof DOMSource) { + callback.domSource(((DOMSource) source).getNode()); + } + else if (isStaxSource(source)) { + XMLStreamReader streamReader = getXMLStreamReader(source); + if (streamReader != null) { + callback.staxSource(streamReader); + } + else { + XMLEventReader eventReader = getXMLEventReader(source); + if (eventReader != null) { + callback.staxSource(eventReader); + } + else { + throw new IllegalArgumentException( + "StAX source contains neither XMLStreamReader nor XMLEventReader"); + } + } + } + else if (source instanceof SAXSource) { + SAXSource saxSource = (SAXSource) source; + callback.saxSource(saxSource.getXMLReader(), saxSource.getInputSource()); + } + else if (source instanceof StreamSource) { + StreamSource streamSource = (StreamSource) source; + if (streamSource.getInputStream() != null) { + callback.streamSource(streamSource.getInputStream()); + } + else if (streamSource.getReader() != null) { + callback.streamSource(streamSource.getReader()); + } + else { + throw new IllegalArgumentException("StreamSource contains neither InputStream nor Reader"); + } + } + else { + throw new IllegalArgumentException("Unknown Source type: " + source.getClass()); + } + } + + /** + * Performs the given {@linkplain ResultCallback callback} operation on a {@link Result}. Supports both the JAXP 1.4 + * {@link StAXResult} and the Spring-WS {@link StaxResult}. + * + * @param result result to look at + * @param callback the callback to invoke for each kind of result + */ + public static void doWithResult(Result result, ResultCallback callback) + throws XMLStreamException, IOException, SAXException { + if (result instanceof DOMResult) { + callback.domResult(((DOMResult) result).getNode()); + } + else if (isStaxResult(result)) { + XMLStreamWriter streamWriter = getXMLStreamWriter(result); + if (streamWriter != null) { + callback.staxResult(streamWriter); + } + else { + XMLEventWriter eventWriter = getXMLEventWriter(result); + if (eventWriter != null) { + callback.staxResult(eventWriter); + } + else { + throw new IllegalArgumentException( + "StAX result contains neither XMLStreamWriter nor XMLEventWriter"); + } + } + } + else if (result instanceof SAXResult) { + SAXResult saxSource = (SAXResult) result; + callback.saxResult(saxSource.getHandler(), saxSource.getLexicalHandler()); + } + else if (result instanceof StreamResult) { + StreamResult streamSource = (StreamResult) result; + if (streamSource.getOutputStream() != null) { + callback.streamResult(streamSource.getOutputStream()); + } + else if (streamSource.getWriter() != null) { + callback.streamResult(streamSource.getWriter()); + } + else { + throw new IllegalArgumentException("StreamResult contains neither OutputStream nor Writer"); + } + } + else { + throw new IllegalArgumentException("Unknown Result type: " + result.getClass()); + } + } + + /** + * Callback interface invoked on each sort of {@link Source}. + * + * @see TraxUtils#doWithSource(Source, SourceCallback) + */ + public interface SourceCallback { + + /** + * Perform an operation on the node contained in a {@link DOMSource}. + * + * @param node the node + */ + void domSource(Node node); + + /** + * Perform an operation on the {@code XMLReader} and {@code InputSource} contained in a {@link SAXSource}. + * + * @param reader the reader, can be {@code null} + * @param inputSource the input source, can be {@code null} + */ + void saxSource(XMLReader reader, InputSource inputSource) throws IOException, SAXException; + + /** + * Perform an operation on the {@code XMLEventReader} contained in a JAXP 1.4 {@link StAXSource} or Spring + * {@link StaxSource}. + * + * @param eventReader the reader + */ + void staxSource(XMLEventReader eventReader) throws XMLStreamException; + + /** + * Perform an operation on the {@code XMLStreamReader} contained in a JAXP 1.4 {@link StAXSource} or Spring + * {@link StaxSource}. + * + * @param streamReader the reader + */ + void staxSource(XMLStreamReader streamReader) throws XMLStreamException; + + /** + * Perform an operation on the {@code InputStream} contained in a {@link StreamSource}. + * + * @param inputStream the input stream + */ + void streamSource(InputStream inputStream) throws IOException; + + /** + * Perform an operation on the {@code Reader} contained in a {@link StreamSource}. + * + * @param reader the reader + */ + void streamSource(Reader reader) throws IOException; + } + + /** + * Callback interface invoked on each sort of {@link Result}. + * + * @see TraxUtils#doWithResult(Result, ResultCallback) + */ + public interface ResultCallback { + + /** + * Perform an operation on the node contained in a {@link DOMResult}. + * + * @param node the node + */ + void domResult(Node node); + + /** + * Perform an operation on the {@code ContentHandler} and {@code LexicalHandler} contained in a {@link + * SAXResult}. + * + * @param contentHandler the content handler + * @param lexicalHandler the lexicalHandler, can be {@code null} + */ + void saxResult(ContentHandler contentHandler, LexicalHandler lexicalHandler) throws IOException, SAXException; + + /** + * Perform an operation on the {@code XMLEventWriter} contained in a JAXP 1.4 {@link StAXResult} or Spring + * {@link StaxResult}. + * + * @param eventWriter the writer + */ + void staxResult(XMLEventWriter eventWriter) throws XMLStreamException; + + /** + * Perform an operation on the {@code XMLStreamWriter} contained in a JAXP 1.4 {@link StAXResult} or Spring + * {@link StaxResult}. + * + * @param streamWriter the writer + */ + void staxResult(XMLStreamWriter streamWriter) throws XMLStreamException; + + /** + * Perform an operation on the {@code OutputStream} contained in a {@link StreamResult}. + * + * @param outputStream the output stream + */ + void streamResult(OutputStream outputStream) throws IOException; + + /** + * Perform an operation on the {@code Writer} contained in a {@link StreamResult}. + * + * @param writer the writer + */ + void streamResult(Writer writer) throws IOException; + } + /** Inner class to avoid a static JAXP 1.4 dependency. */ private static class Jaxp14StaxHandler { diff --git a/xml/src/test/java/org/springframework/xml/transform/TraxUtilsTest.java b/xml/src/test/java/org/springframework/xml/transform/TraxUtilsTest.java index 500bc1f5..a7fc383d 100644 --- a/xml/src/test/java/org/springframework/xml/transform/TraxUtilsTest.java +++ b/xml/src/test/java/org/springframework/xml/transform/TraxUtilsTest.java @@ -16,8 +16,14 @@ package org.springframework.xml.transform; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; +import java.io.Writer; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.stream.XMLEventReader; @@ -26,6 +32,7 @@ import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamReader; import javax.xml.stream.XMLStreamWriter; +import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; @@ -39,8 +46,16 @@ import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import org.custommonkey.xmlunit.XMLTestCase; +import org.easymock.MockControl; import org.w3c.dom.Document; import org.w3c.dom.Element; +import org.xml.sax.ContentHandler; +import org.xml.sax.InputSource; +import org.xml.sax.XMLReader; +import org.xml.sax.ext.DefaultHandler2; +import org.xml.sax.ext.LexicalHandler; +import org.xml.sax.helpers.DefaultHandler; +import org.xml.sax.helpers.XMLReaderFactory; public class TraxUtilsTest extends XMLTestCase { @@ -204,4 +219,214 @@ public class TraxUtilsTest extends XMLTestCase { document.appendChild(element); assertSame("Invalid document", document, TraxUtils.getDocument(new DOMSource(element))); } + + public void testDoWithDomSource() throws Exception { + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); + Document document = documentBuilder.newDocument(); + + MockControl control = MockControl.createControl(TraxUtils.SourceCallback.class); + TraxUtils.SourceCallback mock = (TraxUtils.SourceCallback) control.getMock(); + mock.domSource(document); + control.replay(); + + TraxUtils.doWithSource(new DOMSource(document), mock); + + control.verify(); + } + + public void testDoWithDomResult() throws Exception { + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); + Document document = documentBuilder.newDocument(); + + MockControl control = MockControl.createControl(TraxUtils.ResultCallback.class); + TraxUtils.ResultCallback mock = (TraxUtils.ResultCallback) control.getMock(); + mock.domResult(document); + control.replay(); + + TraxUtils.doWithResult(new DOMResult(document), mock); + + control.verify(); + } + + public void testDoWithSaxSource() throws Exception { + XMLReader reader = XMLReaderFactory.createXMLReader(); + InputSource inputSource = new InputSource(); + + MockControl control = MockControl.createControl(TraxUtils.SourceCallback.class); + TraxUtils.SourceCallback mock = (TraxUtils.SourceCallback) control.getMock(); + mock.saxSource(reader, inputSource); + control.replay(); + + TraxUtils.doWithSource(new SAXSource(reader, inputSource), mock); + + control.verify(); + } + + public void testDoWithSaxResult() throws Exception { + ContentHandler contentHandler = new DefaultHandler(); + LexicalHandler lexicalHandler = new DefaultHandler2(); + + MockControl control = MockControl.createControl(TraxUtils.ResultCallback.class); + TraxUtils.ResultCallback mock = (TraxUtils.ResultCallback) control.getMock(); + mock.saxResult(contentHandler, lexicalHandler); + control.replay(); + + SAXResult result = new SAXResult(contentHandler); + result.setLexicalHandler(lexicalHandler); + TraxUtils.doWithResult(result, mock); + + control.verify(); + } + + public void testDoWithStaxSourceEventReader() throws Exception { + XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + XMLEventReader eventReader = inputFactory.createXMLEventReader(new StringReader("")); + + MockControl control = MockControl.createControl(TraxUtils.SourceCallback.class); + TraxUtils.SourceCallback mock = (TraxUtils.SourceCallback) control.getMock(); + mock.staxSource(eventReader); + control.replay(); + + TraxUtils.doWithSource(new StaxSource(eventReader), mock); + + control.verify(); + } + + public void testDoWithStaxResultEventWriter() throws Exception { + XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); + XMLEventWriter eventWriter = outputFactory.createXMLEventWriter(new StringWriter()); + + MockControl control = MockControl.createControl(TraxUtils.ResultCallback.class); + TraxUtils.ResultCallback mock = (TraxUtils.ResultCallback) control.getMock(); + mock.staxResult(eventWriter); + control.replay(); + + TraxUtils.doWithResult(new StaxResult(eventWriter), mock); + + control.verify(); + } + + public void testDoWithStaxSourceStreamReader() throws Exception { + XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + XMLStreamReader streamReader = inputFactory.createXMLStreamReader(new StringReader("")); + + MockControl control = MockControl.createControl(TraxUtils.SourceCallback.class); + TraxUtils.SourceCallback mock = (TraxUtils.SourceCallback) control.getMock(); + mock.staxSource(streamReader); + control.replay(); + + TraxUtils.doWithSource(new StaxSource(streamReader), mock); + + control.verify(); + } + + public void testDoWithStaxResultStreamWriter() throws Exception { + XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); + XMLStreamWriter streamWriter = outputFactory.createXMLStreamWriter(new StringWriter()); + + MockControl control = MockControl.createControl(TraxUtils.ResultCallback.class); + TraxUtils.ResultCallback mock = (TraxUtils.ResultCallback) control.getMock(); + mock.staxResult(streamWriter); + control.replay(); + + TraxUtils.doWithResult(new StaxResult(streamWriter), mock); + + control.verify(); + } + + public void testDoWithStreamSourceInputStream() throws Exception { + byte[] xml = "".getBytes("UTF-8"); + InputStream inputStream = new ByteArrayInputStream(xml); + + MockControl control = MockControl.createControl(TraxUtils.SourceCallback.class); + TraxUtils.SourceCallback mock = (TraxUtils.SourceCallback) control.getMock(); + mock.streamSource(inputStream); + control.replay(); + + TraxUtils.doWithSource(new StreamSource(inputStream), mock); + + control.verify(); + } + + public void testDoWithStreamResultOutputStream() throws Exception { + OutputStream outputStream = new ByteArrayOutputStream(); + + MockControl control = MockControl.createControl(TraxUtils.ResultCallback.class); + TraxUtils.ResultCallback mock = (TraxUtils.ResultCallback) control.getMock(); + mock.streamResult(outputStream); + control.replay(); + + TraxUtils.doWithResult(new StreamResult(outputStream), mock); + + control.verify(); + } + + public void testDoWithStreamSourceReader() throws Exception { + String xml = ""; + Reader reader = new StringReader(xml); + + MockControl control = MockControl.createControl(TraxUtils.SourceCallback.class); + TraxUtils.SourceCallback mock = (TraxUtils.SourceCallback) control.getMock(); + mock.streamSource(reader); + control.replay(); + + TraxUtils.doWithSource(new StreamSource(reader), mock); + + control.verify(); + } + + public void testDoWithStreamResultWriter() throws Exception { + Writer writer = new StringWriter(); + + MockControl control = MockControl.createControl(TraxUtils.ResultCallback.class); + TraxUtils.ResultCallback mock = (TraxUtils.ResultCallback) control.getMock(); + mock.streamResult(writer); + control.replay(); + + TraxUtils.doWithResult(new StreamResult(writer), mock); + + control.verify(); + } + + public void testDoWithInvalidSource() throws Exception { + Source source = new Source() { + + public void setSystemId(String systemId) { + } + + public String getSystemId() { + return null; + } + }; + + try { + TraxUtils.doWithSource(source, null); + fail("IllegalArgumentException expected"); + } + catch (IllegalArgumentException ex) { + // expected + } + } + + public void testDoWithInvalidResult() throws Exception { + Result result = new Result() { + + public void setSystemId(String systemId) { + } + + public String getSystemId() { + return null; + } + }; + + try { + TraxUtils.doWithResult(result, null); + fail("IllegalArgumentException expected"); + } + catch (IllegalArgumentException ex) { + // expected + } + } } \ No newline at end of file