diff --git a/core/src/main/java/org/springframework/ws/server/endpoint/AbstractXomPayloadEndpoint.java b/core/src/main/java/org/springframework/ws/server/endpoint/AbstractXomPayloadEndpoint.java index 9738fab7..a0649aa0 100644 --- a/core/src/main/java/org/springframework/ws/server/endpoint/AbstractXomPayloadEndpoint.java +++ b/core/src/main/java/org/springframework/ws/server/endpoint/AbstractXomPayloadEndpoint.java @@ -187,6 +187,17 @@ public abstract class AbstractXomPayloadEndpoint extends TransformerObjectSuppor throw new XomParsingException(ex); } } + + public void source(String systemId) throws Exception { + try { + Builder builder = new Builder(); + Document document = builder.build(systemId); + element = document.getRootElement(); + } + catch (ParsingException ex) { + throw new XomParsingException(ex); + } + } } private static class XomParsingException extends NestedRuntimeException { diff --git a/core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/jaxb/AbstractJaxb2PayloadMethodProcessor.java b/core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/jaxb/AbstractJaxb2PayloadMethodProcessor.java index de9272e2..7a450d51 100644 --- a/core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/jaxb/AbstractJaxb2PayloadMethodProcessor.java +++ b/core/src/main/java/org/springframework/ws/server/endpoint/adapter/method/jaxb/AbstractJaxb2PayloadMethodProcessor.java @@ -21,6 +21,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.Reader; import java.io.Writer; +import java.net.URL; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import javax.xml.bind.JAXBContext; @@ -38,6 +39,7 @@ import javax.xml.stream.XMLStreamWriter; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import org.springframework.util.Assert; @@ -227,6 +229,10 @@ public abstract class AbstractJaxb2PayloadMethodProcessor extends AbstractPayloa public void streamSource(Reader reader) throws IOException, JAXBException { result = unmarshaller.unmarshal(reader); } + + public void source(String systemId) throws Exception { + result = unmarshaller.unmarshal(new URL(systemId)); + } } private class JaxbElementSourceCallback implements TraxUtils.SourceCallback { @@ -265,6 +271,10 @@ public abstract class AbstractJaxb2PayloadMethodProcessor extends AbstractPayloa public void streamSource(Reader reader) throws IOException, JAXBException { result = unmarshaller.unmarshal(new StreamSource(reader), declaredType); } + + public void source(String systemId) throws Exception { + result = unmarshaller.unmarshal(new StreamSource(systemId), declaredType); + } } private class Jaxb2ResultCallback implements TraxUtils.ResultCallback { @@ -301,6 +311,10 @@ public abstract class AbstractJaxb2PayloadMethodProcessor extends AbstractPayloa public void streamResult(Writer writer) throws JAXBException { marshaller.marshal(jaxbElement, writer); } + + public void result(String systemId) throws Exception { + marshaller.marshal(jaxbElement, new StreamResult(systemId)); + } } private class JaxbStreamingPayload implements StreamingPayload { diff --git a/core/src/main/java/org/springframework/ws/server/endpoint/support/PayloadRootUtils.java b/core/src/main/java/org/springframework/ws/server/endpoint/support/PayloadRootUtils.java index 19e91bb0..f2145e66 100644 --- a/core/src/main/java/org/springframework/ws/server/endpoint/support/PayloadRootUtils.java +++ b/core/src/main/java/org/springframework/ws/server/endpoint/support/PayloadRootUtils.java @@ -143,6 +143,10 @@ public abstract class PayloadRootUtils { public void streamSource(Reader reader) throws Exception { // Do nothing } + + public void source(String systemId) throws Exception { + // Do nothing + } } 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 26f249ee..d704f15d 100644 --- a/xml/src/main/java/org/springframework/xml/transform/TraxUtils.java +++ b/xml/src/main/java/org/springframework/xml/transform/TraxUtils.java @@ -36,6 +36,7 @@ import javax.xml.transform.stax.StAXSource; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; +import org.springframework.util.StringUtils; import org.springframework.util.xml.StaxUtils; import org.w3c.dom.Document; @@ -207,38 +208,41 @@ public abstract class TraxUtils { public static void doWithSource(Source source, SourceCallback callback) throws Exception { if (source instanceof DOMSource) { callback.domSource(((DOMSource) source).getNode()); + return; } else if (isStaxSource(source)) { XMLStreamReader streamReader = getXMLStreamReader(source); if (streamReader != null) { callback.staxSource(streamReader); + return; } else { XMLEventReader eventReader = getXMLEventReader(source); if (eventReader != null) { callback.staxSource(eventReader); - } - else { - throw new IllegalArgumentException( - "StAX source contains neither XMLStreamReader nor XMLEventReader"); + return; } } } else if (source instanceof SAXSource) { SAXSource saxSource = (SAXSource) source; callback.saxSource(saxSource.getXMLReader(), saxSource.getInputSource()); + return; } else if (source instanceof StreamSource) { StreamSource streamSource = (StreamSource) source; if (streamSource.getInputStream() != null) { callback.streamSource(streamSource.getInputStream()); + return; } else if (streamSource.getReader() != null) { callback.streamSource(streamSource.getReader()); + return; } - else { - throw new IllegalArgumentException("StreamSource contains neither InputStream nor Reader"); - } + } + if (StringUtils.hasLength(source.getSystemId())) { + String systemId = source.getSystemId(); + callback.source(systemId); } else { throw new IllegalArgumentException("Unknown Source type: " + source.getClass()); @@ -246,8 +250,8 @@ public abstract class TraxUtils { } /** - * Performs the given {@linkplain ResultCallback callback} operation on a {@link Result}. Supports both the JAXP 1.4 - * {@link StAXResult} and the Spring 3.0 {@link StaxUtils#createStaxResult StaxSource}. + * Performs the given {@linkplain org.springframework.xml.transform.TraxUtils.ResultCallback callback} operation on a {@link javax.xml.transform.Result}. Supports both the JAXP 1.4 + * {@link javax.xml.transform.stax.StAXResult} and the Spring 3.0 {@link org.springframework.util.xml.StaxUtils#createStaxResult StaxSource}. * * @param result result to look at * @param callback the callback to invoke for each kind of result @@ -255,38 +259,41 @@ public abstract class TraxUtils { public static void doWithResult(Result result, ResultCallback callback) throws Exception{ if (result instanceof DOMResult) { callback.domResult(((DOMResult) result).getNode()); + return; } else if (isStaxResult(result)) { XMLStreamWriter streamWriter = getXMLStreamWriter(result); if (streamWriter != null) { callback.staxResult(streamWriter); + return; } else { XMLEventWriter eventWriter = getXMLEventWriter(result); if (eventWriter != null) { callback.staxResult(eventWriter); - } - else { - throw new IllegalArgumentException( - "StAX result contains neither XMLStreamWriter nor XMLEventWriter"); + return; } } } else if (result instanceof SAXResult) { SAXResult saxSource = (SAXResult) result; callback.saxResult(saxSource.getHandler(), saxSource.getLexicalHandler()); + return; } else if (result instanceof StreamResult) { StreamResult streamSource = (StreamResult) result; if (streamSource.getOutputStream() != null) { callback.streamResult(streamSource.getOutputStream()); + return; } else if (streamSource.getWriter() != null) { callback.streamResult(streamSource.getWriter()); + return; } - else { - throw new IllegalArgumentException("StreamResult contains neither OutputStream nor Writer"); - } + } + if (StringUtils.hasLength(result.getSystemId())) { + String systemId = result.getSystemId(); + callback.result(systemId); } else { throw new IllegalArgumentException("Unknown Result type: " + result.getClass()); @@ -344,6 +351,15 @@ public abstract class TraxUtils { * @param reader the reader */ void streamSource(Reader reader) throws Exception; + + /** + * Perform an operation on the system identifier contained in any {@link Source}. + * + * @param systemId the system identifier + */ + void source(String systemId) throws Exception; + + } /** @@ -398,6 +414,14 @@ public abstract class TraxUtils { * @param writer the writer */ void streamResult(Writer writer) throws Exception; + + /** + * Perform an operation on the system identifier contained in any {@link Result}. + * + * @param systemId the system identifier + */ + void result(String systemId) throws Exception; + } diff --git a/xml/src/main/java/org/springframework/xml/xpath/Jaxp13XPathTemplate.java b/xml/src/main/java/org/springframework/xml/xpath/Jaxp13XPathTemplate.java index 00631da8..d48bdd52 100644 --- a/xml/src/main/java/org/springframework/xml/xpath/Jaxp13XPathTemplate.java +++ b/xml/src/main/java/org/springframework/xml/xpath/Jaxp13XPathTemplate.java @@ -16,32 +16,40 @@ package org.springframework.xml.xpath; +import java.io.InputStream; +import java.io.Reader; import java.util.ArrayList; import java.util.List; import javax.xml.namespace.QName; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; import javax.xml.transform.Source; import javax.xml.transform.TransformerException; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.sax.SAXSource; -import javax.xml.transform.stream.StreamSource; +import javax.xml.transform.dom.DOMResult; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import javax.xml.xpath.XPathFactoryConfigurationException; -import org.springframework.util.xml.StaxUtils; import org.springframework.xml.namespace.SimpleNamespaceContext; +import org.springframework.xml.transform.StaxSource; +import org.springframework.xml.transform.TransformerHelper; +import org.springframework.xml.transform.TraxUtils; import org.w3c.dom.DOMException; +import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; +import org.xml.sax.XMLReader; /** * Implementation of {@link XPathOperations} that uses JAXP 1.3. JAXP 1.3 is part of Java SE since 1.5. *

- * Namespaces can be set using the namespaces property. + * Namespaces can be set using the {@code namespaces} property. * * @author Arjen Poutsma * @see #setNamespaces(java.util.Map) @@ -128,35 +136,9 @@ public class Jaxp13XPathTemplate extends AbstractXPathTemplate { xpath.setNamespaceContext(namespaceContext); } try { - if (StaxUtils.isStaxSource(context)) { - Element element = getRootElement(context); - return xpath.evaluate(expression, element, returnType); - } - else if (context instanceof SAXSource) { - SAXSource saxSource = (SAXSource) context; - return xpath.evaluate(expression, saxSource.getInputSource(), returnType); - } - else if (context instanceof DOMSource) { - DOMSource domSource = (DOMSource) context; - return xpath.evaluate(expression, domSource.getNode(), returnType); - } - else if (context instanceof StreamSource) { - StreamSource streamSource = (StreamSource) context; - InputSource inputSource; - if (streamSource.getInputStream() != null) { - inputSource = new InputSource(streamSource.getInputStream()); - } - else if (streamSource.getReader() != null) { - inputSource = new InputSource(streamSource.getReader()); - } - else { - throw new IllegalArgumentException("StreamSource contains neither InputStream nor Reader"); - } - return xpath.evaluate(expression, inputSource, returnType); - } - else { - throw new IllegalArgumentException("context type unknown"); - } + EvaluationCallback callback = new EvaluationCallback(xpath, expression, returnType); + TraxUtils.doWithSource(context, callback); + return callback.result; } catch (javax.xml.xpath.XPathException ex) { throw new XPathException("Could not evaluate XPath expression [" + expression + "]", ex); @@ -164,11 +146,77 @@ public class Jaxp13XPathTemplate extends AbstractXPathTemplate { catch (TransformerException ex) { throw new XPathException("Could not transform context to DOM Node", ex); } + catch (Exception ex) { + throw new XPathException(ex.getMessage(), ex); + } } private synchronized XPath createXPath() { return xpathFactory.newXPath(); } + private static class EvaluationCallback implements TraxUtils.SourceCallback { + + private final XPath xpath; + + private final String expression; + + private final QName returnType; + + private final TransformerHelper transformerHelper = new TransformerHelper(); + + private Object result; + + private EvaluationCallback(XPath xpath, String expression, QName returnType) { + this.xpath = xpath; + this.expression = expression; + this.returnType = returnType; + } + + public void domSource(Node node) throws XPathExpressionException { + result = xpath.evaluate(expression, node, returnType); + } + + public void saxSource(XMLReader reader, InputSource inputSource) throws XPathExpressionException { + inputSource(inputSource); + } + + public void staxSource(XMLEventReader eventReader) + throws XPathExpressionException, XMLStreamException, TransformerException { + Element element = getRootElement(new StaxSource(eventReader)); + domSource(element); + } + + public void staxSource(XMLStreamReader streamReader) throws TransformerException, XPathExpressionException { + Element element = getRootElement(new StaxSource(streamReader)); + domSource(element); + } + + public void streamSource(InputStream inputStream) throws XPathExpressionException { + inputSource(new InputSource(inputStream)); + } + + public void streamSource(Reader reader) throws XPathExpressionException { + inputSource(new InputSource(reader)); + } + + public void source(String systemId) throws XPathExpressionException { + inputSource(new InputSource(systemId)); + } + + private void inputSource(InputSource inputSource) throws XPathExpressionException { + result = xpath.evaluate(expression, inputSource, returnType); + } + + private Element getRootElement(Source source) throws TransformerException { + DOMResult domResult = new DOMResult(); + transformerHelper.transform(source, domResult); + Document document = (Document) domResult.getNode(); + return document.getDocumentElement(); + } + + } + + } 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 e5d656b8..0a024d1c 100644 --- a/xml/src/test/java/org/springframework/xml/transform/TraxUtilsTest.java +++ b/xml/src/test/java/org/springframework/xml/transform/TraxUtilsTest.java @@ -253,6 +253,35 @@ public class TraxUtilsTest { verify(mock); } + @Test + public void testDoWithSystemIdSource() throws Exception { + String systemId = "http://www.springframework.org/dtd/spring-beans.dtd"; + + TraxUtils.SourceCallback mock = createMock(TraxUtils.SourceCallback.class); + mock.source(systemId); + + replay(mock); + + TraxUtils.doWithSource(new StreamSource(systemId), mock); + + verify(mock); + } + + @Test + public void testDoWithSystemIdResult() throws Exception { + String systemId = "http://www.springframework.org/dtd/spring-beans.dtd"; + + TraxUtils.ResultCallback mock = createMock(TraxUtils.ResultCallback.class); + mock.result(systemId); + + replay(mock); + + TraxUtils.doWithResult(new StreamResult(systemId), mock); + + verify(mock); + } + + @Test public void testDoWithInvalidSource() throws Exception { Source source = new Source() { diff --git a/xml/src/test/java/org/springframework/xml/xpath/AbstractXPathTemplateTestCase.java b/xml/src/test/java/org/springframework/xml/xpath/AbstractXPathTemplateTestCase.java index a2ddf8cb..b6f02e78 100644 --- a/xml/src/test/java/org/springframework/xml/xpath/AbstractXPathTemplateTestCase.java +++ b/xml/src/test/java/org/springframework/xml/xpath/AbstractXPathTemplateTestCase.java @@ -18,12 +18,17 @@ package org.springframework.xml.xpath; import java.io.IOException; import java.io.InputStream; +import java.net.URL; import java.util.List; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamReader; import javax.xml.transform.Source; import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stax.StAXSource; import javax.xml.transform.stream.StreamSource; import org.springframework.core.io.ClassPathResource; @@ -36,6 +41,7 @@ import org.junit.Test; import org.w3c.dom.DOMException; import org.w3c.dom.Document; import org.w3c.dom.Node; +import org.xml.sax.InputSource; import org.xml.sax.SAXException; public abstract class AbstractXPathTemplateTestCase { @@ -133,9 +139,34 @@ public abstract class AbstractXPathTemplateTestCase { } @Test - public void testEvaluateStreamSource() throws IOException, SAXException, ParserConfigurationException { + public void testEvaluateSAXSource() throws Exception { InputStream in = AbstractXPathTemplateTestCase.class.getResourceAsStream("nonamespaces.xml"); - String result = template.evaluateAsString("/root/child/text", new StreamSource(in)); + SAXSource source = new SAXSource(new InputSource(in)); + String result = template.evaluateAsString("/root/child/text", source); + Assert.assertEquals("Invalid result", "text", result); + } + + @Test + public void testEvaluateStaxSource() throws Exception { + InputStream in = AbstractXPathTemplateTestCase.class.getResourceAsStream("nonamespaces.xml"); + XMLStreamReader streamReader = XMLInputFactory.newFactory().createXMLStreamReader(in); + StAXSource source = new StAXSource(streamReader); + String result = template.evaluateAsString("/root/child/text", source); + Assert.assertEquals("Invalid result", "text", result); + } + + @Test + public void testEvaluateStreamSourceInputStream() throws IOException, SAXException, ParserConfigurationException { + InputStream in = AbstractXPathTemplateTestCase.class.getResourceAsStream("nonamespaces.xml"); + StreamSource source = new StreamSource(in); + String result = template.evaluateAsString("/root/child/text", source); + Assert.assertEquals("Invalid result", "text", result); + } + + @Test + public void testEvaluateStreamSourceSystemId() throws IOException, SAXException, ParserConfigurationException { + URL url = AbstractXPathTemplateTestCase.class.getResource("nonamespaces.xml"); + String result = template.evaluateAsString("/root/child/text", new StreamSource(url.toString())); Assert.assertEquals("Invalid result", "text", result); } @@ -152,7 +183,7 @@ public abstract class AbstractXPathTemplateTestCase { @Test public void testEvaluateAsObject() throws Exception { - String result = (String) template.evaluateAsObject("/root/child", nonamespaces, new NodeMapper() { + String result = template.evaluateAsObject("/root/child", nonamespaces, new NodeMapper() { public String mapNode(Node node, int nodeNum) throws DOMException { return node.getLocalName(); }