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 43683d19..a087ed66 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 @@ -17,7 +17,14 @@ package org.springframework.ws.server.endpoint; import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.Result; import javax.xml.transform.Source; +import javax.xml.transform.Transformer; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.sax.SAXSource; import javax.xml.transform.stream.StreamSource; @@ -25,9 +32,12 @@ import javax.xml.transform.stream.StreamSource; import nu.xom.Builder; import nu.xom.Document; import nu.xom.Element; +import nu.xom.NodeFactory; +import nu.xom.Nodes; import nu.xom.ParsingException; import nu.xom.converters.DOMConverter; -import org.springframework.xml.transform.StringSource; +import org.springframework.util.ClassUtils; +import org.springframework.xml.transform.TransformerObjectSupport; import org.w3c.dom.Node; import org.xml.sax.InputSource; @@ -37,13 +47,96 @@ import org.xml.sax.InputSource; *
* AnAbstractXomPayloadEndpoint only accept one payload element. Multiple payload elements are not in
* accordance with WS-I.
+ *
+ * This class tries to use Java reflection to access some of the non-public classes of XOM
+ * (nu.xom.xslt.XOMResult and nu.xom.xslt.XOMSource). If these classes cannot be accessed
+ * because of security restrictions, a slower approach is used. You can specify whether you want to use the faster, but
+ * non-public reflection-based approach by calling {@link #AbstractXomPayloadEndpoint(boolean)}.
*
* @author Arjen Poutsma
* @see Element
*/
-public abstract class AbstractXomPayloadEndpoint implements PayloadEndpoint {
+public abstract class AbstractXomPayloadEndpoint extends TransformerObjectSupport implements PayloadEndpoint {
+
+ private Constructor xomResultConstructor;
+
+ private Method xomResultGetResultMethod;
+
+ private Constructor xomSourceConstructor;
+
+ private boolean useReflection = true;
+
+ private DocumentBuilderFactory documentBuilderFactory;
+
+ /**
+ * Creates a new instance of AbstractXomPayloadEndpoint using reflection to access faster, but
+ * non-public XOM classes.
+ */
+ protected AbstractXomPayloadEndpoint() {
+ this(true);
+ }
+
+ /**
+ * Creates a new instance of AbstractXomPayloadEndpoint.
+ *
+ * @param useReflection specifies whether to use faster, but non-public XOM classes (true); or to use a
+ * converting approach (false)
+ */
+ protected AbstractXomPayloadEndpoint(boolean useReflection) {
+ this.useReflection = useReflection;
+ if (useReflection) {
+ try {
+ Class xomResultClass = ClassUtils.forName("nu.xom.xslt.XOMResult");
+ xomResultConstructor = xomResultClass.getDeclaredConstructor(new Class[]{NodeFactory.class});
+ xomResultConstructor.setAccessible(true);
+ xomResultGetResultMethod = xomResultClass.getDeclaredMethod("getResult", new Class[0]);
+ xomResultGetResultMethod.setAccessible(true);
+ Class xomSourceClass = ClassUtils.forName("nu.xom.xslt.XOMSource");
+ xomSourceConstructor = xomSourceClass.getDeclaredConstructor(new Class[]{Nodes.class});
+ xomSourceConstructor.setAccessible(true);
+ }
+ catch (Exception e) {
+ this.useReflection = false;
+ createDocumentBuilderFactory();
+ }
+ }
+ }
public final Source invoke(Source request) throws Exception {
+ if (useReflection) {
+ return invokeUsingReflection(request);
+ }
+ else {
+ return invokeUsingTransformation(request);
+ }
+ }
+
+ private Source invokeUsingReflection(Source request) throws Exception {
+ try {
+ Transformer transformer = createTransformer();
+ Result xomResult = createXomResult();
+ transformer.transform(request, xomResult);
+ Element requestElement = getRequestElement(xomResult);
+
+ Element responseElement = invokeInternal(requestElement);
+ return responseElement != null ? createXomSource(responseElement) : null;
+ }
+ catch (IllegalAccessException ex) {
+ useReflection = false;
+ throw ex;
+ }
+ catch (InvocationTargetException ex) {
+ useReflection = false;
+ throw ex;
+ }
+ catch (InstantiationException ex) {
+ useReflection = false;
+ throw ex;
+ }
+ }
+
+ private Source invokeUsingTransformation(Source request) throws Exception {
+ logger.debug("Using transformations");
Element requestElement = null;
if (request instanceof DOMSource) {
requestElement = handleDomSource(request);
@@ -59,7 +152,40 @@ public abstract class AbstractXomPayloadEndpoint implements PayloadEndpoint {
"Source [" + request.getClass().getName() + "] is neither SAXSource, DOMSource, nor StreamSource");
}
Element responseElement = invokeInternal(requestElement);
- return responseElement != null ? new StringSource(responseElement.toXML()) : null;
+ if (responseElement != null) {
+ if (documentBuilderFactory == null) {
+ createDocumentBuilderFactory();
+ }
+ DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
+ Document responseDocument = new Document(responseElement);
+ org.w3c.dom.Document w3cDocument =
+ DOMConverter.convert(responseDocument, documentBuilder.getDOMImplementation());
+ return new DOMSource(w3cDocument);
+ }
+ else {
+ return null;
+ }
+
+ }
+
+ private Result createXomResult() throws IllegalAccessException, InvocationTargetException, InstantiationException {
+ return (Result) xomResultConstructor.newInstance(new Object[]{new NodeFactory()});
+ }
+
+ private Element getRequestElement(Result xomResult) throws IllegalAccessException, InvocationTargetException {
+ Nodes result = (Nodes) xomResultGetResultMethod.invoke(xomResult, new Object[0]);
+ if (result.size() == 0) {
+ return null;
+ }
+ else {
+ return (Element) result.get(0);
+ }
+ }
+
+ private Source createXomSource(Element responseElement)
+ throws IllegalAccessException, InvocationTargetException, InstantiationException {
+ Nodes nodes = new Nodes(responseElement);
+ return (Source) xomSourceConstructor.newInstance(new Object[]{nodes});
}
private Element handleStreamSource(Source request) throws ParsingException, IOException {
@@ -109,6 +235,11 @@ public abstract class AbstractXomPayloadEndpoint implements PayloadEndpoint {
return DOMConverter.convert(w3cElement);
}
+ private void createDocumentBuilderFactory() {
+ documentBuilderFactory = DocumentBuilderFactory.newInstance();
+ documentBuilderFactory.setNamespaceAware(true);
+ }
+
/**
* Template method. Subclasses must implement this. Offers the request payload as a XOM Element, and
* allows subclasses to return a response Element.
@@ -118,4 +249,5 @@ public abstract class AbstractXomPayloadEndpoint implements PayloadEndpoint {
*/
protected abstract Element invokeInternal(Element requestElement) throws Exception;
+
}
diff --git a/core/src/test/java/org/springframework/ws/server/endpoint/XomPayloadEndpointTest.java b/core/src/test/java/org/springframework/ws/server/endpoint/NonReflectiveXomPayloadEndpointTest.java
similarity index 80%
rename from core/src/test/java/org/springframework/ws/server/endpoint/XomPayloadEndpointTest.java
rename to core/src/test/java/org/springframework/ws/server/endpoint/NonReflectiveXomPayloadEndpointTest.java
index c421cae1..700954a2 100644
--- a/core/src/test/java/org/springframework/ws/server/endpoint/XomPayloadEndpointTest.java
+++ b/core/src/test/java/org/springframework/ws/server/endpoint/NonReflectiveXomPayloadEndpointTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2006 the original author or authors.
+ * Copyright 2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,10 +18,10 @@ package org.springframework.ws.server.endpoint;
import nu.xom.Element;
-public class XomPayloadEndpointTest extends AbstractPayloadEndpointTestCase {
+public class NonReflectiveXomPayloadEndpointTest extends AbstractPayloadEndpointTestCase {
protected PayloadEndpoint createNoResponseEndpoint() throws Exception {
- return new AbstractXomPayloadEndpoint() {
+ return new AbstractXomPayloadEndpoint(false) {
protected Element invokeInternal(Element requestElement) throws Exception {
return null;
@@ -30,7 +30,7 @@ public class XomPayloadEndpointTest extends AbstractPayloadEndpointTestCase {
}
protected PayloadEndpoint createResponseEndpoint() throws Exception {
- return new AbstractXomPayloadEndpoint() {
+ return new AbstractXomPayloadEndpoint(false) {
protected Element invokeInternal(Element requestElement) throws Exception {
assertNotNull("No requestElement passed", requestElement);
@@ -42,10 +42,10 @@ public class XomPayloadEndpointTest extends AbstractPayloadEndpointTestCase {
}
public void testStaxSourceEventReader() throws Exception {
- // Unfortutately, XOM does not support these, hence the override here
+ // overriden, because XOM doesn not support it
}
public void testStaxSourceStreamReader() throws Exception {
- // Unfortutately, XOM does not support these, hence the override here
+ // overriden, because XOM doesn not support it
}
}
diff --git a/core/src/test/java/org/springframework/ws/server/endpoint/ReflectiveXomPayloadEndpointTest.java b/core/src/test/java/org/springframework/ws/server/endpoint/ReflectiveXomPayloadEndpointTest.java
new file mode 100644
index 00000000..ea6b6d9e
--- /dev/null
+++ b/core/src/test/java/org/springframework/ws/server/endpoint/ReflectiveXomPayloadEndpointTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2006 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.ws.server.endpoint;
+
+import nu.xom.Element;
+
+public class ReflectiveXomPayloadEndpointTest extends AbstractPayloadEndpointTestCase {
+
+ protected PayloadEndpoint createNoResponseEndpoint() throws Exception {
+ return new AbstractXomPayloadEndpoint(true) {
+
+ protected Element invokeInternal(Element requestElement) throws Exception {
+ return null;
+ }
+ };
+ }
+
+ protected PayloadEndpoint createResponseEndpoint() throws Exception {
+ return new AbstractXomPayloadEndpoint(true) {
+
+ protected Element invokeInternal(Element requestElement) throws Exception {
+ assertNotNull("No requestElement passed", requestElement);
+ assertEquals("Invalid request element", REQUEST_ELEMENT, requestElement.getLocalName());
+ assertEquals("Invalid request element", NAMESPACE_URI, requestElement.getNamespaceURI());
+ return new Element(RESPONSE_ELEMENT, NAMESPACE_URI);
+ }
+ };
+ }
+
+
+}