From 3daddc2ba225d04ff186accfafef80c84ec7c98c Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Sat, 27 Jan 2007 15:44:02 +0000 Subject: [PATCH] Added XPathPayloadEndpointMapping (#SWS-85) --- .../PayloadRootQNameEndpointMapping.java | 2 +- .../mapping/XPathPayloadEndpointMapping.java | 108 ++++++++++++++++++ .../XPathPayloadEndpointMappingTest.java | 44 +++++++ 3 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/org/springframework/ws/server/endpoint/mapping/XPathPayloadEndpointMapping.java create mode 100644 core/src/test/java/org/springframework/ws/server/endpoint/mapping/XPathPayloadEndpointMappingTest.java diff --git a/core/src/main/java/org/springframework/ws/server/endpoint/mapping/PayloadRootQNameEndpointMapping.java b/core/src/main/java/org/springframework/ws/server/endpoint/mapping/PayloadRootQNameEndpointMapping.java index 69f52981..5ed9ceca 100644 --- a/core/src/main/java/org/springframework/ws/server/endpoint/mapping/PayloadRootQNameEndpointMapping.java +++ b/core/src/main/java/org/springframework/ws/server/endpoint/mapping/PayloadRootQNameEndpointMapping.java @@ -31,7 +31,7 @@ import org.w3c.dom.Element; /** * Implementation of the EndpointMapping interface to map from the qualified name of the request payload * root element. Supports both mapping to bean instances and mapping to bean names: the latter is required for prototype - * handlers. + * endpoints. *

* The endpointMap property is suitable for populating the endpoint map with bean references, e.g. via the * map element in XML bean definitions. diff --git a/core/src/main/java/org/springframework/ws/server/endpoint/mapping/XPathPayloadEndpointMapping.java b/core/src/main/java/org/springframework/ws/server/endpoint/mapping/XPathPayloadEndpointMapping.java new file mode 100644 index 00000000..2c7fcaa9 --- /dev/null +++ b/core/src/main/java/org/springframework/ws/server/endpoint/mapping/XPathPayloadEndpointMapping.java @@ -0,0 +1,108 @@ +/* + * 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. + * 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.mapping; + +import java.util.Properties; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMResult; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; +import org.springframework.ws.WebServiceMessage; +import org.springframework.ws.context.MessageContext; +import org.springframework.xml.xpath.XPathExpression; +import org.springframework.xml.xpath.XPathExpressionFactory; +import org.w3c.dom.Element; + +/** + * Implementation of the EndpointMapping interface that maps to endpoint using an XPath expression. + * Supports both mapping to bean instances and mapping to bean names: the latter is required for prototype endpoints. + *

+ * The XPath expression can be set using the expression property. Setting this property is required. There + * is also an optional namespaces property, which defines to set namespace bindings that are used in the + * expression. + *

+ * The endpointMap property is suitable for populating the endpoint map with bean references, e.g. via the + * map element in XML bean definitions. + *

+ * Mappings to bean names can be set via the mappings property, in a form accepted by the + * java.util.Properties class, like as follows: + *

+ * BookFlight=bookFlightEndpoint
+ * GetFlights=getFlightsEndpoint
+ * 
+ * The syntax is XPATH_EVALUATION=ENDPOINT_BEAN_NAME. The key is the evaluation of the XPath expression for the incoming + * message, the value is the name of the endpoint. + * + * @author Arjen Poutsma + * @see #setExpression(String) + * @see #setNamespaces(java.util.Properties) + */ +public class XPathPayloadEndpointMapping extends AbstractMapBasedEndpointMapping implements InitializingBean { + + private String expressionString; + + private XPathExpression expression; + + private Properties namespaces; + + private TransformerFactory transformerFactory; + + /** + * Sets the XPath expression to be used. + */ + public void setExpression(String expression) { + expressionString = expression; + } + + /** + * Sets the namespaces bindings used in the expression. Keys are prefixes, values are namespaces. + */ + public void setNamespaces(Properties namespaces) { + this.namespaces = namespaces; + } + + public void afterPropertiesSet() throws Exception { + Assert.notNull(expressionString, "expression is required"); + if (namespaces == null) { + expression = XPathExpressionFactory.createXPathExpression(expressionString); + } + else { + expression = XPathExpressionFactory.createXPathExpression(expressionString, namespaces); + } + transformerFactory = TransformerFactory.newInstance(); + } + + protected String getLookupKeyForMessage(MessageContext messageContext) throws Exception { + Element payloadElement = getMessagePayloadElement(messageContext.getRequest()); + return expression.evaluateAsString(payloadElement); + } + + private Element getMessagePayloadElement(WebServiceMessage message) throws TransformerException { + Transformer transformer = transformerFactory.newTransformer(); + DOMResult domResult = new DOMResult(); + transformer.transform(message.getPayloadSource(), domResult); + return (Element) domResult.getNode().getFirstChild(); + } + + protected boolean validateLookupKey(String key) { + return StringUtils.hasLength(key); + } +} diff --git a/core/src/test/java/org/springframework/ws/server/endpoint/mapping/XPathPayloadEndpointMappingTest.java b/core/src/test/java/org/springframework/ws/server/endpoint/mapping/XPathPayloadEndpointMappingTest.java new file mode 100644 index 00000000..ea3c38c4 --- /dev/null +++ b/core/src/test/java/org/springframework/ws/server/endpoint/mapping/XPathPayloadEndpointMappingTest.java @@ -0,0 +1,44 @@ +/* + * 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. + * 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.mapping; + +import junit.framework.TestCase; +import org.springframework.ws.MockWebServiceMessage; +import org.springframework.ws.MockWebServiceMessageFactory; +import org.springframework.ws.context.DefaultMessageContext; +import org.springframework.ws.context.MessageContext; + +public class XPathPayloadEndpointMappingTest extends TestCase { + + private XPathPayloadEndpointMapping mapping; + + protected void setUp() throws Exception { + mapping = new XPathPayloadEndpointMapping(); + } + + public void testGetLookupKeyForMessage() throws Exception { + mapping.setExpression("/root/text()"); + mapping.afterPropertiesSet(); + + MockWebServiceMessage request = new MockWebServiceMessage("value"); + MessageContext context = new DefaultMessageContext(request, new MockWebServiceMessageFactory()); + + String result = mapping.getLookupKeyForMessage(context); + assertNotNull("mapping returns null", result); + assertEquals("mapping returns invalid result", "value", result); + } +} \ No newline at end of file