Working on WS-Addressing

This commit is contained in:
Arjen Poutsma
2007-10-02 00:38:48 +00:00
parent 06ddb6e9e1
commit fb1b92e126
32 changed files with 930 additions and 658 deletions

View File

@@ -35,37 +35,45 @@ import org.springframework.ws.soap.SoapMessage;
import org.springframework.ws.soap.soap11.Soap11Body;
import org.springframework.ws.soap.soap12.Soap12Body;
import org.springframework.ws.soap.soap12.Soap12Fault;
import org.springframework.xml.transform.TransformerObjectSupport;
import org.springframework.xml.xpath.XPathExpression;
import org.springframework.xml.xpath.XPathExpressionFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/** @author Arjen Poutsma */
class AddressingHelper extends TransformerObjectSupport {
/**
* Abstract extension of the {@link AbstractWsAddressingInterceptor} that uses a {@link WsAddressingVersion}.
*
* @author Arjen Poutsma
* @since 1.1.0
*/
abstract class AbstractVersionBasedWsAddressingInterceptor extends AbstractWsAddressingInterceptor {
private final WsAddressingVersion version;
private final XPathExpression toExpression;
private XPathExpression actionExpression;
private final XPathExpression actionExpression;
private XPathExpression messageIdExpression;
private final XPathExpression messageIdExpression;
private XPathExpression fromExpression;
private final XPathExpression fromExpression;
private XPathExpression replyToExpression;
private final XPathExpression replyToExpression;
private XPathExpression faultToExpression;
private final XPathExpression faultToExpression;
private XPathExpression addressExpression;
private final XPathExpression addressExpression;
private XPathExpression referencePropertiesExpression;
private XPathExpression referenceParametersExpression;
public AddressingHelper(WsAddressingVersion version) {
/**
* Creates a new instance of the {@link AbstractVersionBasedWsAddressingInterceptor} with the given {@link
* WsAddressingVersion}.
*/
protected AbstractVersionBasedWsAddressingInterceptor(WsAddressingVersion version) {
this.version = version;
Properties namespaces = new Properties();
namespaces.setProperty(version.getNamespacePrefix(), version.getNamespaceUri());
@@ -99,89 +107,13 @@ class AddressingHelper extends TransformerObjectSupport {
return XPathExpressionFactory.createXPathExpression(expression, namespaces);
}
public MessageAddressingProperties getMessageAddressingProperties(SoapMessage message) throws TransformerException {
Element headerElement = getSoapHeaderElement(message);
String to = toExpression.evaluateAsString(headerElement);
EndpointReference from = getEndpointReference(fromExpression.evaluateAsNode(headerElement));
EndpointReference replyTo = getEndpointReference(replyToExpression.evaluateAsNode(headerElement));
EndpointReference faultTo = getEndpointReference(faultToExpression.evaluateAsNode(headerElement));
String action = actionExpression.evaluateAsString(headerElement);
String messageId = messageIdExpression.evaluateAsString(headerElement);
return new MessageAddressingProperties(to, from, replyTo, faultTo, action, messageId);
public boolean understands(SoapHeaderElement header) {
return version.getNamespaceUri().equals(header.getName().getNamespaceURI());
}
/** Given a ReplyTo, FaultTo, or From node, returns an endpoint reference. */
private EndpointReference getEndpointReference(Node node) {
if (node == null) {
return null;
}
String address = addressExpression.evaluateAsString(node);
if (!StringUtils.hasLength(address)) {
return null;
}
List referenceProperties = referencePropertiesExpression != null ?
referencePropertiesExpression.evaluateAsNodeList(node) : Collections.EMPTY_LIST;
List referenceParameters = referenceParametersExpression != null ?
referenceParametersExpression.evaluateAsNodeList(node) : Collections.EMPTY_LIST;
return new EndpointReference(address, referenceProperties, referenceParameters);
}
public SoapFault addMessageHeaderRequiredFault(SoapMessage message) {
return addAddressingFault(message, version.getMessageHeaderRequiredName(),
version.getMessageHeaderRequiredText());
}
public SoapFault addDestinationUnreachableFault(SoapMessage message) {
return addAddressingFault(message, version.getDestinationUnreachableName(),
version.getDestinationUnreachableText());
}
public SoapFault addActionNotSupportedFault(SoapMessage message, String action) {
return addAddressingFault(message, version.getActionNotSupportedName(),
version.getActionNotSupportedText(action));
}
private SoapFault addAddressingFault(SoapMessage message, QName subcode, String reason) {
if (message.getSoapBody() instanceof Soap11Body) {
Soap11Body soapBody = (Soap11Body) message.getSoapBody();
return soapBody.addFault(subcode, reason, Locale.ENGLISH);
}
else {
Soap12Body soapBody = (Soap12Body) message.getSoapBody();
Soap12Fault soapFault = (Soap12Fault) soapBody.addClientOrSenderFault(reason, Locale.ENGLISH);
soapFault.addFaultSubcode(subcode);
return soapFault;
}
}
private Element getSoapHeaderElement(SoapMessage message) throws TransformerException {
SoapHeader header = message.getSoapHeader();
if (header.getSource() instanceof DOMSource) {
DOMSource domSource = (DOMSource) header.getSource();
if (domSource.getNode() != null && domSource.getNode().getNodeType() == Node.ELEMENT_NODE) {
return (Element) domSource.getNode();
}
}
Transformer transformer = createTransformer();
DOMResult domResult = new DOMResult();
transformer.transform(message.getSoapHeader().getSource(), domResult);
Document document = (Document) domResult.getNode();
return document.getDocumentElement();
}
public boolean hasNoneAddress(EndpointReference reference) {
String none = version.getNoneUri();
return none != null && none.equals(reference.getAddress());
}
public boolean hasAnonymousAddress(EndpointReference reference) {
String anonymous = version.getAnonymousUri();
return anonymous != null && anonymous.equals(reference.getAddress());
}
public void addAddressingHeaders(SoapMessage response, MessageAddressingProperties map)
protected void addAddressingHeaders(SoapMessage message, MessageAddressingProperties map)
throws TransformerException {
SoapHeader header = response.getSoapHeader();
SoapHeader header = message.getSoapHeader();
SoapHeaderElement messageId = header.addHeaderElement(version.getMessageIdName());
messageId.setText(map.getMessageId());
SoapHeaderElement relatesTo = header.addHeaderElement(version.getRelatesToName());
@@ -202,6 +134,101 @@ class AddressingHelper extends TransformerObjectSupport {
}
}
/**
* Adds a Message Addressing Header Required fault to the given message.
*
* @see <a href="http://www.w3.org/TR/ws-addr-soap/#missingmapfault">Message Addressing Header Required</a>
*/
protected SoapFault addMessageAddressingHeaderRequiredFault(SoapMessage message) {
return addAddressingFault(message, version.getMessageAddressingHeaderRequiredFaultSubcode(),
version.getMessageAddressingHeaderRequiredFaultReason());
}
private SoapFault addAddressingFault(SoapMessage message, QName subcode, String reason) {
if (message.getSoapBody() instanceof Soap11Body) {
Soap11Body soapBody = (Soap11Body) message.getSoapBody();
return soapBody.addFault(subcode, reason, Locale.ENGLISH);
}
else if (message.getSoapBody() instanceof Soap12Body) {
Soap12Body soapBody = (Soap12Body) message.getSoapBody();
Soap12Fault soapFault = (Soap12Fault) soapBody.addClientOrSenderFault(reason, Locale.ENGLISH);
soapFault.addFaultSubcode(subcode);
return soapFault;
}
return null;
}
/**
* Returns the {@link MessageAddressingProperties} for the given message.
*
* @param message the message to find the map for
* @return the message addressing properties
*/
protected MessageAddressingProperties getMessageAddressingProperties(SoapMessage message)
throws TransformerException {
Element headerElement = getSoapHeaderElement(message);
String to = toExpression.evaluateAsString(headerElement);
EndpointReference from = getEndpointReference(fromExpression.evaluateAsNode(headerElement));
EndpointReference replyTo = getEndpointReference(replyToExpression.evaluateAsNode(headerElement));
EndpointReference faultTo = getEndpointReference(faultToExpression.evaluateAsNode(headerElement));
String action = actionExpression.evaluateAsString(headerElement);
String messageId = messageIdExpression.evaluateAsString(headerElement);
return new MessageAddressingProperties(to, from, replyTo, faultTo, action, messageId);
}
private Element getSoapHeaderElement(SoapMessage message) throws TransformerException {
SoapHeader header = message.getSoapHeader();
if (header.getSource() instanceof DOMSource) {
DOMSource domSource = (DOMSource) header.getSource();
if (domSource.getNode() != null && domSource.getNode().getNodeType() == Node.ELEMENT_NODE) {
return (Element) domSource.getNode();
}
}
Transformer transformer = createTransformer();
DOMResult domResult = new DOMResult();
transformer.transform(message.getSoapHeader().getSource(), domResult);
Document document = (Document) domResult.getNode();
return document.getDocumentElement();
}
/** Given a ReplyTo, FaultTo, or From node, returns an endpoint reference. */
private EndpointReference getEndpointReference(Node node) {
if (node == null) {
return null;
}
String address = addressExpression.evaluateAsString(node);
if (!StringUtils.hasLength(address)) {
return null;
}
List referenceProperties = referencePropertiesExpression != null ?
referencePropertiesExpression.evaluateAsNodeList(node) : Collections.EMPTY_LIST;
List referenceParameters = referenceParametersExpression != null ?
referenceParametersExpression.evaluateAsNodeList(node) : Collections.EMPTY_LIST;
return new EndpointReference(address, referenceProperties, referenceParameters);
}
/**
* Indicates whether the given endpoint reference has a Anonymous address. This address is used to indicate that a
* message should be sent in-band.
*
* @see <a href="http://www.w3.org/TR/ws-addr-core/#formreplymsg">Formulating a Reply Message</a>
*/
protected boolean hasAnonymousAddress(EndpointReference epr) {
String anonymous = version.getAnonymousUri();
return anonymous != null && anonymous.equals(epr.getAddress());
}
/**
* Indicates whether the given endpoint reference has a None address. Messages to be sent to this address will not
* be sent.
*
* @see <a href="http://www.w3.org/TR/ws-addr-core/#sendmsgepr">Sending a Message to an EPR</a>
*/
protected boolean hasNoneAddress(EndpointReference epr) {
String none = version.getNoneUri();
return none != null && none.equals(epr.getAddress());
}
public boolean supports(SoapMessage message) {
SoapHeader header = message.getSoapHeader();
if (header != null) {
@@ -213,10 +240,5 @@ class AddressingHelper extends TransformerObjectSupport {
}
}
return false;
}
public boolean understands(SoapHeaderElement header) {
return version.getNamespaceUri().equals(header.getName().getNamespaceURI());
}
}
}

View File

@@ -0,0 +1,142 @@
package org.springframework.ws.soap.addressing;
import java.io.IOException;
import javax.xml.transform.TransformerException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.soap.SoapFault;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.ws.soap.addressing.messageid.MessageIdProvider;
import org.springframework.ws.soap.server.SoapEndpointInterceptor;
import org.springframework.ws.transport.WebServiceConnection;
import org.springframework.ws.transport.WebServiceMessageSender;
import org.springframework.xml.transform.TransformerObjectSupport;
/** @author Arjen Poutsma */
public abstract class AbstractWsAddressingInterceptor extends TransformerObjectSupport
implements SoapEndpointInterceptor {
/** Logger available for subclasses. */
protected final Log logger = LogFactory.getLog(getClass());
private MessageIdProvider messageIdProvider;
private WebServiceMessageSender[] messageSenders = new WebServiceMessageSender[0];
public final void setMessageIdProvider(MessageIdProvider messageIdProvider) {
this.messageIdProvider = messageIdProvider;
}
public final boolean handleRequest(MessageContext messageContext, Object endpoint) throws Exception {
Assert.isTrue(messageContext.getRequest() instanceof SoapMessage,
"WsAddressingInterceptor requires a SoapMessage request");
SoapMessage request = (SoapMessage) messageContext.getRequest();
MessageAddressingProperties requestMap = getMessageAddressingProperties(request);
if (!requestMap.isValid()) {
addMessageAddressingHeaderRequiredFault((SoapMessage) messageContext.getResponse());
return false;
}
return true;
}
public final boolean handleResponse(MessageContext messageContext, Object endpoint) throws Exception {
return handleResponseOrFault(messageContext);
}
public boolean handleFault(MessageContext messageContext, Object endpoint) throws Exception {
return handleResponseOrFault(messageContext);
}
/**
* Adds a Message Addressing Header Required fault to the given message.
*
* @see <a href="http://www.w3.org/TR/ws-addr-soap/#missingmapfault">Message Addressing Header Required</a>
*/
protected abstract SoapFault addMessageAddressingHeaderRequiredFault(SoapMessage message);
private boolean handleResponseOrFault(MessageContext messageContext) throws Exception {
Assert.isTrue(messageContext.getRequest() instanceof SoapMessage &&
messageContext.getResponse() instanceof SoapMessage,
"WsAddressingInterceptor requires a SoapMessage request and response");
SoapMessage request = (SoapMessage) messageContext.getRequest();
MessageAddressingProperties requestMap = getMessageAddressingProperties(request);
SoapMessage response = (SoapMessage) messageContext.getResponse();
EndpointReference responseEpr = response.hasFault() ? requestMap.getFaultTo() : requestMap.getReplyTo();
if (responseEpr == null || hasNoneAddress(responseEpr)) {
logger.debug("Request has none reply address");
return false;
}
String responseMessageId = messageIdProvider.getMessageId(response);
if (logger.isDebugEnabled()) {
logger.debug("Generated reply MessageID [" + responseMessageId + "]");
}
MessageAddressingProperties replyMap = requestMap.getResponseProperties(responseEpr, null, responseMessageId);
addAddressingHeaders(response, replyMap);
if (hasAnonymousAddress(responseEpr)) {
logger.debug("Request has anonymous reply address");
return true;
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Sending reply message to EPR address [" + responseEpr.getAddress() + "]");
}
sendOutOfBand(responseEpr.getAddress(), response);
return false;
}
}
private void sendOutOfBand(String uri, SoapMessage message) throws IOException {
boolean supported = false;
for (int i = 0; i < messageSenders.length; i++) {
if (messageSenders[i].supports(uri)) {
supported = true;
WebServiceConnection connection = null;
try {
connection = messageSenders[i].createConnection(uri);
connection.send(message);
break;
}
finally {
if (connection != null) {
connection.close();
}
}
}
}
if (!supported) {
throw new IllegalArgumentException("Could not resolve [" + uri + "] to a WebServiceMessageSender");
}
}
/**
* Returns the {@link MessageAddressingProperties} for the given message.
*
* @param message the message to find the map for
* @return the message addressing properties
*/
protected abstract MessageAddressingProperties getMessageAddressingProperties(SoapMessage message)
throws TransformerException;
/**
* Indicates whether the given endpoint reference has a None address. Messages to be sent to this address will not
* be sent.
*
* @see <a href="http://www.w3.org/TR/ws-addr-core/#sendmsgepr">Sending a Message to an EPR</a>
*/
protected abstract boolean hasNoneAddress(EndpointReference epr);
/**
* Indicates whether the given endpoint reference has a Anonymous address. This address is used to indicate that a
* message should be sent in-band.
*
* @see <a href="http://www.w3.org/TR/ws-addr-core/#formreplymsg">Formulating a Reply Message</a>
*/
protected abstract boolean hasAnonymousAddress(EndpointReference epr);
protected abstract void addAddressingHeaders(SoapMessage message, MessageAddressingProperties map)
throws TransformerException;
}

View File

@@ -16,6 +16,7 @@
package org.springframework.ws.soap.addressing;
import java.util.Iterator;
import javax.xml.transform.TransformerException;
import org.springframework.core.JdkVersion;
@@ -23,6 +24,9 @@ import org.springframework.util.Assert;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.EndpointInterceptor;
import org.springframework.ws.server.EndpointInvocationChain;
import org.springframework.ws.server.EndpointMapping;
import org.springframework.ws.soap.SoapHeader;
import org.springframework.ws.soap.SoapHeaderElement;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.ws.soap.addressing.messageid.MessageIdProvider;
import org.springframework.ws.soap.addressing.messageid.UidMessageIdProvider;
@@ -32,7 +36,10 @@ import org.springframework.ws.soap.server.SoapEndpointMapping;
import org.springframework.xml.transform.TransformerObjectSupport;
/**
* Abstract base class for {@link EndpointMapping} implementations that implement WS-Addressing.
*
* @author Arjen Poutsma
* @since 1.1.0
*/
public abstract class AbstractWsAddressingMapping extends TransformerObjectSupport implements SoapEndpointMapping {
@@ -42,18 +49,16 @@ public abstract class AbstractWsAddressingMapping extends TransformerObjectSuppo
private MessageIdProvider messageIdProvider;
private AddressingHelper[] helpers = new AddressingHelper[]{new AddressingHelper(new WsAddressing200408())};
private AbstractWsAddressingInterceptor[] addressingInterceptors;
private EndpointInterceptor[] preInterceptors;
private EndpointInterceptor[] postInterceptors;
private static final Object MISSING_HEADER_ENDPOINT = new Object();
/**
* Protected constructor
*/
/** Protected constructor */
protected AbstractWsAddressingMapping() {
addressingInterceptors = new AbstractWsAddressingInterceptor[]{new WsAddressing200408Interceptor(),
new WsAddressing200508Interceptor()};
if (JdkVersion.getMajorJavaVersion() >= JdkVersion.JAVA_15) {
messageIdProvider = new UuidMessageIdProvider();
}
@@ -77,47 +82,100 @@ public abstract class AbstractWsAddressingMapping extends TransformerObjectSuppo
}
/**
* Sets the message id provider used for creating WS-Addressing MessageIds. By default, the {@link
* UuidMessageIdProvider} is used on Java 5 and higher, and the {@link UidMessageIdProvider} on Java 1.4 and lower.
* Set additional interceptors to be applied before the implicit WS-Addressing interceptor, e.g.
* <code>XwsSecurityInterceptor</code>.
*/
public final void setPreInterceptors(EndpointInterceptor[] preInterceptors) {
this.preInterceptors = preInterceptors;
}
/**
* Set additional interceptors to be applied after the implicit WS-Addressing interceptor, e.g.
* <code>PayloadLoggingInterceptor</code>.
*/
public final void setPostInterceptors(EndpointInterceptor[] postInterceptors) {
this.postInterceptors = postInterceptors;
}
/**
* Sets the message id provider used for creating WS-Addressing MessageIds.
* <p/>
* By default, the {@link UuidMessageIdProvider} is used on Java 5 and higher, and the {@link UidMessageIdProvider}
* on Java 1.4 and lower.
*/
public final void setMessageIdProvider(MessageIdProvider messageIdProvider) {
this.messageIdProvider = messageIdProvider;
}
public final void setVersions(WsAddressingVersion[] versions) {
Assert.notEmpty(versions, "specifications must not be empty");
this.helpers = new AddressingHelper[versions.length];
for (int i = 0; i < versions.length; i++) {
this.helpers[i] = new AddressingHelper(versions[i]);
}
/**
* Sets the WS-Addressing interceptors to be supported by this mapping.
* <p/>
* By default, this includes the {@link WsAddressing200408Interceptor}, and the {@link
* WsAddressing200508Interceptor}.
*/
public final void setAddressingInterceptors(AbstractWsAddressingInterceptor[] addressingInterceptors) {
Assert.notEmpty(addressingInterceptors, "'addressingInterceptors' must not be empty");
this.addressingInterceptors = addressingInterceptors;
}
public final EndpointInvocationChain getEndpoint(MessageContext messageContext) throws TransformerException {
Assert.isTrue(messageContext.getResponse() instanceof SoapMessage,
"WsAddressingMapping requires a SoapMessage request");
SoapMessage request = (SoapMessage) messageContext.getRequest();
for (int i = 0; i < helpers.length; i++) {
if (!helpers[i].supports(request)) {
for (int i = 0; i < addressingInterceptors.length; i++) {
AbstractWsAddressingInterceptor interceptor = addressingInterceptors[i];
if (!understands(interceptor, request)) {
continue;
}
MessageAddressingProperties map = helpers[i].getMessageAddressingProperties(request);
Object endpoint;
if (map.isValid()) {
endpoint = getEndpointInternal(map);
}
else {
// Set a 'fake' endpoint, so that the invocation will continue, but result in a MissingHeader fault
// returned by the interceptor
endpoint = MISSING_HEADER_ENDPOINT;
MessageAddressingProperties requestMap = interceptor.getMessageAddressingProperties(request);
if (requestMap == null) {
return null;
}
Object endpoint = getEndpointInternal(requestMap);
if (endpoint == null) {
return null;
}
return new SoapEndpointInvocationChain(endpoint, null, actorsOrRoles, isUltimateReceiver);
return new SoapEndpointInvocationChain(endpoint, getAllEndpointInterceptors(interceptor), actorsOrRoles,
isUltimateReceiver);
}
return null;
}
private boolean understands(AbstractWsAddressingInterceptor interceptor, SoapMessage request) {
SoapHeader header = request.getSoapHeader();
if (header != null) {
for (Iterator iterator = header.examineAllHeaderElements(); iterator.hasNext();) {
SoapHeaderElement headerElement = (SoapHeaderElement) iterator.next();
if (interceptor.understands(headerElement)) {
return true;
}
}
}
return false;
}
protected EndpointInterceptor[] getAllEndpointInterceptors(AbstractWsAddressingInterceptor interceptor) {
if (preInterceptors == null) {
preInterceptors = new EndpointInterceptor[0];
}
if (postInterceptors == null) {
postInterceptors = new EndpointInterceptor[0];
}
EndpointInterceptor[] interceptors =
new EndpointInterceptor[preInterceptors.length + postInterceptors.length + 1];
System.arraycopy(preInterceptors, 0, interceptors, 0, preInterceptors.length);
interceptors[preInterceptors.length] = interceptor;
System.arraycopy(postInterceptors, 0, interceptors, preInterceptors.length + 1, postInterceptors.length);
return interceptors;
}
/**
* Lookup an endpoint for the given {@link MessageAddressingProperties}, returning <code>null</code> if no specific
* one is found. This template method is called by {@link #getEndpoint(MessageContext)}.
*
* @param map the message addressing properties
* @return the endpoint, or <code>null</code>
*/
protected abstract Object getEndpointInternal(MessageAddressingProperties map);

View File

@@ -0,0 +1,72 @@
package org.springframework.ws.soap.addressing;
import javax.xml.namespace.QName;
/**
* Abstract implementation of the {@link WsAddressingVersion} interface.
*
* @author Arjen Poutsma
*/
public abstract class AbstractWsAddressingVersion implements WsAddressingVersion {
public String getNamespacePrefix() {
return "wsa";
}
/*
* Message addressing properties
*/
public QName getToName() {
return new QName(getNamespaceUri(), "To", getNamespacePrefix());
}
public QName getFromName() {
return new QName(getNamespaceUri(), "From", getNamespacePrefix());
}
public QName getReplyToName() {
return new QName(getNamespaceUri(), "ReplyTo", getNamespacePrefix());
}
public QName getFaultToName() {
return new QName(getNamespaceUri(), "FaultTo", getNamespacePrefix());
}
public QName getActionName() {
return new QName(getNamespaceUri(), "Action", getNamespacePrefix());
}
public QName getMessageIdName() {
return new QName(getNamespaceUri(), "MessageID", getNamespacePrefix());
}
public QName getRelatesToName() {
return new QName(getNamespaceUri(), "RelatesTo", getNamespacePrefix());
}
public QName getRelationshipTypeName() {
return new QName(getNamespaceUri(), "RelationshipType", getNamespacePrefix());
}
public QName getReferencePropertiesName() {
return new QName(getNamespaceUri(), "ReferenceProperties", getNamespacePrefix());
}
public QName getReferenceParametersName() {
return new QName(getNamespaceUri(), "ReferenceParameters", getNamespacePrefix());
}
/*
* Endpoint Reference
*/
public QName getAddressName() {
return new QName(getNamespaceUri(), "Address", getNamespacePrefix());
}
public QName getMetadataName() {
return new QName(getNamespaceUri(), "Metadata", getNamespacePrefix());
}
}

View File

@@ -20,9 +20,18 @@ import java.util.Collections;
import java.util.List;
import org.springframework.util.Assert;
import org.w3c.dom.Node;
/** @author Arjen Poutsma */
public class EndpointReference {
/**
* Represents a set of Message Addressing Properties, as defined in the WS-Addressing specification.
* <p/>
* In earlier versions of the spec, these properties were called Message Information Headers.
*
* @author Arjen Poutsma
* @see <a href="http://www.w3.org/TR/ws-addr-core/#eprs">Endpoint References</a>
* @since 1.1.0
*/
public final class EndpointReference {
private final String address;
@@ -30,12 +39,26 @@ public class EndpointReference {
private final List referenceParameters;
/**
* Creates a new instance of the {@link EndpointReference} class with the given address. The reference parameters
* and properties are empty.
*
* @param address the endpoint address
*/
public EndpointReference(String address) {
this.address = address;
this.referenceParameters = Collections.EMPTY_LIST;
this.referenceProperties = Collections.EMPTY_LIST;
}
/**
* Creates a new instance of the {@link EndpointReference} class with the given address, reference properties, and
* reference paramters.
*
* @param address the endpoint address
* @param referenceProperties the reference properties, as a list of {@link Node}
* @param referenceProperties the reference parameters, as a list of {@link Node}
*/
public EndpointReference(String address, List referenceProperties, List referenceParameters) {
Assert.notNull(address, "address must not be null");
Assert.notNull(referenceProperties, "referenceProperties must not be null");
@@ -45,14 +68,17 @@ public class EndpointReference {
this.referenceParameters = referenceParameters;
}
/** Returns the address of the endpoint. */
public String getAddress() {
return address;
}
/** Returns the reference properties of the endpoint, as a list of {@link Node} objects. */
public List getReferenceProperties() {
return referenceProperties;
}
/** Returns the reference parameters of the endpoint, as a list of {@link Node} objects. */
public List getReferenceParameters() {
return referenceParameters;
}

View File

@@ -28,8 +28,9 @@ import org.springframework.util.StringUtils;
*
* @author Arjen Poutsma
* @see <a href="http://www.w3.org/TR/ws-addr-core/#msgaddrprops">Message Addressing Properties</a>
* @since 1.1.0
*/
public class MessageAddressingProperties {
public final class MessageAddressingProperties {
private final String to;
@@ -49,6 +50,7 @@ public class MessageAddressingProperties {
private final List referenceParameters;
/*
public MessageAddressingProperties(String to, EndpointReference replyTo, String action, String messageId) {
this.to = to;
this.replyTo = replyTo;
@@ -60,6 +62,7 @@ public class MessageAddressingProperties {
this.referenceProperties = Collections.EMPTY_LIST;
this.referenceParameters = Collections.EMPTY_LIST;
}
*/
public MessageAddressingProperties(String to,
EndpointReference from,
@@ -78,12 +81,13 @@ public class MessageAddressingProperties {
this.referenceParameters = Collections.EMPTY_LIST;
}
/*
private MessageAddressingProperties(String to,
String action,
String messageId,
String relatesTo,
List referenceProperties,
List referenceParameters) {
String action,
String messageId,
String relatesTo,
List referenceProperties,
List referenceParameters) {
this.to = to;
this.action = action;
this.messageId = messageId;
@@ -94,6 +98,19 @@ public class MessageAddressingProperties {
this.replyTo = null;
this.faultTo = null;
}
*/
private MessageAddressingProperties(EndpointReference epr, String action, String messageId, String relatesTo) {
this.to = epr.getAddress();
this.action = action;
this.messageId = messageId;
this.relatesTo = relatesTo;
this.referenceParameters = epr.getReferenceParameters();
this.referenceProperties = epr.getReferenceProperties();
this.from = null;
this.replyTo = null;
this.faultTo = null;
}
public String getTo() {
return to;
@@ -124,13 +141,17 @@ public class MessageAddressingProperties {
}
public List getReferenceProperties() {
return referenceProperties;
return Collections.unmodifiableList(referenceProperties);
}
public List getReferenceParameters() {
return referenceParameters;
return Collections.unmodifiableList(referenceParameters);
}
/**
* Indicates whether the given {@link MessageAddressingProperties} are valid, i.e. whether all required elements are
* listed.
*/
public boolean isValid() {
return StringUtils.hasLength(to) && StringUtils.hasLength(action) &&
!(replyTo != null && !StringUtils.hasLength(messageId)) &&
@@ -138,8 +159,8 @@ public class MessageAddressingProperties {
}
public MessageAddressingProperties getReplyProperties(EndpointReference epr, String action, String messageId) {
return new MessageAddressingProperties(epr.getAddress(), action, messageId, this.messageId,
epr.getReferenceProperties(), epr.getReferenceParameters());
public MessageAddressingProperties getResponseProperties(EndpointReference epr, String action, String messageId) {
return new MessageAddressingProperties(epr, action, messageId, this.messageId);
}
}

View File

@@ -1,95 +0,0 @@
/*
* 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.soap.addressing;
import javax.xml.transform.TransformerException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.soap.SoapHeaderElement;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.ws.soap.addressing.messageid.MessageIdProvider;
import org.springframework.ws.soap.server.SoapEndpointInterceptor;
/** @author Arjen Poutsma */
class StatefulAddressingInterceptor implements SoapEndpointInterceptor {
private static final Log logger = LogFactory.getLog(StatefulAddressingInterceptor.class);
private final AddressingHelper helper;
private final MessageIdProvider messageIdProvider;
private final MessageAddressingProperties requestMap;
public StatefulAddressingInterceptor(AddressingHelper helper,
MessageIdProvider messageIdProvider,
MessageAddressingProperties map) {
this.helper = helper;
this.messageIdProvider = messageIdProvider;
this.requestMap = map;
}
public boolean understands(SoapHeaderElement header) {
return helper.understands(header);
}
public boolean handleRequest(MessageContext messageContext, Object endpoint) throws Exception {
if (!requestMap.isValid()) {
helper.addMessageHeaderRequiredFault((SoapMessage) messageContext.getResponse());
return false;
}
return true;
}
public boolean handleResponse(MessageContext messageContext, Object endpoint) throws Exception {
SoapMessage response = (SoapMessage) messageContext.getResponse();
return handleReturnMessage(response, requestMap.getReplyTo());
}
public boolean handleFault(MessageContext messageContext, Object endpoint) throws Exception {
SoapMessage response = (SoapMessage) messageContext.getResponse();
return handleReturnMessage(response, requestMap.getFaultTo());
}
private boolean handleReturnMessage(SoapMessage response, EndpointReference epr) throws TransformerException {
if (epr == null || helper.hasNoneAddress(epr)) {
logger.debug("Request has no response address");
return false;
}
String replyMessageId = messageIdProvider.getMessageId(response);
if (logger.isDebugEnabled()) {
logger.debug("Generated response MessageID [" + replyMessageId + "]");
}
MessageAddressingProperties replyMap = requestMap.getReplyProperties(epr, null, replyMessageId);
helper.addAddressingHeaders(response, replyMap);
if (helper.hasAnonymousAddress(epr)) {
logger.debug("Request has anonymous response address");
return true;
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Sending response message to EPR address [" + epr.getAddress() + "]");
}
// TODO: send the message
throw new UnsupportedOperationException("Sending to out-of-band EPR not supported");
}
}
}

View File

@@ -1,159 +0,0 @@
/*
* 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.soap.addressing;
import javax.xml.namespace.QName;
/**
* Implements the August 2004 edition of the WS-Addressing specification. This version of the specification is used by
* Microsoft's Web Services Enhancements (WSE) 3.0.
*
* @author Arjen Poutsma
* @see <a href="http://msdn.microsoft.com/ws/2004/08/ws-addressing/">Web Services Addressing, August 2004</a>
* @see <a href="http://msdn.microsoft.com/webservices/webservices/building/wse/">Web Services Enhancements</a>
*/
public class WsAddressing200408 implements WsAddressingVersion {
private static final String NAMESPACE_URI = "http://schemas.xmlsoap.org/ws/2004/08/addressing";
private static final String NAMESPACE_PREFIX = "wsa";
private static final QName TO = new QName(NAMESPACE_URI, "To", NAMESPACE_PREFIX);
private static final QName REPLY_TO = new QName(NAMESPACE_URI, "ReplyTo", NAMESPACE_PREFIX);
private static final QName FROM = new QName(NAMESPACE_URI, "From", NAMESPACE_PREFIX);
private static final QName FAULT_TO = new QName(NAMESPACE_URI, "FaultTo", NAMESPACE_PREFIX);
private static final QName ACTION = new QName(NAMESPACE_URI, "Action", NAMESPACE_PREFIX);
private static final QName MESSAGE_ID = new QName(NAMESPACE_URI, "MessageID", NAMESPACE_PREFIX);
private static final QName RELATES_TO = new QName(NAMESPACE_URI, "RelatesTo", NAMESPACE_PREFIX);
private static final QName RELATIONSHIP_REPLY = new QName(NAMESPACE_URI, "Reply", NAMESPACE_PREFIX);
private static final QName RELATIONSHIP_TYPE = new QName(NAMESPACE_URI, "RelationshipType", NAMESPACE_PREFIX);
private static final QName MESSAGE_INFORMATION_HEADER_REQUIRED =
new QName(NAMESPACE_URI, "MessageInformationHeaderRequired", NAMESPACE_PREFIX);
private static final QName DESTINATION_UNREACHABLE =
new QName(NAMESPACE_URI, "DestinationUnreachable", NAMESPACE_PREFIX);
private static final QName ACTION_NOT_SUPPORTED_NAME =
new QName(NAMESPACE_URI, "ActionNotSupported", NAMESPACE_PREFIX);
private static final QName ADDRESS = new QName(NAMESPACE_URI, "Address", NAMESPACE_PREFIX);
private static final QName REFERENCE_PARAMETERS = new QName(NAMESPACE_URI, "ReferenceParameters", NAMESPACE_PREFIX);
private static final QName REFERENCE_PROPERTIES = new QName(NAMESPACE_URI, "ReferenceProperties", NAMESPACE_PREFIX);
public String getNamespaceUri() {
return NAMESPACE_URI;
}
public String getNamespacePrefix() {
return NAMESPACE_PREFIX;
}
public String getAnonymousUri() {
return NAMESPACE_URI + "/role/anonymous";
}
public String getNoneUri() {
return null;
}
public QName getToName() {
return TO;
}
public QName getFromName() {
return FROM;
}
public QName getReplyToName() {
return REPLY_TO;
}
public QName getFaultToName() {
return FAULT_TO;
}
public QName getActionName() {
return ACTION;
}
public QName getMessageIdName() {
return MESSAGE_ID;
}
public QName getRelatesToName() {
return RELATES_TO;
}
public QName getRelationshipReplyName() {
return RELATIONSHIP_REPLY;
}
public QName getAddressName() {
return ADDRESS;
}
public QName getRelationshipTypeName() {
return RELATIONSHIP_TYPE;
}
public QName getReferenceParametersName() {
return REFERENCE_PARAMETERS;
}
public QName getReferencePropertiesName() {
return REFERENCE_PROPERTIES;
}
public QName getMessageHeaderRequiredName() {
return MESSAGE_INFORMATION_HEADER_REQUIRED;
}
public String getMessageHeaderRequiredText() {
return "A required message information header, To, MessageID, or Action, is not present.";
}
public QName getDestinationUnreachableName() {
return DESTINATION_UNREACHABLE;
}
public String getDestinationUnreachableText() {
return "No route can be determined to reach the destination role defined by the WS-Addressing To.";
}
public QName getActionNotSupportedName() {
return ACTION_NOT_SUPPORTED_NAME;
}
public String getActionNotSupportedText(String action) {
return "The " + action + " cannot be processed at the receiver.";
}
public String toString() {
return NAMESPACE_URI;
}
}

View File

@@ -0,0 +1,60 @@
package org.springframework.ws.soap.addressing;
import javax.xml.namespace.QName;
/**
* Implements the August 2004 edition of the WS-Addressing specification. This version of the specification is used by
* Microsoft's Web Services Enhancements (WSE) 3.0.
*
* @author Arjen Poutsma
* @see <a href="http://msdn.microsoft.com/ws/2004/08/ws-addressing/">Web Services Addressing, August 2004</a>
* @see <a href="http://msdn.microsoft.com/webservices/webservices/building/wse/">Web Services Enhancements</a>
* @since 1.1.0
*/
public class WsAddressing200408Interceptor extends AbstractVersionBasedWsAddressingInterceptor {
protected WsAddressing200408Interceptor() {
super(new WsAddressing200408());
}
private static class WsAddressing200408 extends AbstractWsAddressingVersion {
private static final String NAMESPACE_URI = "http://schemas.xmlsoap.org/ws/2004/08/addressing";
public String getNamespaceUri() {
return NAMESPACE_URI;
}
/*
* Message addressing properties
*/
public String getRelationshipReply() {
return getNamespacePrefix() + ":Reply";
}
/*
* Address URIs
*/
public String getAnonymousUri() {
return NAMESPACE_URI + "/role/anonymous";
}
public String getNoneUri() {
return null;
}
/*
* Faults
*/
public QName getMessageAddressingHeaderRequiredFaultSubcode() {
return new QName(NAMESPACE_URI, "MessageInformationHeaderRequired", getNamespacePrefix());
}
public String getMessageAddressingHeaderRequiredFaultReason() {
return "A required message information header, To, MessageID, or Action, is not present.";
}
}
}

View File

@@ -0,0 +1,58 @@
package org.springframework.ws.soap.addressing;
import javax.xml.namespace.QName;
/** @author Arjen Poutsma */
public class WsAddressing200508Interceptor extends AbstractVersionBasedWsAddressingInterceptor {
public WsAddressing200508Interceptor() {
super(new WsAddressing200508());
}
private static class WsAddressing200508 extends AbstractWsAddressingVersion {
private static final String NAMESPACE_URI = "http://www.w3.org/2005/08/addressing";
public String getNamespaceUri() {
return NAMESPACE_URI;
}
/*
* Message addressing properties
*/
public String getRelationshipReply() {
return "http://www.w3.org/2005/08/addressing/reply";
}
public QName getReferencePropertiesName() {
return null;
}
/*
* Address URIs
*/
public String getAnonymousUri() {
return NAMESPACE_URI + "/anonymous";
}
public String getNoneUri() {
return NAMESPACE_URI + "/none";
}
/*
* Faults
*/
public QName getMessageAddressingHeaderRequiredFaultSubcode() {
return new QName(NAMESPACE_URI, "MessageAddressingHeaderRequired", getNamespacePrefix());
}
public String getMessageAddressingHeaderRequiredFaultReason() {
return "A required header representing a Message Addressing Property is not present";
}
}
}

View File

@@ -31,11 +31,9 @@ public interface WsAddressingVersion {
/** Returns the prefix associated with the WS-Addressing namespace handled by this specification. */
String getNamespacePrefix();
/** Returns the anonymous URI. */
String getAnonymousUri();
/** Returns the none URI, or <code>null</code> if the spec does not define it. */
String getNoneUri();
/*
* Message addressing properties
*/
/** Returns the qualified name of the <code>To</code> addressing header. */
QName getToName();
@@ -61,7 +59,7 @@ public interface WsAddressingVersion {
/**
* Returns the qualified name of the <code>Relationship</code> addressing attribute.
*
* @see #getRelationshipReplyName()
* @see #getRelationshipReply()
*/
QName getRelationshipTypeName();
@@ -70,7 +68,7 @@ public interface WsAddressingVersion {
*
* @see #getRelationshipTypeName()
*/
QName getRelationshipReplyName();
String getRelationshipReply();
/**
* Returns the qualified name of the <code>ReferenceProperties</code> in the endpoint reference. Returns
@@ -84,24 +82,34 @@ public interface WsAddressingVersion {
*/
QName getReferenceParametersName();
/*
* Endpoint Reference
*/
/** The qualified name of the <code>Address</code> in <code>EndpointReference</code>. */
QName getAddressName();
/** The qualified name of the <code>Metadata</code> in <code>EndpointReference</code>. */
QName getMetadataName();
/*
* Address URIs
*/
/** Returns the anonymous URI. */
String getAnonymousUri();
/** Returns the none URI, or <code>null</code> if the spec does not define it. */
String getNoneUri();
/*
* Faults
*/
/** Returns the qualified name of the fault subcode that indicates that a header is missing. */
QName getMessageHeaderRequiredName();
QName getMessageAddressingHeaderRequiredFaultSubcode();
/** Returns the text of the fault that indicates that a header is missing. */
String getMessageHeaderRequiredText();
/** Returns the reason of the fault that indicates that a header is missing. */
String getMessageAddressingHeaderRequiredFaultReason();
/** Returns the qualified name of the <code>DestinationUnreachable</code> fault subcode. */
QName getDestinationUnreachableName();
/** Returns the text of the <code>DestinationUnreachable</code> fault. */
String getDestinationUnreachableText();
/** Returns the qualified name of the <code>ActionNotSupported</code> fault subcode. */
QName getActionNotSupportedName();
/** Returns the text of the <code>ActionNotSupported</code> fault. */
String getActionNotSupportedText(String action);
}

View File

@@ -27,7 +27,6 @@ import org.springframework.ws.soap.SoapMessage;
* Note that the {@link UUID} class is only available on Java 5 and above.
*
* @author Arjen Poutsma
* @see java.util.UUID
*/
public class UuidMessageIdProvider implements MessageIdProvider {

View File

@@ -0,0 +1,103 @@
package org.springframework.ws.soap.addressing;
import java.util.Iterator;
import org.easymock.MockControl;
import org.springframework.ws.context.DefaultMessageContext;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.soap.SoapHeaderElement;
import org.springframework.ws.soap.addressing.messageid.MessageIdProvider;
import org.springframework.ws.soap.saaj.SaajSoapMessage;
import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
public abstract class AbstractWsAddressingInterceptorTestCase extends AbstractWsAddressingTestCase {
protected AbstractWsAddressingInterceptor interceptor;
private MockControl providerControl;
private MessageIdProvider providerMock;
protected final void onSetUp() throws Exception {
providerControl = MockControl.createControl(MessageIdProvider.class);
providerMock = (MessageIdProvider) providerControl.getMock();
interceptor = createInterceptor();
interceptor.setMessageIdProvider(providerMock);
}
public void testUnderstands() throws Exception {
SaajSoapMessage validRequest = loadSaajMessage(getTestPath() + "/valid.xml");
Iterator iterator = validRequest.getSoapHeader().examineAllHeaderElements();
providerControl.replay();
while (iterator.hasNext()) {
SoapHeaderElement headerElement = (SoapHeaderElement) iterator.next();
assertTrue("Header [" + headerElement.getName() + " not understood",
interceptor.understands(headerElement));
}
providerControl.verify();
}
public void testHandleValidRequest() throws Exception {
SaajSoapMessage valid = loadSaajMessage(getTestPath() + "/valid.xml");
MessageContext context = new DefaultMessageContext(valid, new SaajSoapMessageFactory(messageFactory));
providerControl.replay();
boolean result = interceptor.handleRequest(context, null);
assertTrue("Valid request not handled", result);
assertFalse("Message Context has response", context.hasResponse());
providerControl.verify();
}
public void testHandleInvalidRequest() throws Exception {
SaajSoapMessage valid = loadSaajMessage(getTestPath() + "/invalid.xml");
MessageContext context = new DefaultMessageContext(valid, new SaajSoapMessageFactory(messageFactory));
providerControl.replay();
boolean result = interceptor.handleRequest(context, null);
assertFalse("Invalid request handled", result);
assertTrue("Message Context has no response", context.hasResponse());
SaajSoapMessage expectedResponse = loadSaajMessage(getTestPath() + "/response-invalid.xml");
assertXMLEqual("Invalid response for message with invalid MAP", expectedResponse,
(SaajSoapMessage) context.getResponse());
providerControl.verify();
}
public void testHandleAnonymousReplyTo() throws Exception {
SaajSoapMessage valid = loadSaajMessage(getTestPath() + "/anonymous.xml");
MessageContext context = new DefaultMessageContext(valid, new SaajSoapMessageFactory(messageFactory));
SaajSoapMessage response = (SaajSoapMessage) context.getResponse();
String messageId = "uid:1234";
providerControl.expectAndReturn(providerMock.getMessageId(response), messageId);
providerControl.replay();
boolean result = interceptor.handleResponse(context, null);
assertTrue("Anonymous request not handled", result);
SaajSoapMessage expectedResponse = loadSaajMessage(getTestPath() + "/response-anonymous.xml");
assertXMLEqual("Invalid response for message with invalid MAP", expectedResponse,
(SaajSoapMessage) context.getResponse());
providerControl.verify();
}
public void testHandleNoneReplyTo() throws Exception {
SaajSoapMessage valid = loadSaajMessage(getTestPath() + "/none.xml");
MessageContext context = new DefaultMessageContext(valid, new SaajSoapMessageFactory(messageFactory));
providerControl.replay();
boolean result = interceptor.handleResponse(context, null);
assertFalse("None request handled", result);
providerControl.verify();
}
public void testHandleOutOfBandReplyTo() throws Exception {
SaajSoapMessage valid = loadSaajMessage(getTestPath() + "/valid.xml");
MessageContext context = new DefaultMessageContext(valid, new SaajSoapMessageFactory(messageFactory));
SaajSoapMessage response = (SaajSoapMessage) context.getResponse();
String messageId = "uid:1234";
providerControl.expectAndReturn(providerMock.getMessageId(response), messageId);
providerControl.replay();
boolean result = interceptor.handleResponse(context, null);
assertFalse("Out of Band request handled", result);
providerControl.verify();
}
protected abstract AbstractWsAddressingInterceptor createInterceptor();
protected abstract String getTestPath();
}

View File

@@ -24,15 +24,17 @@ import javax.xml.soap.SOAPConstants;
import javax.xml.soap.SOAPException;
import org.custommonkey.xmlunit.XMLTestCase;
import org.custommonkey.xmlunit.XMLUnit;
import org.springframework.ws.soap.saaj.SaajSoapMessage;
import org.w3c.dom.Document;
/** @author Arjen Poutsma */
public abstract class AbstractWsAddressingTestCase extends XMLTestCase {
protected MessageFactory messageFactory;
protected final void setUp() throws Exception {
messageFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_2_PROTOCOL);
XMLUnit.setIgnoreWhitespace(true);
onSetUp();
}
@@ -43,6 +45,7 @@ public abstract class AbstractWsAddressingTestCase extends XMLTestCase {
MimeHeaders mimeHeaders = new MimeHeaders();
mimeHeaders.addHeader("Content-Type", " application/soap+xml");
InputStream is = getClass().getResourceAsStream(fileName);
assertNotNull("Could not load " + fileName, is);
try {
return new SaajSoapMessage(messageFactory.createMessage(mimeHeaders, is));
}
@@ -50,4 +53,10 @@ public abstract class AbstractWsAddressingTestCase extends XMLTestCase {
is.close();
}
}
protected void assertXMLEqual(String message, SaajSoapMessage expected, SaajSoapMessage result) {
Document expectedDocument = expected.getSaajMessage().getSOAPPart();
Document resultDocument = result.getSaajMessage().getSOAPPart();
assertXMLEqual(message, expectedDocument, resultDocument);
}
}

View File

@@ -1,61 +0,0 @@
/*
* 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.soap.addressing;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPConstants;
import javax.xml.soap.SOAPMessage;
import org.springframework.ws.soap.saaj.SaajSoapMessage;
public class AddressingHelperTest extends AbstractWsAddressingTestCase {
private AddressingHelper helper;
protected void onSetUp() throws Exception {
helper = new AddressingHelper(new WsAddressing200408());
SaajSoapMessage message = loadSaajMessage("request-200408.xml");
}
public void testAddMessageHeaderRequiredFault12() throws Exception {
MessageFactory messageFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_2_PROTOCOL);
SOAPMessage saajMessage = messageFactory.createMessage();
SaajSoapMessage message = new SaajSoapMessage(saajMessage);
helper.addMessageHeaderRequiredFault(message);
saajMessage.writeTo(System.out);
System.out.println();
}
public void testAddDestinationUnreachableFault() throws Exception {
MessageFactory messageFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_2_PROTOCOL);
SOAPMessage saajMessage = messageFactory.createMessage();
SaajSoapMessage message = new SaajSoapMessage(saajMessage);
helper.addDestinationUnreachableFault(message);
saajMessage.writeTo(System.out);
System.out.println();
}
public void testAddActionNotSupportedFault() throws Exception {
MessageFactory messageFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_2_PROTOCOL);
SOAPMessage saajMessage = messageFactory.createMessage();
SaajSoapMessage message = new SaajSoapMessage(saajMessage);
helper.addActionNotSupportedFault(message, "myAction");
saajMessage.writeTo(System.out);
System.out.println();
}
}

View File

@@ -1,109 +0,0 @@
/*
* 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.soap.addressing;
import java.util.Iterator;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import org.springframework.ws.context.DefaultMessageContext;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.soap.SoapHeaderElement;
import org.springframework.ws.soap.addressing.messageid.UuidMessageIdProvider;
import org.springframework.ws.soap.saaj.SaajSoapMessage;
import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
public class StatefulAddressingInterceptorTest extends AbstractWsAddressingTestCase {
private StatefulAddressingInterceptor interceptor;
private SaajSoapMessage request;
private SOAPMessage saajRequest;
private MessageContext messageContext;
private WsAddressing200408 version;
protected void onSetUp() throws Exception {
version = new WsAddressing200408();
MessageAddressingProperties map = new MessageAddressingProperties("mailto:joe@fabrikam123.example",
new EndpointReference("http://business456.example/client1"), "http://fabrikam123.example/mail/Delete",
"uuid:aaaabbbb-cccc-dddd-eeee-ffffffffffff");
interceptor =
new StatefulAddressingInterceptor(new AddressingHelper(version), new UuidMessageIdProvider(), map);
request = loadSaajMessage("request-200408.xml");
saajRequest = request.getSaajMessage();
messageContext = new DefaultMessageContext(request, new SaajSoapMessageFactory(messageFactory));
}
public void testUnderstands() throws Exception {
Iterator iterator = request.getSoapHeader()
.examineAllHeaderElements();
SoapHeaderElement headerElement = (SoapHeaderElement) iterator.next();
assertTrue("Interceptor does not understand header", interceptor.understands(headerElement));
}
public void testHandleRequestNormal() throws Exception {
boolean result = interceptor.handleRequest(messageContext, null);
assertTrue("Invalid result", result);
}
public void testHandleRequestToMissing() throws Exception {
removeElement(version.getToName());
boolean result = interceptor.handleRequest(messageContext, null);
assertFalse("Invalid result", result);
assertTrue("Response has no fault", messageContext.getResponse().hasFault());
}
public void testHandleRequestActionMissing() throws Exception {
removeElement(version.getActionName());
boolean result = interceptor.handleRequest(messageContext, null);
assertFalse("Invalid result", result);
assertTrue("Response has no fault", messageContext.getResponse().hasFault());
}
public void testHandleRequestMessageIdMissing() throws Exception {
removeElement(version.getMessageIdName());
boolean result = interceptor.handleRequest(messageContext, null);
assertFalse("Invalid result", result);
assertTrue("Response has no fault", messageContext.getResponse().hasFault());
}
public void testHandleResponse() throws Exception {
interceptor.handleRequest(messageContext, null);
interceptor.handleResponse(messageContext, null);
messageContext.getResponse().writeTo(System.out);
}
public void testHandleFault() throws Exception {
interceptor.handleRequest(messageContext, null);
interceptor.handleFault(messageContext, null);
messageContext.getResponse().writeTo(System.out);
}
private void removeElement(QName name) throws SOAPException {
Iterator iterator = saajRequest.getSOAPHeader().getChildElements(name);
while (iterator.hasNext()) {
SOAPElement element = (SOAPElement) iterator.next();
element.detachNode();
}
}
}

View File

@@ -0,0 +1,16 @@
package org.springframework.ws.soap.addressing;
public class WsAddressing200408InterceptorTest extends AbstractWsAddressingInterceptorTestCase {
protected AbstractWsAddressingInterceptor createInterceptor() {
return new WsAddressing200408Interceptor();
}
protected String getTestPath() {
return "200408";
}
public void testHandleNoneReplyTo() throws Exception {
// This version of the spec does not have none addresses
}
}

View File

@@ -0,0 +1,12 @@
package org.springframework.ws.soap.addressing;
public class WsAddressing200508InterceptorTest extends AbstractWsAddressingInterceptorTestCase {
protected AbstractWsAddressingInterceptor createInterceptor() {
return new WsAddressing200508Interceptor();
}
protected String getTestPath() {
return "200508";
}
}

View File

@@ -1,56 +0,0 @@
/*
* 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.soap.addressing;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.xml.namespace.SimpleNamespaceContext;
import org.w3c.dom.Element;
/** Test case for AbstractWsAddressingMapping */
public class WsAddressingMappingTest extends AbstractWsAddressingTestCase {
private AbstractWsAddressingMapping mapping;
protected void onSetUp() throws Exception {
mapping = new MyWsAddressingMapping();
// mapping.afterPropertiesSet();
}
public void testGetSoapHeaderElement() throws Exception {
SoapMessage message = loadSaajMessage("request-200408.xml");
Element element = mapping.getSoapHeaderElement(message);
assertNotNull("No element returned", element);
assertEquals("Invalid header element returned", "Header", element.getLocalName());
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
SimpleNamespaceContext namespaceContext = new SimpleNamespaceContext();
namespaceContext.bindNamespaceUri("wsa", "http://schemas.xmlsoap.org/ws/2004/08/addressing");
xpath.setNamespaceContext(namespaceContext);
XPathExpression expression = xpath.compile("wsa:To");
String result = expression.evaluate(element);
System.out.println("result = " + result);
}
private static class MyWsAddressingMapping extends AbstractWsAddressingMapping {
}
}

View File

@@ -31,7 +31,6 @@ public abstract class AbstractMessageIdProviderTestCase extends TestCase {
public void testProvider() {
String messageId1 = provider.getMessageId(null);
System.out.println(messageId1);
assertTrue("Empty messageId", StringUtils.hasLength(messageId1));
String messageId2 = provider.getMessageId(null);
assertTrue("Empty messageId", StringUtils.hasLength(messageId2));

View File

@@ -0,0 +1,17 @@
<S:Envelope xmlns:S="http://www.w3.org/2003/05/soap-envelope"
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
xmlns:f123="http://www.fabrikam123.example/svc53">
<S:Header>
<wsa:MessageID>uuid:aaaabbbb-cccc-dddd-eeee-ffffffffffff</wsa:MessageID>
<wsa:ReplyTo>
<wsa:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:Address>
</wsa:ReplyTo>
<wsa:To S:mustUnderstand="1">mailto:joe@fabrikam123.example</wsa:To>
<wsa:Action>http://fabrikam123.example/mail/Delete</wsa:Action>
</S:Header>
<S:Body>
<f123:Delete>
<maxCount>42</maxCount>
</f123:Delete>
</S:Body>
</S:Envelope>

View File

@@ -0,0 +1,17 @@
<S:Envelope xmlns:S="http://www.w3.org/2003/05/soap-envelope"
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
xmlns:f123="http://www.fabrikam123.example/svc53">
<S:Header>
<!--<wsa:MessageID>uuid:aaaabbbb-cccc-dddd-eeee-ffffffffffff</wsa:MessageID>-->
<wsa:ReplyTo>
<wsa:Address>http://business456.example/client1</wsa:Address>
</wsa:ReplyTo>
<wsa:To S:mustUnderstand="1">mailto:joe@fabrikam123.example</wsa:To>
<wsa:Action>http://fabrikam123.example/mail/Delete</wsa:Action>
</S:Header>
<S:Body>
<f123:Delete>
<maxCount>42</maxCount>
</f123:Delete>
</S:Body>
</S:Envelope>

View File

@@ -0,0 +1,9 @@
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope"
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">
<env:Header>
<wsa:MessageID>uid:1234</wsa:MessageID>
<wsa:RelatesTo>uuid:aaaabbbb-cccc-dddd-eeee-ffffffffffff</wsa:RelatesTo>
<wsa:To env:mustUnderstand="true">http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
</env:Header>
<env:Body/>
</env:Envelope>

View File

@@ -0,0 +1,19 @@
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope"
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">
<env:Header/>
<env:Body>
<env:Fault>
<env:Code>
<env:Value>env:Sender</env:Value>
<env:Subcode>
<env:Value>wsa:MessageInformationHeaderRequired</env:Value>
</env:Subcode>
</env:Code>
<env:Reason>
<env:Text xml:lang="en">
A required message information header, To, MessageID, or Action, is not present.
</env:Text>
</env:Reason>
</env:Fault>
</env:Body>
</env:Envelope>

View File

@@ -0,0 +1,17 @@
<S:Envelope xmlns:S="http://www.w3.org/2003/05/soap-envelope"
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
xmlns:f123="http://www.fabrikam123.example/svc53">
<S:Header>
<wsa:MessageID>uuid:aaaabbbb-cccc-dddd-eeee-ffffffffffff</wsa:MessageID>
<wsa:ReplyTo>
<wsa:Address>http://business456.example/client1</wsa:Address>
</wsa:ReplyTo>
<wsa:To S:mustUnderstand="1">mailto:joe@fabrikam123.example</wsa:To>
<wsa:Action>http://fabrikam123.example/mail/Delete</wsa:Action>
</S:Header>
<S:Body>
<f123:Delete>
<maxCount>42</maxCount>
</f123:Delete>
</S:Body>
</S:Envelope>

View File

@@ -0,0 +1,15 @@
<S:Envelope xmlns:S="http://www.w3.org/2003/05/soap-envelope" xmlns:wsa="http://www.w3.org/2005/08/addressing">
<S:Header>
<wsa:MessageID>http://example.com/someuniquestring</wsa:MessageID>
<wsa:ReplyTo>
<wsa:Address>http://www.w3.org/2005/08/addressing/anonymous</wsa:Address>
</wsa:ReplyTo>
<wsa:To>mailto:fabrikam@example.com</wsa:To>
<wsa:Action>http://example.com/fabrikam/mail/Delete</wsa:Action>
</S:Header>
<S:Body>
<f:Delete xmlns:f="http://example.com/fabrikam">
<maxCount>42</maxCount>
</f:Delete>
</S:Body>
</S:Envelope>

View File

@@ -0,0 +1,15 @@
<S:Envelope xmlns:S="http://www.w3.org/2003/05/soap-envelope" xmlns:wsa="http://www.w3.org/2005/08/addressing">
<S:Header>
<!--<wsa:MessageID>http://example.com/someuniquestring</wsa:MessageID>-->
<wsa:ReplyTo>
<wsa:Address>http://example.com/business/client1</wsa:Address>
</wsa:ReplyTo>
<wsa:To>mailto:fabrikam@example.com</wsa:To>
<wsa:Action>http://example.com/fabrikam/mail/Delete</wsa:Action>
</S:Header>
<S:Body>
<f:Delete xmlns:f="http://example.com/fabrikam">
<maxCount>42</maxCount>
</f:Delete>
</S:Body>
</S:Envelope>

View File

@@ -0,0 +1,15 @@
<S:Envelope xmlns:S="http://www.w3.org/2003/05/soap-envelope" xmlns:wsa="http://www.w3.org/2005/08/addressing">
<S:Header>
<wsa:MessageID>http://example.com/someuniquestring</wsa:MessageID>
<wsa:ReplyTo>
<wsa:Address>http://www.w3.org/2005/08/addressing/none</wsa:Address>
</wsa:ReplyTo>
<wsa:To>mailto:fabrikam@example.com</wsa:To>
<wsa:Action>http://example.com/fabrikam/mail/Delete</wsa:Action>
</S:Header>
<S:Body>
<f:Delete xmlns:f="http://example.com/fabrikam">
<maxCount>42</maxCount>
</f:Delete>
</S:Body>
</S:Envelope>

View File

@@ -0,0 +1,8 @@
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:wsa="http://www.w3.org/2005/08/addressing">
<env:Header>
<wsa:MessageID>uid:1234</wsa:MessageID>
<wsa:RelatesTo>http://example.com/someuniquestring</wsa:RelatesTo>
<wsa:To env:mustUnderstand="true">http://www.w3.org/2005/08/addressing/anonymous</wsa:To>
</env:Header>
<env:Body/>
</env:Envelope>

View File

@@ -0,0 +1,19 @@
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope"
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">
<env:Header/>
<env:Body>
<env:Fault>
<env:Code>
<env:Value>env:Sender</env:Value>
<env:Subcode>
<env:Value>wsa:MessageAddressingHeaderRequired</env:Value>
</env:Subcode>
</env:Code>
<env:Reason>
<env:Text xml:lang="en">
A required header representing a Message Addressing Property is not present
</env:Text>
</env:Reason>
</env:Fault>
</env:Body>
</env:Envelope>

View File

@@ -0,0 +1,15 @@
<S:Envelope xmlns:S="http://www.w3.org/2003/05/soap-envelope" xmlns:wsa="http://www.w3.org/2005/08/addressing">
<S:Header>
<wsa:MessageID>http://example.com/someuniquestring</wsa:MessageID>
<wsa:ReplyTo>
<wsa:Address>http://example.com/business/client1</wsa:Address>
</wsa:ReplyTo>
<wsa:To>mailto:fabrikam@example.com</wsa:To>
<wsa:Action>http://example.com/fabrikam/mail/Delete</wsa:Action>
</S:Header>
<S:Body>
<f:Delete xmlns:f="http://example.com/fabrikam">
<maxCount>42</maxCount>
</f:Delete>
</S:Body>
</S:Envelope>

View File

@@ -1,19 +0,0 @@
<S:Envelope xmlns:S="http://www.w3.org/2003/05/soap-envelope"
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
xmlns:f123="http://www.fabrikam123.example/svc53">
<S:Header>
<wsa:MessageID>
uuid:aaaabbbb-cccc-dddd-eeee-wwwwwwwwwww
</wsa:MessageID>
<wsa:RelatesTo RelationshipType="wsa:Reply">
uuid:aaaabbbb-cccc-dddd-eeee-ffffffffffff
</wsa:RelatesTo>
<wsa:To S:mustUnderstand="1">
http://business456.example/client1
</wsa:To>
<wsa:Action>http://fabrikam123.example/mail/DeleteAck</wsa:Action>
</S:Header>
<S:Body>
<f123:DeleteAck/>
</S:Body>
</S:Envelope>