diff --git a/sandbox/src/main/java/org/springframework/ws/soap/addressing/AbstractVersionBasedWsAddressingInterceptor.java b/sandbox/src/main/java/org/springframework/ws/addressing/AbstractVersionBasedWsAddressingInterceptor.java
similarity index 100%
rename from sandbox/src/main/java/org/springframework/ws/soap/addressing/AbstractVersionBasedWsAddressingInterceptor.java
rename to sandbox/src/main/java/org/springframework/ws/addressing/AbstractVersionBasedWsAddressingInterceptor.java
diff --git a/sandbox/src/main/java/org/springframework/ws/soap/addressing/AbstractWsAddressingInterceptor.java b/sandbox/src/main/java/org/springframework/ws/addressing/AbstractWsAddressingInterceptor.java
similarity index 100%
rename from sandbox/src/main/java/org/springframework/ws/soap/addressing/AbstractWsAddressingInterceptor.java
rename to sandbox/src/main/java/org/springframework/ws/addressing/AbstractWsAddressingInterceptor.java
diff --git a/sandbox/src/main/java/org/springframework/ws/addressing/AbstractWsAddressingMapping.java b/sandbox/src/main/java/org/springframework/ws/addressing/AbstractWsAddressingMapping.java
new file mode 100644
index 00000000..337d6115
--- /dev/null
+++ b/sandbox/src/main/java/org/springframework/ws/addressing/AbstractWsAddressingMapping.java
@@ -0,0 +1,182 @@
+/*
+ * 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.transform.TransformerException;
+
+import org.springframework.core.JdkVersion;
+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;
+import org.springframework.ws.soap.addressing.messageid.UuidMessageIdProvider;
+import org.springframework.ws.soap.server.SoapEndpointInvocationChain;
+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 {
+
+ private String[] actorsOrRoles;
+
+ private boolean isUltimateReceiver = true;
+
+ private MessageIdProvider messageIdProvider;
+
+ private AbstractWsAddressingInterceptor[] addressingInterceptors;
+
+ private EndpointInterceptor[] preInterceptors;
+
+ private EndpointInterceptor[] postInterceptors;
+
+ /** Protected constructor */
+ protected AbstractWsAddressingMapping() {
+ addressingInterceptors = new AbstractWsAddressingInterceptor[]{new WsAddressing200408Interceptor(),
+ new WsAddressing200508Interceptor()};
+ if (JdkVersion.getMajorJavaVersion() >= JdkVersion.JAVA_15) {
+ messageIdProvider = new UuidMessageIdProvider();
+ }
+ else {
+ messageIdProvider = new UidMessageIdProvider();
+ }
+ }
+
+ public final void setActorOrRole(String actorOrRole) {
+ Assert.notNull(actorOrRole, "actorOrRole must not be null");
+ actorsOrRoles = new String[]{actorOrRole};
+ }
+
+ public final void setActorsOrRoles(String[] actorsOrRoles) {
+ Assert.notEmpty(actorsOrRoles, "actorsOrRoles must not be empty");
+ this.actorsOrRoles = actorsOrRoles;
+ }
+
+ public final void setUltimateReceiver(boolean ultimateReceiver) {
+ this.isUltimateReceiver = ultimateReceiver;
+ }
+
+ /**
+ * Set additional interceptors to be applied before the implicit WS-Addressing interceptor, e.g.
+ * XwsSecurityInterceptor.
+ */
+ public final void setPreInterceptors(EndpointInterceptor[] preInterceptors) {
+ this.preInterceptors = preInterceptors;
+ }
+
+ /**
+ * Set additional interceptors to be applied after the implicit WS-Addressing interceptor, e.g.
+ * PayloadLoggingInterceptor.
+ */
+ public final void setPostInterceptors(EndpointInterceptor[] postInterceptors) {
+ this.postInterceptors = postInterceptors;
+ }
+
+ /**
+ * Sets the message id provider used for creating WS-Addressing MessageIds.
+ *
null 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 null
+ */
+ protected abstract Object getEndpointInternal(MessageAddressingProperties map);
+
+
+}
diff --git a/sandbox/src/main/java/org/springframework/ws/soap/addressing/AbstractWsAddressingVersion.java b/sandbox/src/main/java/org/springframework/ws/addressing/AbstractWsAddressingVersion.java
similarity index 100%
rename from sandbox/src/main/java/org/springframework/ws/soap/addressing/AbstractWsAddressingVersion.java
rename to sandbox/src/main/java/org/springframework/ws/addressing/AbstractWsAddressingVersion.java
diff --git a/sandbox/src/main/java/org/springframework/ws/addressing/EndpointReference.java b/sandbox/src/main/java/org/springframework/ws/addressing/EndpointReference.java
new file mode 100644
index 00000000..be18e9bf
--- /dev/null
+++ b/sandbox/src/main/java/org/springframework/ws/addressing/EndpointReference.java
@@ -0,0 +1,104 @@
+/*
+ * 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.Collections;
+import java.util.List;
+
+import org.springframework.util.Assert;
+import org.w3c.dom.Node;
+
+/**
+ * Represents a set of Message Addressing Properties, as defined in the WS-Addressing specification.
+ *
+ * In earlier versions of the spec, these properties were called Message Information Headers.
+ *
+ * @author Arjen Poutsma
+ * @see Endpoint References
+ * @since 1.1.0
+ */
+public final class EndpointReference {
+
+ private final String address;
+
+ private final List referenceProperties;
+
+ 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");
+ Assert.notNull(referenceParameters, "referenceParameters must not be null");
+ this.address = address;
+ this.referenceProperties = referenceProperties;
+ 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;
+ }
+
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o != null && o instanceof EndpointReference) {
+ EndpointReference other = (EndpointReference) o;
+ return address.equals(other.address);
+ }
+ return false;
+ }
+
+ public int hashCode() {
+ return address.hashCode();
+ }
+
+ public String toString() {
+ return "EndpointReference[" + address + ']';
+ }
+}
diff --git a/sandbox/src/main/java/org/springframework/ws/addressing/MessageAddressingProperties.java b/sandbox/src/main/java/org/springframework/ws/addressing/MessageAddressingProperties.java
new file mode 100644
index 00000000..ee281281
--- /dev/null
+++ b/sandbox/src/main/java/org/springframework/ws/addressing/MessageAddressingProperties.java
@@ -0,0 +1,166 @@
+/*
+ * 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.Collections;
+import java.util.List;
+
+import org.springframework.util.StringUtils;
+
+/**
+ * Represents a set of Message Addressing Properties, as defined in the WS-Addressing specification.
+ *
+ * In earlier versions of the spec, these properties were called Message Information Headers.
+ *
+ * @author Arjen Poutsma
+ * @see Message Addressing Properties
+ * @since 1.1.0
+ */
+public final class MessageAddressingProperties {
+
+ private final String to;
+
+ private final EndpointReference from;
+
+ private final EndpointReference replyTo;
+
+ private final EndpointReference faultTo;
+
+ private final String action;
+
+ private final String messageId;
+
+ private final String relatesTo;
+
+ private final List referenceProperties;
+
+ private final List referenceParameters;
+
+/*
+ public MessageAddressingProperties(String to, EndpointReference replyTo, String action, String messageId) {
+ this.to = to;
+ this.replyTo = replyTo;
+ this.action = action;
+ this.messageId = messageId;
+ this.from = null;
+ this.faultTo = null;
+ this.relatesTo = null;
+ this.referenceProperties = Collections.EMPTY_LIST;
+ this.referenceParameters = Collections.EMPTY_LIST;
+ }
+*/
+
+ public MessageAddressingProperties(String to,
+ EndpointReference from,
+ EndpointReference replyTo,
+ EndpointReference faultTo,
+ String action,
+ String messageId) {
+ this.to = to;
+ this.from = from;
+ this.replyTo = replyTo;
+ this.faultTo = faultTo;
+ this.action = action;
+ this.messageId = messageId;
+ this.relatesTo = null;
+ this.referenceProperties = Collections.EMPTY_LIST;
+ this.referenceParameters = Collections.EMPTY_LIST;
+ }
+
+/*
+ private MessageAddressingProperties(String to,
+ String action,
+ String messageId,
+ String relatesTo,
+ List referenceProperties,
+ List referenceParameters) {
+ this.to = to;
+ this.action = action;
+ this.messageId = messageId;
+ this.relatesTo = relatesTo;
+ this.referenceProperties = referenceProperties;
+ this.referenceParameters = referenceParameters;
+ this.from = null;
+ 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;
+ }
+
+ public EndpointReference getFrom() {
+ return from;
+ }
+
+ public EndpointReference getReplyTo() {
+ return replyTo != null ? replyTo : getFrom();
+ }
+
+ public EndpointReference getFaultTo() {
+ return faultTo != null ? faultTo : getReplyTo();
+ }
+
+ public String getAction() {
+ return action;
+ }
+
+ public String getMessageId() {
+ return messageId;
+ }
+
+ public String getRelatesTo() {
+ return relatesTo;
+ }
+
+ public List getReferenceProperties() {
+ return Collections.unmodifiableList(referenceProperties);
+ }
+
+ public List getReferenceParameters() {
+ 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)) &&
+ !(faultTo != null && !StringUtils.hasLength(messageId));
+
+ }
+
+ public MessageAddressingProperties getResponseProperties(EndpointReference epr, String action, String messageId) {
+ return new MessageAddressingProperties(epr, action, messageId, this.messageId);
+ }
+
+}
diff --git a/sandbox/src/main/java/org/springframework/ws/soap/addressing/WsAddressing200408Interceptor.java b/sandbox/src/main/java/org/springframework/ws/addressing/WsAddressing200408Interceptor.java
similarity index 100%
rename from sandbox/src/main/java/org/springframework/ws/soap/addressing/WsAddressing200408Interceptor.java
rename to sandbox/src/main/java/org/springframework/ws/addressing/WsAddressing200408Interceptor.java
diff --git a/sandbox/src/main/java/org/springframework/ws/soap/addressing/WsAddressing200508Interceptor.java b/sandbox/src/main/java/org/springframework/ws/addressing/WsAddressing200508Interceptor.java
similarity index 100%
rename from sandbox/src/main/java/org/springframework/ws/soap/addressing/WsAddressing200508Interceptor.java
rename to sandbox/src/main/java/org/springframework/ws/addressing/WsAddressing200508Interceptor.java
diff --git a/sandbox/src/main/java/org/springframework/ws/addressing/package.html b/sandbox/src/main/java/org/springframework/ws/addressing/package.html
new file mode 100644
index 00000000..b859632d
--- /dev/null
+++ b/sandbox/src/main/java/org/springframework/ws/addressing/package.html
@@ -0,0 +1,5 @@
+
+
+Provides WS-Addressing implementation classes.
+
+
\ No newline at end of file
diff --git a/sandbox/src/main/java/org/springframework/ws/soap/addressing/AbstractWsAddressingMapping.java b/sandbox/src/main/java/org/springframework/ws/soap/addressing/AbstractWsAddressingMapping.java
index 337d6115..2c40c8c1 100644
--- a/sandbox/src/main/java/org/springframework/ws/soap/addressing/AbstractWsAddressingMapping.java
+++ b/sandbox/src/main/java/org/springframework/ws/soap/addressing/AbstractWsAddressingMapping.java
@@ -28,11 +28,15 @@ 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;
-import org.springframework.ws.soap.addressing.messageid.UuidMessageIdProvider;
+import org.springframework.ws.soap.addressing.messageid.MessageIdStrategy;
+import org.springframework.ws.soap.addressing.messageid.UidMessageIdStrategy;
+import org.springframework.ws.soap.addressing.messageid.UuidMessageIdStrategy;
+import org.springframework.ws.soap.addressing.version.WsAddressing200408;
+import org.springframework.ws.soap.addressing.version.WsAddressing200605;
+import org.springframework.ws.soap.addressing.version.WsAddressingVersion;
import org.springframework.ws.soap.server.SoapEndpointInvocationChain;
import org.springframework.ws.soap.server.SoapEndpointMapping;
+import org.springframework.ws.transport.WebServiceMessageSender;
import org.springframework.xml.transform.TransformerObjectSupport;
/**
@@ -47,23 +51,24 @@ public abstract class AbstractWsAddressingMapping extends TransformerObjectSuppo
private boolean isUltimateReceiver = true;
- private MessageIdProvider messageIdProvider;
+ private MessageIdStrategy messageIdStrategy;
- private AbstractWsAddressingInterceptor[] addressingInterceptors;
+ private WebServiceMessageSender[] messageSenders;
+
+ private WsAddressingVersion[] versions;
private EndpointInterceptor[] preInterceptors;
private EndpointInterceptor[] postInterceptors;
- /** Protected constructor */
+ /** Protected constructor. Initializes the default settings. */
protected AbstractWsAddressingMapping() {
- addressingInterceptors = new AbstractWsAddressingInterceptor[]{new WsAddressing200408Interceptor(),
- new WsAddressing200508Interceptor()};
+ this.versions = new WsAddressingVersion[]{new WsAddressing200408(), new WsAddressing200605()};
if (JdkVersion.getMajorJavaVersion() >= JdkVersion.JAVA_15) {
- messageIdProvider = new UuidMessageIdProvider();
+ messageIdStrategy = new UuidMessageIdStrategy();
}
else {
- messageIdProvider = new UidMessageIdProvider();
+ messageIdStrategy = new UidMessageIdStrategy();
}
}
@@ -100,53 +105,54 @@ 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}
+ * By default, the {@link UuidMessageIdStrategy} is used on Java 5 and higher, and the {@link UidMessageIdStrategy}
* on Java 1.4 and lower.
*/
- public final void setMessageIdProvider(MessageIdProvider messageIdProvider) {
- this.messageIdProvider = messageIdProvider;
+ public final void setMessageIdProvider(MessageIdStrategy messageIdStrategy) {
+ this.messageIdStrategy = messageIdStrategy;
+ }
+
+ public final void setMessageSenders(WebServiceMessageSender[] messageSenders) {
+ this.messageSenders = messageSenders;
}
/**
- * Sets the WS-Addressing interceptors to be supported by this mapping.
+ * Sets the WS-Addressing versions to be supported by this mapping.
*
- * By default, this includes the {@link WsAddressing200408Interceptor}, and the {@link
- * WsAddressing200508Interceptor}.
+ * By default, this array is set to support {@link WsAddressing200408 the August 2004} and the {@link
+ * WsAddressing200605 May 2006} versions of the specification.
*/
- public final void setAddressingInterceptors(AbstractWsAddressingInterceptor[] addressingInterceptors) {
- Assert.notEmpty(addressingInterceptors, "'addressingInterceptors' must not be empty");
- this.addressingInterceptors = addressingInterceptors;
+ public final void setVersions(WsAddressingVersion[] versions) {
+ this.versions = versions;
}
public final EndpointInvocationChain getEndpoint(MessageContext messageContext) throws TransformerException {
- Assert.isTrue(messageContext.getResponse() instanceof SoapMessage,
+ Assert.isInstanceOf(SoapMessage.class, messageContext.getResponse(),
"WsAddressingMapping requires a SoapMessage request");
SoapMessage request = (SoapMessage) messageContext.getRequest();
- for (int i = 0; i < addressingInterceptors.length; i++) {
- AbstractWsAddressingInterceptor interceptor = addressingInterceptors[i];
- if (!understands(interceptor, request)) {
- continue;
+ for (int i = 0; i < versions.length; i++) {
+ if (supports(versions[i], request)) {
+ MessageAddressingProperties requestMap = versions[i].getMessageAddressingProperties(request);
+ if (requestMap == null) {
+ return null;
+ }
+ Object endpoint = getEndpointInternal(requestMap);
+ if (endpoint == null) {
+ return null;
+ }
+ return new SoapEndpointInvocationChain(endpoint, getAllEndpointInterceptors(versions[i]), actorsOrRoles,
+ isUltimateReceiver);
}
- MessageAddressingProperties requestMap = interceptor.getMessageAddressingProperties(request);
- if (requestMap == null) {
- return null;
- }
- Object endpoint = getEndpointInternal(requestMap);
- if (endpoint == null) {
- return null;
- }
- return new SoapEndpointInvocationChain(endpoint, getAllEndpointInterceptors(interceptor), actorsOrRoles,
- isUltimateReceiver);
}
return null;
}
- private boolean understands(AbstractWsAddressingInterceptor interceptor, SoapMessage request) {
+ private boolean supports(WsAddressingVersion version, 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)) {
+ if (version.understands(headerElement)) {
return true;
}
}
@@ -154,7 +160,7 @@ public abstract class AbstractWsAddressingMapping extends TransformerObjectSuppo
return false;
}
- protected EndpointInterceptor[] getAllEndpointInterceptors(AbstractWsAddressingInterceptor interceptor) {
+ private EndpointInterceptor[] getAllEndpointInterceptors(WsAddressingVersion version) {
if (preInterceptors == null) {
preInterceptors = new EndpointInterceptor[0];
}
@@ -164,7 +170,7 @@ public abstract class AbstractWsAddressingMapping extends TransformerObjectSuppo
EndpointInterceptor[] interceptors =
new EndpointInterceptor[preInterceptors.length + postInterceptors.length + 1];
System.arraycopy(preInterceptors, 0, interceptors, 0, preInterceptors.length);
- interceptors[preInterceptors.length] = interceptor;
+ interceptors[preInterceptors.length] = new WsAddressingInterceptor(version, messageIdStrategy, messageSenders);
System.arraycopy(postInterceptors, 0, interceptors, preInterceptors.length + 1, postInterceptors.length);
return interceptors;
}
@@ -178,5 +184,4 @@ public abstract class AbstractWsAddressingMapping extends TransformerObjectSuppo
*/
protected abstract Object getEndpointInternal(MessageAddressingProperties map);
-
}
diff --git a/sandbox/src/main/java/org/springframework/ws/soap/addressing/EndpointReference.java b/sandbox/src/main/java/org/springframework/ws/soap/addressing/EndpointReference.java
index be18e9bf..8681f4e2 100644
--- a/sandbox/src/main/java/org/springframework/ws/soap/addressing/EndpointReference.java
+++ b/sandbox/src/main/java/org/springframework/ws/soap/addressing/EndpointReference.java
@@ -46,6 +46,7 @@ public final class EndpointReference {
* @param address the endpoint address
*/
public EndpointReference(String address) {
+ Assert.notNull(address, "address must not be null");
this.address = address;
this.referenceParameters = Collections.EMPTY_LIST;
this.referenceProperties = Collections.EMPTY_LIST;
diff --git a/sandbox/src/main/java/org/springframework/ws/soap/addressing/MessageAddressingProperties.java b/sandbox/src/main/java/org/springframework/ws/soap/addressing/MessageAddressingProperties.java
index ee281281..a6b10daf 100644
--- a/sandbox/src/main/java/org/springframework/ws/soap/addressing/MessageAddressingProperties.java
+++ b/sandbox/src/main/java/org/springframework/ws/soap/addressing/MessageAddressingProperties.java
@@ -50,20 +50,16 @@ public final class MessageAddressingProperties {
private final List referenceParameters;
-/*
- public MessageAddressingProperties(String to, EndpointReference replyTo, String action, String messageId) {
- this.to = to;
- this.replyTo = replyTo;
- this.action = action;
- this.messageId = messageId;
- this.from = null;
- this.faultTo = null;
- this.relatesTo = null;
- this.referenceProperties = Collections.EMPTY_LIST;
- this.referenceParameters = Collections.EMPTY_LIST;
- }
-*/
-
+ /**
+ * Constructs a new {@link MessageAddressingProperties} with the given parameters.
+ *
+ * @param to the value of the destination property
+ * @param from the value of the source endpoint property
+ * @param replyTo the value of the reply endpoint property
+ * @param faultTo the value of the fault endpoint property
+ * @param action the value of the action property
+ * @param messageId the value of the message id property
+ */
public MessageAddressingProperties(String to,
EndpointReference from,
EndpointReference replyTo,
@@ -81,25 +77,6 @@ public final class MessageAddressingProperties {
this.referenceParameters = Collections.EMPTY_LIST;
}
-/*
- private MessageAddressingProperties(String to,
- String action,
- String messageId,
- String relatesTo,
- List referenceProperties,
- List referenceParameters) {
- this.to = to;
- this.action = action;
- this.messageId = messageId;
- this.relatesTo = relatesTo;
- this.referenceProperties = referenceProperties;
- this.referenceParameters = referenceParameters;
- this.from = null;
- this.replyTo = null;
- this.faultTo = null;
- }
-*/
-
private MessageAddressingProperties(EndpointReference epr, String action, String messageId, String relatesTo) {
this.to = epr.getAddress();
this.action = action;
@@ -112,45 +89,55 @@ public final class MessageAddressingProperties {
this.faultTo = null;
}
+ /** Returns the value of the destination property. */
public String getTo() {
return to;
}
+ /** Returns the value of the source endpoint property. */
public EndpointReference getFrom() {
return from;
}
+ /** Returns the value of the reply endpoint property. */
public EndpointReference getReplyTo() {
- return replyTo != null ? replyTo : getFrom();
+ return replyTo;
}
+ /** Returns the value of the fault endpoint property. Defaults to {@link #getReplyTo()} if no fault endpoint is set. */
public EndpointReference getFaultTo() {
return faultTo != null ? faultTo : getReplyTo();
}
+ /** Returns the value of the action property. */
public String getAction() {
return action;
}
+ /** Returns the value of the message id property. */
public String getMessageId() {
return messageId;
}
+ /** Returns the value of the relationship property. */
public String getRelatesTo() {
return relatesTo;
}
+ /** Returns the endpoint properties. Returns an empty list of none are set. */
public List getReferenceProperties() {
return Collections.unmodifiableList(referenceProperties);
}
+ /** Returns the endpoint parameters. Returns an empty list of none are set. */
public List getReferenceParameters() {
return Collections.unmodifiableList(referenceParameters);
}
/**
- * Indicates whether the given {@link MessageAddressingProperties} are valid, i.e. whether all required elements are
- * listed.
+ * Indicates whether is {@link MessageAddressingProperties} is valid, i.e. whether all required elements are listed.
+ * Returns true if the destination and action properties have been set, and if a reply or fault
+ * endpoint has been set, also checks for the message id.
*/
public boolean isValid() {
return StringUtils.hasLength(to) && StringUtils.hasLength(action) &&
@@ -163,4 +150,14 @@ public final class MessageAddressingProperties {
return new MessageAddressingProperties(epr, action, messageId, this.messageId);
}
+ /**
+ * Indicates whether is {@link MessageAddressingProperties} has all required properties. Returns true
+ * if the destination and action properties have been set, and if a reply or fault endpoint has been set, also
+ * checks for the message id.
+ */
+ public boolean hasRequiredProperties() {
+ return StringUtils.hasLength(to) && StringUtils.hasLength(action) &&
+ !(replyTo != null && !StringUtils.hasLength(messageId)) &&
+ !(faultTo != null && !StringUtils.hasLength(messageId));
+ }
}
diff --git a/sandbox/src/main/java/org/springframework/ws/soap/addressing/WsAddressingException.java b/sandbox/src/main/java/org/springframework/ws/soap/addressing/WsAddressingException.java
new file mode 100644
index 00000000..ae5b3b97
--- /dev/null
+++ b/sandbox/src/main/java/org/springframework/ws/soap/addressing/WsAddressingException.java
@@ -0,0 +1,20 @@
+package org.springframework.ws.soap.addressing;
+
+import org.springframework.ws.WebServiceException;
+
+/**
+ * Exception thrown in cases on WS-Addressing errors.
+ *
+ * @author Arjen Poutsma
+ * @since 1.1.0
+ */
+public class WsAddressingException extends WebServiceException {
+
+ public WsAddressingException(String msg) {
+ super(msg);
+ }
+
+ public WsAddressingException(String msg, Throwable ex) {
+ super(msg, ex);
+ }
+}
diff --git a/sandbox/src/main/java/org/springframework/ws/soap/addressing/WsAddressingInterceptor.java b/sandbox/src/main/java/org/springframework/ws/soap/addressing/WsAddressingInterceptor.java
new file mode 100644
index 00000000..7b143605
--- /dev/null
+++ b/sandbox/src/main/java/org/springframework/ws/soap/addressing/WsAddressingInterceptor.java
@@ -0,0 +1,126 @@
+package org.springframework.ws.soap.addressing;
+
+import java.io.IOException;
+
+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.SoapHeaderElement;
+import org.springframework.ws.soap.SoapMessage;
+import org.springframework.ws.soap.addressing.messageid.MessageIdStrategy;
+import org.springframework.ws.soap.addressing.version.WsAddressingVersion;
+import org.springframework.ws.soap.server.SoapEndpointInterceptor;
+import org.springframework.ws.transport.WebServiceConnection;
+import org.springframework.ws.transport.WebServiceMessageSender;
+
+/**
+ * {@link SoapEndpointInterceptor} implementation that u
+ *
+ * @author Arjen Poutsma
+ */
+class WsAddressingInterceptor implements SoapEndpointInterceptor {
+
+ private static final Log logger = LogFactory.getLog(WsAddressingInterceptor.class);
+
+ private final WsAddressingVersion version;
+
+ private final MessageIdStrategy messageIdStrategy;
+
+ private final WebServiceMessageSender[] messageSenders;
+
+ WsAddressingInterceptor(WsAddressingVersion version,
+ MessageIdStrategy messageIdStrategy,
+ WebServiceMessageSender[] messageSenders) {
+ Assert.notNull(version, "version must not be null");
+ Assert.notNull(messageIdStrategy, "messageIdStrategy must not be null");
+ Assert.notNull(messageSenders, "messageSenders must not be null");
+ this.version = version;
+ this.messageIdStrategy = messageIdStrategy;
+ this.messageSenders = messageSenders;
+ }
+
+ public boolean handleRequest(MessageContext messageContext, Object endpoint) throws Exception {
+ Assert.isInstanceOf(SoapMessage.class, messageContext.getRequest(),
+ "WsAddressingInterceptor requires a SoapMessage request");
+ SoapMessage request = (SoapMessage) messageContext.getRequest();
+ MessageAddressingProperties requestMap = version.getMessageAddressingProperties(request);
+ if (!requestMap.hasRequiredProperties()) {
+ version.addMessageAddressingHeaderRequiredFault((SoapMessage) messageContext.getResponse());
+ return false;
+ }
+ if (!requestMap.isValid() || messageIdStrategy.isDuplicate(requestMap.getMessageId())) {
+ version.addInvalidAddressingHeaderFault((SoapMessage) messageContext.getResponse());
+ return false;
+ }
+ return true;
+ }
+
+ public boolean handleResponse(MessageContext messageContext, Object endpoint) throws Exception {
+ return handleResponseOrFault(messageContext);
+ }
+
+ public boolean handleFault(MessageContext messageContext, Object endpoint) throws Exception {
+ return handleResponseOrFault(messageContext);
+ }
+
+ private boolean handleResponseOrFault(MessageContext messageContext) throws Exception {
+ Assert.isInstanceOf(SoapMessage.class, messageContext.getRequest(),
+ "WsAddressingInterceptor requires a SoapMessage request");
+ Assert.isInstanceOf(SoapMessage.class, messageContext.getResponse(),
+ "WsAddressingInterceptor requires a SoapMessage response");
+ SoapMessage request = (SoapMessage) messageContext.getRequest();
+ MessageAddressingProperties requestMap = version.getMessageAddressingProperties(request);
+ SoapMessage response = (SoapMessage) messageContext.getResponse();
+ EndpointReference responseEpr = response.hasFault() ? requestMap.getFaultTo() : requestMap.getReplyTo();
+ if (responseEpr == null || version.hasNoneAddress(responseEpr)) {
+ logger.debug("Request has none reply address");
+ return false;
+ }
+ String responseMessageId = messageIdStrategy.newMessageId(response);
+ if (logger.isDebugEnabled()) {
+ logger.debug("Generated reply MessageID [" + responseMessageId + "]");
+ }
+ MessageAddressingProperties replyMap = requestMap.getResponseProperties(responseEpr, null, responseMessageId);
+ version.addAddressingHeaders(response, replyMap);
+ if (version.hasAnonymousAddress(responseEpr)) {
+ logger.debug("Sending in-band reply");
+ return true;
+ }
+ else {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Sending out-of-band 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) {
+ logger.warn("Could not send out-of-band response to [" + uri + "]. " +
+ "Configure WebServiceMessageSenders which support this uri.");
+ }
+ }
+
+ public boolean understands(SoapHeaderElement header) {
+ return version.understands(header);
+ }
+}
diff --git a/sandbox/src/main/java/org/springframework/ws/soap/addressing/WsAddressingVersion.java b/sandbox/src/main/java/org/springframework/ws/soap/addressing/WsAddressingVersion.java
deleted file mode 100644
index 5d7b5430..00000000
--- a/sandbox/src/main/java/org/springframework/ws/soap/addressing/WsAddressingVersion.java
+++ /dev/null
@@ -1,115 +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;
-
-/**
- * Defines the contract for a specific version of the WS-Addressing specification.
- *
- * @author Arjen Poutsma
- */
-public interface WsAddressingVersion {
-
- /** Returns the WS-Addressing namespace handled by this specification. */
- String getNamespaceUri();
-
- /** Returns the prefix associated with the WS-Addressing namespace handled by this specification. */
- String getNamespacePrefix();
-
- /*
- * Message addressing properties
- */
-
- /** Returns the qualified name of the To addressing header. */
- QName getToName();
-
- /** Returns the qualified name of the From addressing header. */
- QName getFromName();
-
- /** Returns the qualified name of the ReplyTo addressing header. */
- QName getReplyToName();
-
- /** Returns the qualified name of the FaultTo addressing header. */
- QName getFaultToName();
-
- /** Returns the qualified name of the Action addressing header. */
- QName getActionName();
-
- /** Returns the qualified name of the MessageID addressing header. */
- QName getMessageIdName();
-
- /** Returns the qualified name of the RelatesTo addressing header. */
- QName getRelatesToName();
-
- /**
- * Returns the qualified name of the Relationship addressing attribute.
- *
- * @see #getRelationshipReply()
- */
- QName getRelationshipTypeName();
-
- /**
- * Returns the value of the RelationshipType attribute indicating a reply to the related message.
- *
- * @see #getRelationshipTypeName()
- */
- String getRelationshipReply();
-
- /**
- * Returns the qualified name of the ReferenceProperties in the endpoint reference. Returns
- * null when reference properties are not supported by this version of the spec.
- */
- QName getReferencePropertiesName();
-
- /**
- * Returns the qualified name of the ReferenceParameters in the endpoint reference. Returns
- * null when reference parameters are not supported by this version of the spec.
- */
- QName getReferenceParametersName();
-
- /*
- * Endpoint Reference
- */
-
- /** The qualified name of the Address in EndpointReference. */
- QName getAddressName();
-
- /** The qualified name of the Metadata in EndpointReference. */
- QName getMetadataName();
-
- /*
- * Address URIs
- */
-
- /** Returns the anonymous URI. */
- String getAnonymousUri();
-
- /** Returns the none URI, or null 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 getMessageAddressingHeaderRequiredFaultSubcode();
-
- /** Returns the reason of the fault that indicates that a header is missing. */
- String getMessageAddressingHeaderRequiredFaultReason();
-
-}
diff --git a/sandbox/src/main/java/org/springframework/ws/soap/addressing/messageid/MessageIdProvider.java b/sandbox/src/main/java/org/springframework/ws/soap/addressing/messageid/MessageIdStrategy.java
similarity index 52%
rename from sandbox/src/main/java/org/springframework/ws/soap/addressing/messageid/MessageIdProvider.java
rename to sandbox/src/main/java/org/springframework/ws/soap/addressing/messageid/MessageIdStrategy.java
index 32301331..c42d4ac9 100644
--- a/sandbox/src/main/java/org/springframework/ws/soap/addressing/messageid/MessageIdProvider.java
+++ b/sandbox/src/main/java/org/springframework/ws/soap/addressing/messageid/MessageIdStrategy.java
@@ -19,13 +19,27 @@ package org.springframework.ws.soap.addressing.messageid;
import org.springframework.ws.soap.SoapMessage;
/**
- * Declares the contract for classes that provide WS-Addressing MessageIds, either by generation or otherwise.
+ * Strategy interface that encapsulates the creation and validation of WS-Addressing MessageIDs.
*
* @author Arjen Poutsma
+ * @since 1.1.0
*/
-public interface MessageIdProvider {
+public interface MessageIdStrategy {
- /** Returns a WS-Addressing Message Id for the given message. */
- String getMessageId(SoapMessage message);
+ /**
+ * Indicates whether the given MessageID value is a duplicate or not
+ *
+ * @param messageId the message id
+ * @return true if a duplicate; false otherwise
+ */
+ boolean isDuplicate(String messageId);
+
+ /**
+ * Returns a new WS-Addressing MessageID for the given message.
+ *
+ * @param message the SOAP message to create a new message id for
+ * @return the new message id
+ */
+ String newMessageId(SoapMessage message);
}
diff --git a/sandbox/src/main/java/org/springframework/ws/soap/addressing/messageid/UidMessageIdProvider.java b/sandbox/src/main/java/org/springframework/ws/soap/addressing/messageid/UidMessageIdStrategy.java
similarity index 76%
rename from sandbox/src/main/java/org/springframework/ws/soap/addressing/messageid/UidMessageIdProvider.java
rename to sandbox/src/main/java/org/springframework/ws/soap/addressing/messageid/UidMessageIdStrategy.java
index 1ba88e3a..48b15d7f 100644
--- a/sandbox/src/main/java/org/springframework/ws/soap/addressing/messageid/UidMessageIdProvider.java
+++ b/sandbox/src/main/java/org/springframework/ws/soap/addressing/messageid/UidMessageIdStrategy.java
@@ -21,16 +21,21 @@ import java.rmi.server.UID;
import org.springframework.ws.soap.SoapMessage;
/**
- * Implementation of the {@link MessageIdProvider} interface that uses a {@link UID} to generate a Message Id. The UID
+ * Implementation of the {@link MessageIdStrategy} interface that uses a {@link UID} to generate a Message Id. The UID
* is prefixed by uid:.
*
* @author Arjen Poutsma
*/
-public class UidMessageIdProvider implements MessageIdProvider {
+public class UidMessageIdStrategy implements MessageIdStrategy {
public static final String PREFIX = "uid:";
- public String getMessageId(SoapMessage message) {
+ /** Returns false. */
+ public boolean isDuplicate(String messageId) {
+ return false;
+ }
+
+ public String newMessageId(SoapMessage message) {
return PREFIX + new UID().toString();
}
}
diff --git a/sandbox/src/main/java/org/springframework/ws/soap/addressing/messageid/UuidMessageIdProvider.java b/sandbox/src/main/java/org/springframework/ws/soap/addressing/messageid/UuidMessageIdStrategy.java
similarity index 78%
rename from sandbox/src/main/java/org/springframework/ws/soap/addressing/messageid/UuidMessageIdProvider.java
rename to sandbox/src/main/java/org/springframework/ws/soap/addressing/messageid/UuidMessageIdStrategy.java
index 82d6b9ed..40ce94a2 100644
--- a/sandbox/src/main/java/org/springframework/ws/soap/addressing/messageid/UuidMessageIdProvider.java
+++ b/sandbox/src/main/java/org/springframework/ws/soap/addressing/messageid/UuidMessageIdStrategy.java
@@ -21,18 +21,23 @@ import java.util.UUID;
import org.springframework.ws.soap.SoapMessage;
/**
- * Implementation of the {@link MessageIdProvider} interface that uses a {@link UUID} to generate a Message Id. The UUID
+ * Implementation of the {@link MessageIdStrategy} interface that uses a {@link UUID} to generate a Message Id. The UUID
* is prefixed by uuid:.
*
* Note that the {@link UUID} class is only available on Java 5 and above.
*
* @author Arjen Poutsma
*/
-public class UuidMessageIdProvider implements MessageIdProvider {
+public class UuidMessageIdStrategy implements MessageIdStrategy {
public static final String PREFIX = "uuid:";
- public String getMessageId(SoapMessage message) {
+ /** Returns false. */
+ public boolean isDuplicate(String messageId) {
+ return false;
+ }
+
+ public String newMessageId(SoapMessage message) {
return PREFIX + UUID.randomUUID().toString();
}
}
\ No newline at end of file
diff --git a/sandbox/src/main/java/org/springframework/ws/soap/addressing/messageid/package.html b/sandbox/src/main/java/org/springframework/ws/soap/addressing/messageid/package.html
new file mode 100644
index 00000000..672410ae
--- /dev/null
+++ b/sandbox/src/main/java/org/springframework/ws/soap/addressing/messageid/package.html
@@ -0,0 +1,5 @@
+
+
+Contains various strategies for generating WS-Addressing MessageIDs.
+
+
\ No newline at end of file
diff --git a/sandbox/src/main/java/org/springframework/ws/soap/addressing/version/AbstractWsAddressingVersion.java b/sandbox/src/main/java/org/springframework/ws/soap/addressing/version/AbstractWsAddressingVersion.java
new file mode 100644
index 00000000..d23b6507
--- /dev/null
+++ b/sandbox/src/main/java/org/springframework/ws/soap/addressing/version/AbstractWsAddressingVersion.java
@@ -0,0 +1,310 @@
+package org.springframework.ws.soap.addressing.version;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Properties;
+import javax.xml.namespace.QName;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.dom.DOMSource;
+
+import org.springframework.util.StringUtils;
+import org.springframework.ws.soap.SoapFault;
+import org.springframework.ws.soap.SoapHeader;
+import org.springframework.ws.soap.SoapHeaderElement;
+import org.springframework.ws.soap.SoapMessage;
+import org.springframework.ws.soap.addressing.EndpointReference;
+import org.springframework.ws.soap.addressing.MessageAddressingProperties;
+import org.springframework.ws.soap.addressing.WsAddressingException;
+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;
+
+/**
+ * Abstract base class for {@link WsAddressingVersion} implementations. Uses {@link XPathExpression}s to retrieve
+ * addressing information.
+ *
+ * @author Arjen Poutsma
+ * @since 1.1.0
+ */
+public abstract class AbstractWsAddressingVersion extends TransformerObjectSupport implements WsAddressingVersion {
+
+ private final XPathExpression toExpression;
+
+ private final XPathExpression actionExpression;
+
+ private final XPathExpression messageIdExpression;
+
+ private final XPathExpression fromExpression;
+
+ private final XPathExpression replyToExpression;
+
+ private final XPathExpression faultToExpression;
+
+ private final XPathExpression addressExpression;
+
+ private final XPathExpression referencePropertiesExpression;
+
+ private final XPathExpression referenceParametersExpression;
+
+ protected AbstractWsAddressingVersion() {
+ Properties namespaces = new Properties();
+ namespaces.setProperty(getNamespacePrefix(), getNamespaceUri());
+ toExpression = createNormalizedExpression(getToName(), namespaces);
+ actionExpression = createNormalizedExpression(getActionName(), namespaces);
+ messageIdExpression = createNormalizedExpression(getMessageIdName(), namespaces);
+ fromExpression = createExpression(getFromName(), namespaces);
+ replyToExpression = createExpression(getReplyToName(), namespaces);
+ faultToExpression = createExpression(getFaultToName(), namespaces);
+ addressExpression = createNormalizedExpression(getAddressName(), namespaces);
+ if (getReferencePropertiesName() != null) {
+ referencePropertiesExpression = createChildrenExpression(getReferencePropertiesName(), namespaces);
+ }
+ else {
+ referencePropertiesExpression = null;
+ }
+ if (getReferenceParametersName() != null) {
+ referenceParametersExpression = createChildrenExpression(getReferenceParametersName(), namespaces);
+ }
+ else {
+ referenceParametersExpression = null;
+ }
+ }
+
+ private XPathExpression createExpression(QName name, Properties namespaces) {
+ String expression = name.getPrefix() + ":" + name.getLocalPart();
+ return XPathExpressionFactory.createXPathExpression(expression, namespaces);
+ }
+
+ private XPathExpression createNormalizedExpression(QName name, Properties namespaces) {
+ String expression = "normalize-space(" + name.getPrefix() + ":" + name.getLocalPart() + ")";
+ return XPathExpressionFactory.createXPathExpression(expression, namespaces);
+ }
+
+ private XPathExpression createChildrenExpression(QName name, Properties namespaces) {
+ String expression = name.getPrefix() + ":" + name.getLocalPart() + "/*";
+ return XPathExpressionFactory.createXPathExpression(expression, namespaces);
+ }
+
+ public MessageAddressingProperties getMessageAddressingProperties(SoapMessage message) {
+ 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) {
+ 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();
+ }
+ }
+ try {
+ DOMResult domResult = new DOMResult();
+ transform(header.getSource(), domResult);
+ Document document = (Document) domResult.getNode();
+ return document.getDocumentElement();
+ }
+ catch (TransformerException ex) {
+ throw new WsAddressingException("Could not transform SoapHeader to Document", ex);
+ }
+ }
+
+ /** 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 final boolean understands(SoapHeaderElement headerElement) {
+ return getNamespaceUri().equals(headerElement.getName().getNamespaceURI());
+ }
+
+ public final void addAddressingHeaders(SoapMessage message, MessageAddressingProperties map) {
+ SoapHeader header = message.getSoapHeader();
+ SoapHeaderElement messageId = header.addHeaderElement(getMessageIdName());
+ messageId.setText(map.getMessageId());
+ SoapHeaderElement relatesTo = header.addHeaderElement(getRelatesToName());
+ relatesTo.setText(map.getRelatesTo());
+ SoapHeaderElement to = header.addHeaderElement(getToName());
+ to.setText(map.getTo());
+ to.setMustUnderstand(true);
+ try {
+ Transformer transformer = createTransformer();
+ for (Iterator iterator = map.getReferenceParameters().iterator(); iterator.hasNext();) {
+ Node node = (Node) iterator.next();
+ DOMSource source = new DOMSource(node);
+ transformer.transform(source, header.getResult());
+ }
+ for (Iterator iterator = map.getReferenceProperties().iterator(); iterator.hasNext();) {
+ Node node = (Node) iterator.next();
+ DOMSource source = new DOMSource(node);
+ transformer.transform(source, header.getResult());
+ }
+ }
+ catch (TransformerException ex) {
+ throw new WsAddressingException("Could not add reference properties/parameters to message", ex);
+ }
+ }
+
+ public final SoapFault addInvalidAddressingHeaderFault(SoapMessage message) {
+ return addAddressingFault(message, getInvalidAddressingHeaderFaultSubcode(),
+ getInvalidAddressingHeaderFaultReason());
+ }
+
+ public final SoapFault addMessageAddressingHeaderRequiredFault(SoapMessage message) {
+ return addAddressingFault(message, getMessageAddressingHeaderRequiredFaultSubcode(),
+ 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;
+ }
+
+ /*
+ * Address URIs
+ */
+
+ public final boolean hasAnonymousAddress(EndpointReference epr) {
+ String anonymous = getAnonymousUri();
+ return anonymous != null && anonymous.equals(epr.getAddress());
+ }
+
+ public final boolean hasNoneAddress(EndpointReference epr) {
+ String none = getNoneUri();
+ return none != null && none.equals(epr.getAddress());
+ }
+
+ /** Returns the prefix associated with the WS-Addressing namespace handled by this specification. */
+ protected String getNamespacePrefix() {
+ return "wsa";
+ }
+
+ /** Returns the WS-Addressing namespace handled by this specification. */
+ protected abstract String getNamespaceUri();
+
+ /*
+ * Message addressing properties
+ */
+
+ /** Returns the qualified name of the To addressing header. */
+ protected QName getToName() {
+ return new QName(getNamespaceUri(), "To", getNamespacePrefix());
+ }
+
+ /** Returns the qualified name of the From addressing header. */
+ protected QName getFromName() {
+ return new QName(getNamespaceUri(), "From", getNamespacePrefix());
+ }
+
+ /** Returns the qualified name of the ReplyTo addressing header. */
+ protected QName getReplyToName() {
+ return new QName(getNamespaceUri(), "ReplyTo", getNamespacePrefix());
+ }
+
+ /** Returns the qualified name of the FaultTo addressing header. */
+ protected QName getFaultToName() {
+ return new QName(getNamespaceUri(), "FaultTo", getNamespacePrefix());
+ }
+
+ /** Returns the qualified name of the Action addressing header. */
+ protected QName getActionName() {
+ return new QName(getNamespaceUri(), "Action", getNamespacePrefix());
+ }
+
+ /** Returns the qualified name of the MessageID addressing header. */
+ protected QName getMessageIdName() {
+ return new QName(getNamespaceUri(), "MessageID", getNamespacePrefix());
+ }
+
+ /** Returns the qualified name of the RelatesTo addressing header. */
+ protected QName getRelatesToName() {
+ return new QName(getNamespaceUri(), "RelatesTo", getNamespacePrefix());
+ }
+
+ /**
+ * Returns the qualified name of the ReferenceProperties in the endpoint reference. Returns
+ * null when reference properties are not supported by this version of the spec.
+ */
+ protected QName getReferencePropertiesName() {
+ return new QName(getNamespaceUri(), "ReferenceProperties", getNamespacePrefix());
+ }
+
+ /**
+ * Returns the qualified name of the ReferenceParameters in the endpoint reference. Returns
+ * null when reference parameters are not supported by this version of the spec.
+ */
+ protected QName getReferenceParametersName() {
+ return new QName(getNamespaceUri(), "ReferenceParameters", getNamespacePrefix());
+ }
+
+ /*
+ * Endpoint Reference
+ */
+
+ /** The qualified name of the Address in EndpointReference. */
+ protected QName getAddressName() {
+ return new QName(getNamespaceUri(), "Address", getNamespacePrefix());
+ }
+
+ /*
+ * Address URIs
+ */
+
+ /** Returns the anonymous URI. */
+ protected abstract String getAnonymousUri();
+
+ /** Returns the none URI, or null if the spec does not define it. */
+ protected abstract String getNoneUri();
+
+ /*
+ * Faults
+ */
+
+ /** Returns the qualified name of the fault subcode that indicates that a header is missing. */
+ protected abstract QName getMessageAddressingHeaderRequiredFaultSubcode();
+
+ /** Returns the reason of the fault that indicates that a header is missing. */
+ protected abstract String getMessageAddressingHeaderRequiredFaultReason();
+
+ /** Returns the qualified name of the fault subcode that indicates that a header is invalid. */
+ protected abstract QName getInvalidAddressingHeaderFaultSubcode();
+
+ /** Returns the reason of the fault that indicates that a header is invalid. */
+ protected abstract String getInvalidAddressingHeaderFaultReason();
+}
diff --git a/sandbox/src/main/java/org/springframework/ws/soap/addressing/version/WsAddressing200408.java b/sandbox/src/main/java/org/springframework/ws/soap/addressing/version/WsAddressing200408.java
new file mode 100644
index 00000000..611b7613
--- /dev/null
+++ b/sandbox/src/main/java/org/springframework/ws/soap/addressing/version/WsAddressing200408.java
@@ -0,0 +1,44 @@
+package org.springframework.ws.soap.addressing.version;
+
+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, and supported by Axis 1 and 2, and XFire.
+ *
+ * @author Arjen Poutsma
+ * @see Web Services Addressing, August 2004
+ * @since 1.1.0
+ */
+public class WsAddressing200408 extends AbstractWsAddressingVersion {
+
+ private static final String NAMESPACE_URI = "http://schemas.xmlsoap.org/ws/2004/08/addressing";
+
+ protected final String getAnonymousUri() {
+ return NAMESPACE_URI + "/role/anonymous";
+ }
+
+ protected final String getInvalidAddressingHeaderFaultReason() {
+ return "A message information header is not valid and the message cannot be processed.";
+ }
+
+ protected final QName getInvalidAddressingHeaderFaultSubcode() {
+ return new QName(NAMESPACE_URI, "InvalidMessageInformationHeader", getNamespacePrefix());
+ }
+
+ protected final String getMessageAddressingHeaderRequiredFaultReason() {
+ return "A required message information header, To, MessageID, or Action, is not present.";
+ }
+
+ protected final QName getMessageAddressingHeaderRequiredFaultSubcode() {
+ return new QName(NAMESPACE_URI, "MessageInformationHeaderRequired", getNamespacePrefix());
+ }
+
+ protected final String getNamespaceUri() {
+ return NAMESPACE_URI;
+ }
+
+ protected final String getNoneUri() {
+ return null;
+ }
+}
diff --git a/sandbox/src/main/java/org/springframework/ws/soap/addressing/version/WsAddressing200605.java b/sandbox/src/main/java/org/springframework/ws/soap/addressing/version/WsAddressing200605.java
new file mode 100644
index 00000000..bacebae8
--- /dev/null
+++ b/sandbox/src/main/java/org/springframework/ws/soap/addressing/version/WsAddressing200605.java
@@ -0,0 +1,49 @@
+package org.springframework.ws.soap.addressing.version;
+
+import javax.xml.namespace.QName;
+
+/**
+ * Implements the May 2006 edition of the WS-Addressing specification. This version of the specification is used by
+ * Microsoft's Windows Communication Foundation (WCF), and supported by Axis 1 and 2.
+ *
+ * @author Arjen Poutsma
+ * @see Web Services Addressing, August 2004
+ * @since 1.1.0
+ */
+
+public class WsAddressing200605 extends AbstractWsAddressingVersion {
+
+ private static final String NAMESPACE_URI = "http://www.w3.org/2005/08/addressing";
+
+ protected String getNamespaceUri() {
+ return NAMESPACE_URI;
+ }
+
+ protected QName getReferencePropertiesName() {
+ return null;
+ }
+
+ protected final String getAnonymousUri() {
+ return NAMESPACE_URI + "/anonymous";
+ }
+
+ protected final String getNoneUri() {
+ return NAMESPACE_URI + "/none";
+ }
+
+ protected final QName getMessageAddressingHeaderRequiredFaultSubcode() {
+ return new QName(NAMESPACE_URI, "MessageAddressingHeaderRequired", getNamespacePrefix());
+ }
+
+ protected final String getMessageAddressingHeaderRequiredFaultReason() {
+ return "A required header representing a Message Addressing Property is not present";
+ }
+
+ protected QName getInvalidAddressingHeaderFaultSubcode() {
+ return new QName(NAMESPACE_URI, "InvalidAddressingHeader", getNamespacePrefix());
+ }
+
+ protected String getInvalidAddressingHeaderFaultReason() {
+ return "A header representing a Message Addressing Property is not valid and the message cannot be processed";
+ }
+}
diff --git a/sandbox/src/main/java/org/springframework/ws/soap/addressing/version/WsAddressingVersion.java b/sandbox/src/main/java/org/springframework/ws/soap/addressing/version/WsAddressingVersion.java
new file mode 100644
index 00000000..1c128bcf
--- /dev/null
+++ b/sandbox/src/main/java/org/springframework/ws/soap/addressing/version/WsAddressingVersion.java
@@ -0,0 +1,80 @@
+package org.springframework.ws.soap.addressing.version;
+
+import org.springframework.ws.soap.SoapFault;
+import org.springframework.ws.soap.SoapHeaderElement;
+import org.springframework.ws.soap.SoapMessage;
+import org.springframework.ws.soap.addressing.EndpointReference;
+import org.springframework.ws.soap.addressing.MessageAddressingProperties;
+
+/**
+ * Defines the contract for a specific version of the WS-Addressing specification.
+ *
+ * @author Arjen Poutsma
+ * @since 1.1.0
+ */
+public interface WsAddressingVersion {
+
+ /**
+ * Returns the {@link MessageAddressingProperties} for the given message.
+ *
+ * @param message the message to find the map for
+ * @return the message addressing properties
+ * @see Message Addressing Properties
+ */
+ MessageAddressingProperties getMessageAddressingProperties(SoapMessage message);
+
+ /**
+ * Adds addressing SOAP headers to the given message, using the given {@link MessageAddressingProperties}.
+ *
+ * @param message the message to add the headers to
+ * @param map the message addressing properties
+ */
+ void addAddressingHeaders(SoapMessage message, MessageAddressingProperties map);
+
+ /**
+ * Given a SoapHeaderElement, return whether or not this version understands it.
+ *
+ * @param headerElement the header
+ * @return true if understood, false otherwise
+ */
+ boolean understands(SoapHeaderElement headerElement);
+
+ /*
+ * Address URIs
+ */
+
+ /**
+ * 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 Formulating a Reply Message
+ */
+ boolean hasAnonymousAddress(EndpointReference epr);
+
+ /**
+ * Indicates whether the given endpoint reference has a None address. Messages to be sent to this address will not
+ * be sent.
+ *
+ * @see Sending a Message to an EPR
+ */
+ boolean hasNoneAddress(EndpointReference epr);
+
+ /*
+ * Faults
+ */
+
+ /**
+ * Adds a Invalid Addressing Header fault to the given message.
+ *
+ * @see Invalid Addressing Header
+ */
+ SoapFault addInvalidAddressingHeaderFault(SoapMessage message);
+
+ /**
+ * Adds a Message Addressing Header Required fault to the given message.
+ *
+ * @see Message Addressing Header Required
+ */
+ SoapFault addMessageAddressingHeaderRequiredFault(SoapMessage message);
+
+}
diff --git a/sandbox/src/main/java/org/springframework/ws/soap/addressing/version/package.html b/sandbox/src/main/java/org/springframework/ws/soap/addressing/version/package.html
new file mode 100644
index 00000000..6ed08533
--- /dev/null
+++ b/sandbox/src/main/java/org/springframework/ws/soap/addressing/version/package.html
@@ -0,0 +1,5 @@
+
+
+Contains various implementations of the WS-Addressing specification.
+
+
\ No newline at end of file
diff --git a/sandbox/src/test/java/org/springframework/ws/addressing/AbstractWsAddressingInterceptorTestCase.java b/sandbox/src/test/java/org/springframework/ws/addressing/AbstractWsAddressingInterceptorTestCase.java
new file mode 100644
index 00000000..d97107d3
--- /dev/null
+++ b/sandbox/src/test/java/org/springframework/ws/addressing/AbstractWsAddressingInterceptorTestCase.java
@@ -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();
+
+}
diff --git a/sandbox/src/test/java/org/springframework/ws/addressing/AbstractWsAddressingTestCase.java b/sandbox/src/test/java/org/springframework/ws/addressing/AbstractWsAddressingTestCase.java
new file mode 100644
index 00000000..f8ee36e9
--- /dev/null
+++ b/sandbox/src/test/java/org/springframework/ws/addressing/AbstractWsAddressingTestCase.java
@@ -0,0 +1,62 @@
+/*
+ * 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.io.IOException;
+import java.io.InputStream;
+import javax.xml.soap.MessageFactory;
+import javax.xml.soap.MimeHeaders;
+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;
+
+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();
+ }
+
+ protected void onSetUp() throws Exception {
+ }
+
+ protected SaajSoapMessage loadSaajMessage(String fileName) throws SOAPException, IOException {
+ 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));
+ }
+ finally {
+ 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);
+ }
+}
diff --git a/sandbox/src/test/java/org/springframework/ws/soap/addressing/WsAddressing200408InterceptorTest.java b/sandbox/src/test/java/org/springframework/ws/addressing/WsAddressing200408InterceptorTest.java
similarity index 100%
rename from sandbox/src/test/java/org/springframework/ws/soap/addressing/WsAddressing200408InterceptorTest.java
rename to sandbox/src/test/java/org/springframework/ws/addressing/WsAddressing200408InterceptorTest.java
diff --git a/sandbox/src/test/java/org/springframework/ws/soap/addressing/WsAddressing200508InterceptorTest.java b/sandbox/src/test/java/org/springframework/ws/addressing/WsAddressing200508InterceptorTest.java
similarity index 100%
rename from sandbox/src/test/java/org/springframework/ws/soap/addressing/WsAddressing200508InterceptorTest.java
rename to sandbox/src/test/java/org/springframework/ws/addressing/WsAddressing200508InterceptorTest.java
diff --git a/sandbox/src/test/java/org/springframework/ws/soap/addressing/AbstractWsAddressingInterceptorTestCase.java b/sandbox/src/test/java/org/springframework/ws/soap/addressing/AbstractWsAddressingInterceptorTestCase.java
index d97107d3..9107f5b7 100644
--- a/sandbox/src/test/java/org/springframework/ws/soap/addressing/AbstractWsAddressingInterceptorTestCase.java
+++ b/sandbox/src/test/java/org/springframework/ws/soap/addressing/AbstractWsAddressingInterceptorTestCase.java
@@ -6,58 +6,61 @@ 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.addressing.messageid.MessageIdStrategy;
+import org.springframework.ws.soap.addressing.version.WsAddressingVersion;
import org.springframework.ws.soap.saaj.SaajSoapMessage;
import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
+import org.springframework.ws.transport.WebServiceConnection;
+import org.springframework.ws.transport.WebServiceMessageSender;
public abstract class AbstractWsAddressingInterceptorTestCase extends AbstractWsAddressingTestCase {
- protected AbstractWsAddressingInterceptor interceptor;
+ protected WsAddressingInterceptor interceptor;
- private MockControl providerControl;
+ private MockControl strategyControl;
- private MessageIdProvider providerMock;
+ private MessageIdStrategy strategyMock;
protected final void onSetUp() throws Exception {
- providerControl = MockControl.createControl(MessageIdProvider.class);
- providerMock = (MessageIdProvider) providerControl.getMock();
- interceptor = createInterceptor();
- interceptor.setMessageIdProvider(providerMock);
+ strategyControl = MockControl.createControl(MessageIdStrategy.class);
+ strategyMock = (MessageIdStrategy) strategyControl.getMock();
+ strategyControl.expectAndDefaultReturn(strategyMock.isDuplicate(null), false);
+ interceptor = new WsAddressingInterceptor(getVersion(), strategyMock, new WebServiceMessageSender[0]);
}
public void testUnderstands() throws Exception {
SaajSoapMessage validRequest = loadSaajMessage(getTestPath() + "/valid.xml");
Iterator iterator = validRequest.getSoapHeader().examineAllHeaderElements();
- providerControl.replay();
+ strategyControl.replay();
while (iterator.hasNext()) {
SoapHeaderElement headerElement = (SoapHeaderElement) iterator.next();
assertTrue("Header [" + headerElement.getName() + " not understood",
interceptor.understands(headerElement));
}
- providerControl.verify();
+ strategyControl.verify();
}
public void testHandleValidRequest() throws Exception {
SaajSoapMessage valid = loadSaajMessage(getTestPath() + "/valid.xml");
MessageContext context = new DefaultMessageContext(valid, new SaajSoapMessageFactory(messageFactory));
- providerControl.replay();
+ strategyControl.replay();
boolean result = interceptor.handleRequest(context, null);
assertTrue("Valid request not handled", result);
assertFalse("Message Context has response", context.hasResponse());
- providerControl.verify();
+ strategyControl.verify();
}
public void testHandleInvalidRequest() throws Exception {
SaajSoapMessage valid = loadSaajMessage(getTestPath() + "/invalid.xml");
MessageContext context = new DefaultMessageContext(valid, new SaajSoapMessageFactory(messageFactory));
- providerControl.replay();
+ strategyControl.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();
+ strategyControl.verify();
}
public void testHandleAnonymousReplyTo() throws Exception {
@@ -65,38 +68,61 @@ public abstract class AbstractWsAddressingInterceptorTestCase extends AbstractWs
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();
+ strategyControl.expectAndReturn(strategyMock.newMessageId(response), messageId);
+ strategyControl.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();
+ strategyControl.verify();
}
public void testHandleNoneReplyTo() throws Exception {
SaajSoapMessage valid = loadSaajMessage(getTestPath() + "/none.xml");
MessageContext context = new DefaultMessageContext(valid, new SaajSoapMessageFactory(messageFactory));
- providerControl.replay();
+ strategyControl.replay();
boolean result = interceptor.handleResponse(context, null);
assertFalse("None request handled", result);
- providerControl.verify();
+ strategyControl.verify();
}
public void testHandleOutOfBandReplyTo() throws Exception {
+ MockControl senderControl = MockControl.createControl(WebServiceMessageSender.class);
+ WebServiceMessageSender senderMock = (WebServiceMessageSender) senderControl.getMock();
+
+ interceptor =
+ new WsAddressingInterceptor(getVersion(), strategyMock, new WebServiceMessageSender[]{senderMock});
+
+ MockControl connectionControl = MockControl.createControl(WebServiceConnection.class);
+ WebServiceConnection connectionMock = (WebServiceConnection) connectionControl.getMock();
+
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();
+ strategyControl.expectAndReturn(strategyMock.newMessageId(response), messageId);
+
+ String uri = "http://example.com/business/client1";
+ senderControl.expectAndReturn(senderMock.supports(uri), true);
+ senderControl.expectAndReturn(senderMock.createConnection(uri), connectionMock);
+ connectionMock.send(response);
+ connectionMock.close();
+
+ strategyControl.replay();
+ senderControl.replay();
+ connectionControl.replay();
+
boolean result = interceptor.handleResponse(context, null);
assertFalse("Out of Band request handled", result);
- providerControl.verify();
+
+ strategyControl.verify();
+ senderControl.verify();
+ connectionControl.verify();
}
- protected abstract AbstractWsAddressingInterceptor createInterceptor();
+ protected abstract WsAddressingVersion getVersion();
protected abstract String getTestPath();
diff --git a/sandbox/src/test/java/org/springframework/ws/soap/addressing/WsAddressingInterceptor200408Test.java b/sandbox/src/test/java/org/springframework/ws/soap/addressing/WsAddressingInterceptor200408Test.java
new file mode 100644
index 00000000..21b50d9d
--- /dev/null
+++ b/sandbox/src/test/java/org/springframework/ws/soap/addressing/WsAddressingInterceptor200408Test.java
@@ -0,0 +1,19 @@
+package org.springframework.ws.soap.addressing;
+
+import org.springframework.ws.soap.addressing.version.WsAddressing200408;
+import org.springframework.ws.soap.addressing.version.WsAddressingVersion;
+
+public class WsAddressingInterceptor200408Test extends AbstractWsAddressingInterceptorTestCase {
+
+ protected WsAddressingVersion getVersion() {
+ return new WsAddressing200408();
+ }
+
+ protected String getTestPath() {
+ return "200408";
+ }
+
+ public void testHandleNoneReplyTo() throws Exception {
+ // This version of the spec does not have none addresses
+ }
+}
diff --git a/sandbox/src/test/java/org/springframework/ws/soap/addressing/WsAddressingInterceptor200605Test.java b/sandbox/src/test/java/org/springframework/ws/soap/addressing/WsAddressingInterceptor200605Test.java
new file mode 100644
index 00000000..f305615a
--- /dev/null
+++ b/sandbox/src/test/java/org/springframework/ws/soap/addressing/WsAddressingInterceptor200605Test.java
@@ -0,0 +1,15 @@
+package org.springframework.ws.soap.addressing;
+
+import org.springframework.ws.soap.addressing.version.WsAddressing200605;
+import org.springframework.ws.soap.addressing.version.WsAddressingVersion;
+
+public class WsAddressingInterceptor200605Test extends AbstractWsAddressingInterceptorTestCase {
+
+ protected WsAddressingVersion getVersion() {
+ return new WsAddressing200605();
+ }
+
+ protected String getTestPath() {
+ return "200508";
+ }
+}
\ No newline at end of file
diff --git a/sandbox/src/test/java/org/springframework/ws/soap/addressing/messageid/AbstractMessageIdProviderTestCase.java b/sandbox/src/test/java/org/springframework/ws/soap/addressing/messageid/AbstractMessageIdStrategyTestCase.java
similarity index 77%
rename from sandbox/src/test/java/org/springframework/ws/soap/addressing/messageid/AbstractMessageIdProviderTestCase.java
rename to sandbox/src/test/java/org/springframework/ws/soap/addressing/messageid/AbstractMessageIdStrategyTestCase.java
index 50bc7b6a..0bfef2aa 100644
--- a/sandbox/src/test/java/org/springframework/ws/soap/addressing/messageid/AbstractMessageIdProviderTestCase.java
+++ b/sandbox/src/test/java/org/springframework/ws/soap/addressing/messageid/AbstractMessageIdStrategyTestCase.java
@@ -19,20 +19,20 @@ package org.springframework.ws.soap.addressing.messageid;
import junit.framework.TestCase;
import org.springframework.util.StringUtils;
-public abstract class AbstractMessageIdProviderTestCase extends TestCase {
+public abstract class AbstractMessageIdStrategyTestCase extends TestCase {
- private MessageIdProvider provider;
+ private MessageIdStrategy strategy;
protected final void setUp() throws Exception {
- provider = createProvider();
+ strategy = createProvider();
}
- protected abstract MessageIdProvider createProvider();
+ protected abstract MessageIdStrategy createProvider();
public void testProvider() {
- String messageId1 = provider.getMessageId(null);
+ String messageId1 = strategy.newMessageId(null);
assertTrue("Empty messageId", StringUtils.hasLength(messageId1));
- String messageId2 = provider.getMessageId(null);
+ String messageId2 = strategy.newMessageId(null);
assertTrue("Empty messageId", StringUtils.hasLength(messageId2));
assertFalse("Equal messageIds", messageId1.equals(messageId2));
}
diff --git a/sandbox/src/test/java/org/springframework/ws/soap/addressing/messageid/UidMessageIdProviderTest.java b/sandbox/src/test/java/org/springframework/ws/soap/addressing/messageid/UidMessageIdStrategyTest.java
similarity index 79%
rename from sandbox/src/test/java/org/springframework/ws/soap/addressing/messageid/UidMessageIdProviderTest.java
rename to sandbox/src/test/java/org/springframework/ws/soap/addressing/messageid/UidMessageIdStrategyTest.java
index eb3d719d..eabcab3e 100644
--- a/sandbox/src/test/java/org/springframework/ws/soap/addressing/messageid/UidMessageIdProviderTest.java
+++ b/sandbox/src/test/java/org/springframework/ws/soap/addressing/messageid/UidMessageIdStrategyTest.java
@@ -16,9 +16,9 @@
package org.springframework.ws.soap.addressing.messageid;
-public class UidMessageIdProviderTest extends AbstractMessageIdProviderTestCase {
+public class UidMessageIdStrategyTest extends AbstractMessageIdStrategyTestCase {
- protected MessageIdProvider createProvider() {
- return new UidMessageIdProvider();
+ protected MessageIdStrategy createProvider() {
+ return new UidMessageIdStrategy();
}
}
\ No newline at end of file
diff --git a/sandbox/src/test/java/org/springframework/ws/soap/addressing/messageid/UuidMessageIdProviderTest.java b/sandbox/src/test/java/org/springframework/ws/soap/addressing/messageid/UuidMessageIdStrategyTest.java
similarity index 79%
rename from sandbox/src/test/java/org/springframework/ws/soap/addressing/messageid/UuidMessageIdProviderTest.java
rename to sandbox/src/test/java/org/springframework/ws/soap/addressing/messageid/UuidMessageIdStrategyTest.java
index 78376c7c..8ab89be0 100644
--- a/sandbox/src/test/java/org/springframework/ws/soap/addressing/messageid/UuidMessageIdProviderTest.java
+++ b/sandbox/src/test/java/org/springframework/ws/soap/addressing/messageid/UuidMessageIdStrategyTest.java
@@ -16,10 +16,10 @@
package org.springframework.ws.soap.addressing.messageid;
-public class UuidMessageIdProviderTest extends AbstractMessageIdProviderTestCase {
+public class UuidMessageIdStrategyTest extends AbstractMessageIdStrategyTestCase {
- protected MessageIdProvider createProvider() {
- return new UuidMessageIdProvider();
+ protected MessageIdStrategy createProvider() {
+ return new UuidMessageIdStrategy();
}
}
\ No newline at end of file
diff --git a/sandbox/src/test/resources/org/springframework/ws/soap/addressing/200408/anonymous.xml b/sandbox/src/test/resources/org/springframework/ws/soap/addressing/200408/anonymous.xml
deleted file mode 100644
index 6db3c331..00000000
--- a/sandbox/src/test/resources/org/springframework/ws/soap/addressing/200408/anonymous.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-