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.
*
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("