Working on SWS-84 (WS-Addressing)
This commit is contained in:
@@ -112,7 +112,7 @@ public abstract class AbstractMethodEndpointMapping extends AbstractEndpointMapp
|
||||
Assert.notNull(endpoint, "'endpoint' must not be null");
|
||||
Method[] methods = getEndpointClass(endpoint).getMethods();
|
||||
for (int i = 0; i < methods.length; i++) {
|
||||
if (JdkVersion.getMajorJavaVersion() >= JdkVersion.JAVA_15 && methods[i].isSynthetic() ||
|
||||
if (JdkVersion.isAtLeastJava15() && methods[i].isSynthetic() ||
|
||||
methods[i].getDeclaringClass().equals(Object.class)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* 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.net.URI;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import javax.xml.transform.TransformerException;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
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.MessageIdStrategy;
|
||||
import org.springframework.ws.soap.addressing.messageid.RandomGuidMessageIdStrategy;
|
||||
import org.springframework.ws.soap.addressing.messageid.UuidMessageIdStrategy;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Abstract base class for {@link EndpointMapping} implementations that implement WS-Addressing.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public abstract class AbstractWsAddressingEndpointMapping extends TransformerObjectSupport
|
||||
implements SoapEndpointMapping, InitializingBean {
|
||||
|
||||
private String[] actorsOrRoles;
|
||||
|
||||
private boolean isUltimateReceiver = true;
|
||||
|
||||
private MessageIdStrategy messageIdStrategy;
|
||||
|
||||
private WebServiceMessageSender[] messageSenders;
|
||||
|
||||
private WsAddressingVersion[] versions;
|
||||
|
||||
private EndpointInterceptor[] preInterceptors = new EndpointInterceptor[0];
|
||||
|
||||
private EndpointInterceptor[] postInterceptors = new EndpointInterceptor[0];
|
||||
|
||||
/** Protected constructor. Initializes the default settings. */
|
||||
protected AbstractWsAddressingEndpointMapping() {
|
||||
initDefaultStrategies();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the default implementation for this mapping's strategies: the {@link WsAddressing200408} and {@link
|
||||
* WsAddressing200605} versions of the specication, and the {@link UuidMessageIdStrategy} on Java 5 and higher; the
|
||||
* {@link RandomGuidMessageIdStrategy} on Java 1.4.
|
||||
*/
|
||||
protected void initDefaultStrategies() {
|
||||
this.versions = new WsAddressingVersion[]{new WsAddressing200408(), new WsAddressing200605()};
|
||||
if (JdkVersion.isAtLeastJava15()) {
|
||||
messageIdStrategy = new UuidMessageIdStrategy();
|
||||
}
|
||||
else {
|
||||
messageIdStrategy = new RandomGuidMessageIdStrategy();
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
* <code>XwsSecurityInterceptor</code>.
|
||||
*/
|
||||
public final void setPreInterceptors(EndpointInterceptor[] preInterceptors) {
|
||||
Assert.notNull(preInterceptors, "'preInterceptors' must not be null");
|
||||
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) {
|
||||
Assert.notNull(postInterceptors, "'postInterceptors' must not be null");
|
||||
this.postInterceptors = postInterceptors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the message id provider used for creating WS-Addressing MessageIds.
|
||||
* <p/>
|
||||
* By default, the {@link UuidMessageIdStrategy} is used on Java 5 and higher, and the {@link
|
||||
* RandomGuidMessageIdStrategy} on Java 1.4.
|
||||
*/
|
||||
public final void setMessageIdProvider(MessageIdStrategy messageIdStrategy) {
|
||||
this.messageIdStrategy = messageIdStrategy;
|
||||
}
|
||||
|
||||
public final void setMessageSenders(WebServiceMessageSender[] messageSenders) {
|
||||
this.messageSenders = messageSenders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the WS-Addressing versions to be supported by this mapping.
|
||||
* <p/>
|
||||
* 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 setVersions(WsAddressingVersion[] versions) {
|
||||
this.versions = versions;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Supporting versions " + Arrays.asList(versions));
|
||||
}
|
||||
}
|
||||
|
||||
public final EndpointInvocationChain getEndpoint(MessageContext messageContext) throws TransformerException {
|
||||
Assert.isInstanceOf(SoapMessage.class, messageContext.getRequest());
|
||||
SoapMessage request = (SoapMessage) messageContext.getRequest();
|
||||
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 getEndpointInvocationChain(endpoint, versions[i]);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Creates a {@link SoapEndpointInvocationChain} based on the given endpoint and {@link WsAddressingVersion}. */
|
||||
private EndpointInvocationChain getEndpointInvocationChain(Object endpoint, WsAddressingVersion version) {
|
||||
URI responseAction = getResponseAction(endpoint);
|
||||
URI faultAction = getFaultAction(endpoint);
|
||||
EndpointInterceptor[] interceptors =
|
||||
new EndpointInterceptor[preInterceptors.length + postInterceptors.length + 1];
|
||||
System.arraycopy(preInterceptors, 0, interceptors, 0, preInterceptors.length);
|
||||
AddressingEndpointInterceptor interceptor = new AddressingEndpointInterceptor(version, messageIdStrategy,
|
||||
messageSenders, responseAction, faultAction);
|
||||
interceptors[preInterceptors.length] = interceptor;
|
||||
System.arraycopy(postInterceptors, 0, interceptors, preInterceptors.length + 1, postInterceptors.length);
|
||||
return new SoapEndpointInvocationChain(endpoint, interceptors, actorsOrRoles, isUltimateReceiver);
|
||||
}
|
||||
|
||||
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 (version.understands(headerElement)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
protected URI getResponseAction(Object endpoint) {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected URI getFaultAction(Object endpoint) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright 2008 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.lang.reflect.Method;
|
||||
import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContextException;
|
||||
import org.springframework.core.JdkVersion;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.ws.server.endpoint.MethodEndpoint;
|
||||
|
||||
/**
|
||||
* @author Arjen Poutsma
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public abstract class AbstractWsAddressingMethodEndpointMapping extends AbstractWsAddressingEndpointMapping {
|
||||
|
||||
/** Keys are URI Actions, values are {@link MethodEndpoint}s. */
|
||||
private final Map endpointMap = new HashMap();
|
||||
|
||||
protected Object getEndpointInternal(MessageAddressingProperties map) {
|
||||
URI action = map.getAction();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Looking up endpoint for [" + key + "]");
|
||||
}
|
||||
return lookupEndpoint(key);
|
||||
|
||||
//TODO implement
|
||||
throw new UnsupportedOperationException("Not implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up an endpoint instance for the given Action URI.
|
||||
*
|
||||
* @param action the Addressing action being mapped to
|
||||
* @return the associated endpoint instance, or <code>null</code> if not found
|
||||
*/
|
||||
protected MethodEndpoint lookupEndpoint(URI action) {
|
||||
return (MethodEndpoint) endpointMap.get(action);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the given endpoint instance under the action URI.
|
||||
*
|
||||
* @param action the lookup key
|
||||
* @param endpoint the method endpoint instance
|
||||
* @throws BeansException if the endpoint could not be registered
|
||||
*/
|
||||
protected void registerEndpoint(URI action, MethodEndpoint endpoint) throws BeansException {
|
||||
Object mappedEndpoint = endpointMap.get(action);
|
||||
if (mappedEndpoint != null) {
|
||||
throw new ApplicationContextException("Cannot map endpoint [" + endpoint + "] on action [" + action +
|
||||
"]: there's already endpoint [" + mappedEndpoint + "] mapped");
|
||||
}
|
||||
if (endpoint == null) {
|
||||
throw new ApplicationContextException("Could not find endpoint for action [" + action + "]");
|
||||
}
|
||||
endpointMap.put(action, endpoint);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Mapped action [" + action + "] onto endpoint [" + endpoint + "]");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method that registers the methods of the given bean. This method iterates over the methods of the bean,
|
||||
* and calls {@link #getActionForMethod(java.lang.reflect.Method)} for each. If this returns a string, the method is
|
||||
* registered using {@link #registerEndpoint(URI, MethodEndpoint)}.
|
||||
*
|
||||
* @see #getActionForMethod (java.lang.reflect.Method)
|
||||
*/
|
||||
protected void registerMethods(Object endpoint) {
|
||||
Assert.notNull(endpoint, "'endpoint' must not be null");
|
||||
Method[] methods = getEndpointClass(endpoint).getMethods();
|
||||
for (int i = 0; i < methods.length; i++) {
|
||||
if (JdkVersion.isAtLeastJava15() && methods[i].isSynthetic() ||
|
||||
methods[i].getDeclaringClass().equals(Object.class)) {
|
||||
continue;
|
||||
}
|
||||
URI action = getActionForMethod(methods[i]);
|
||||
if (action != null) {
|
||||
registerEndpoint(action, new MethodEndpoint(endpoint, methods[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the the action URI for the given method. Returns <code>null</code> if the method is not to be registered,
|
||||
* which is the default.
|
||||
*
|
||||
* @param method the method
|
||||
* @return the action URI, or <code>null</code> if the method is not to be registered
|
||||
*/
|
||||
protected URI getActionForMethod(Method method) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the class or interface to use for method reflection.
|
||||
* <p/>
|
||||
* Default implementation delegates to {@link AopUtils#getTargetClass(Object)}.
|
||||
*
|
||||
* @param endpoint the bean instance (might be an AOP proxy)
|
||||
* @return the bean class to expose
|
||||
*/
|
||||
protected Class getEndpointClass(Object endpoint) {
|
||||
return AopUtils.getTargetClass(endpoint);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -190,6 +190,10 @@ public abstract class AbstractWsAddressingVersion extends TransformerObjectSuppo
|
||||
SoapHeaderElement to = header.addHeaderElement(getToName());
|
||||
to.setText(map.getTo().toString());
|
||||
to.setMustUnderstand(true);
|
||||
if (map.getAction() != null) {
|
||||
SoapHeaderElement action = header.addHeaderElement(getActionName());
|
||||
action.setText(map.getAction().toString());
|
||||
}
|
||||
try {
|
||||
Transformer transformer = createTransformer();
|
||||
for (Iterator iterator = map.getReferenceParameters().iterator(); iterator.hasNext();) {
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* 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.net.URI;
|
||||
|
||||
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.server.SoapEndpointInterceptor;
|
||||
import org.springframework.ws.transport.WebServiceConnection;
|
||||
import org.springframework.ws.transport.WebServiceMessageSender;
|
||||
|
||||
/**
|
||||
* {@link SoapEndpointInterceptor} implementation that deals with WS-Addressing headers. Stateful, and instatiated by
|
||||
* the {@link AbstractWsAddressingEndpointMapping}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 1.5.0
|
||||
*/
|
||||
class AddressingEndpointInterceptor implements SoapEndpointInterceptor {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(AddressingEndpointInterceptor.class);
|
||||
|
||||
private final WsAddressingVersion version;
|
||||
|
||||
private final MessageIdStrategy messageIdStrategy;
|
||||
|
||||
private final WebServiceMessageSender[] messageSenders;
|
||||
|
||||
private URI replyAction;
|
||||
|
||||
private URI faultAction;
|
||||
|
||||
AddressingEndpointInterceptor(WsAddressingVersion version,
|
||||
MessageIdStrategy messageIdStrategy,
|
||||
WebServiceMessageSender[] messageSenders,
|
||||
URI replyAction,
|
||||
URI faultAction) {
|
||||
Assert.notNull(version, "version must not be null");
|
||||
Assert.notNull(messageIdStrategy, "messageIdStrategy must not be null");
|
||||
if (messageSenders == null) {
|
||||
messageSenders = new WebServiceMessageSender[0];
|
||||
}
|
||||
this.version = version;
|
||||
this.messageIdStrategy = messageIdStrategy;
|
||||
this.messageSenders = messageSenders;
|
||||
this.replyAction = replyAction;
|
||||
this.faultAction = faultAction;
|
||||
}
|
||||
|
||||
public final boolean handleRequest(MessageContext messageContext, Object endpoint) throws Exception {
|
||||
Assert.isInstanceOf(SoapMessage.class, messageContext.getRequest());
|
||||
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 final boolean handleResponse(MessageContext messageContext, Object endpoint) throws Exception {
|
||||
return handleResponseOrFault(messageContext, false);
|
||||
}
|
||||
|
||||
public final boolean handleFault(MessageContext messageContext, Object endpoint) throws Exception {
|
||||
return handleResponseOrFault(messageContext, true);
|
||||
}
|
||||
|
||||
private boolean handleResponseOrFault(MessageContext messageContext, boolean isFault) throws Exception {
|
||||
Assert.isInstanceOf(SoapMessage.class, messageContext.getRequest());
|
||||
Assert.isInstanceOf(SoapMessage.class, messageContext.getResponse());
|
||||
MessageAddressingProperties requestMap =
|
||||
version.getMessageAddressingProperties((SoapMessage) messageContext.getRequest());
|
||||
EndpointReference replyEpr = !isFault ? requestMap.getReplyTo() : requestMap.getFaultTo();
|
||||
if (handleNoneAddress(messageContext, replyEpr)) {
|
||||
return false;
|
||||
}
|
||||
URI responseMessageId = getMessageId(messageContext);
|
||||
URI action = !isFault ? replyAction : faultAction;
|
||||
MessageAddressingProperties replyMap = requestMap.getReplyProperties(replyEpr, action, responseMessageId);
|
||||
version.addAddressingHeaders((SoapMessage) messageContext.getResponse(), replyMap);
|
||||
if (handleAnonymousAddress(messageContext, replyEpr)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
sendOutOfBand(messageContext, replyEpr);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean handleNoneAddress(MessageContext messageContext, EndpointReference replyEpr) {
|
||||
if (replyEpr == null || version.hasNoneAddress(replyEpr)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Request " + messageContext.getRequest() + "] has [" + replyEpr +
|
||||
"] reply address; reply [" + messageContext.getResponse() + "] discarded");
|
||||
}
|
||||
messageContext.clearResponse();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean handleAnonymousAddress(MessageContext messageContext, EndpointReference replyEpr) {
|
||||
if (version.hasAnonymousAddress(replyEpr)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Request " + messageContext.getRequest() + "] has [" + replyEpr +
|
||||
"] reply address; sending in-band reply [" + messageContext.getResponse() + "]");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void sendOutOfBand(MessageContext messageContext, EndpointReference replyEpr) throws IOException {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Request " + messageContext.getRequest() + "] has [" + replyEpr +
|
||||
"] reply address; sending out-of-band reply [" + messageContext.getResponse() + "]");
|
||||
}
|
||||
|
||||
boolean supported = false;
|
||||
for (int i = 0; i < messageSenders.length; i++) {
|
||||
if (messageSenders[i].supports(replyEpr.getAddress())) {
|
||||
supported = true;
|
||||
WebServiceConnection connection = null;
|
||||
try {
|
||||
connection = messageSenders[i].createConnection(replyEpr.getAddress());
|
||||
connection.send(messageContext.getResponse());
|
||||
break;
|
||||
}
|
||||
finally {
|
||||
messageContext.clearResponse();
|
||||
if (connection != null) {
|
||||
connection.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!supported) {
|
||||
logger.warn("Could not send out-of-band response to [" + replyEpr.getAddress() + "]. " +
|
||||
"Configure WebServiceMessageSenders which support this uri.");
|
||||
}
|
||||
}
|
||||
|
||||
private URI getMessageId(MessageContext messageContext) {
|
||||
URI responseMessageId = messageIdStrategy.newMessageId(messageContext);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Generated reply MessageID [" + responseMessageId + "] for [" + messageContext + "]");
|
||||
}
|
||||
return responseMessageId;
|
||||
}
|
||||
|
||||
public boolean understands(SoapHeaderElement header) {
|
||||
return version.understands(header);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2008 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.beans.PropertyEditorSupport;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Editor for <code>EndpointReference</code>, to directly populate a EPR property instead of using a String property as
|
||||
* bridge.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see EndpointReference
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public class EndpointReferenceEditor extends PropertyEditorSupport {
|
||||
|
||||
public void setAsText(String text) throws IllegalArgumentException {
|
||||
if (StringUtils.hasText(text)) {
|
||||
String uri = text.trim();
|
||||
try {
|
||||
URI address = new URI(uri);
|
||||
setValue(new EndpointReference(address));
|
||||
}
|
||||
catch (URISyntaxException ex) {
|
||||
throw new IllegalArgumentException("Invalid URI syntax: " + ex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
setValue(null);
|
||||
}
|
||||
}
|
||||
|
||||
public String getAsText() {
|
||||
EndpointReference value = (EndpointReference) getValue();
|
||||
return (value != null ? value.toString() : "");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright 2008 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.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Implementation of the <code>EndpointMapping</code> interface to map from WS-Addressing <code>Action</code> headers to
|
||||
* endpoint beans. Supports both mapping to bean instances and mapping to bean names.
|
||||
* <p/>
|
||||
* The <code>endpointMap</code> property is suitable for populating the endpoint map with bean references, e.g. via the
|
||||
* map element in XML bean definitions.
|
||||
* <p/>
|
||||
* Mappings to bean names can be set via the <code>mappings</code> property, in a form accepted by the
|
||||
* <code>java.util.Properties</code> class, like as follows:
|
||||
* <pre>
|
||||
* http://www.springframework.org/spring-ws/samples/airline/BookFlight=bookFlightEndpoint
|
||||
* http://www.springframework.org/spring-ws/samples/airline/GetFlights=getFlightsEndpoint
|
||||
* </pre>
|
||||
* The syntax is WS_ADDRESSING_ACTION=ENDPOINT_BEAN_NAME.
|
||||
* <p/>
|
||||
* If set, the <code>destination</code> property is used suitable for further endpoint determination. can be used to set
|
||||
* an EndpointReference destination (i.e. the <code>To</code> element). If this propert
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public class WsAddressingActionEndpointMapping extends AbstractWsAddressingEndpointMapping
|
||||
implements ApplicationContextAware {
|
||||
|
||||
// keys are action URIs, values are endpoints
|
||||
private final Map endpointMap = new HashMap();
|
||||
|
||||
// contents will be copied over to endpointMap
|
||||
private final Map temporaryEndpointMap = new HashMap();
|
||||
|
||||
private URI destination;
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
public void setMappings(Properties mappings) throws URISyntaxException {
|
||||
setEndpointMap(mappings);
|
||||
}
|
||||
|
||||
public void setEndpointMap(Map actionMap) throws URISyntaxException {
|
||||
Iterator it = actionMap.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry entry = (Map.Entry) it.next();
|
||||
URI action;
|
||||
if (entry.getKey() instanceof String) {
|
||||
action = new URI((String) entry.getKey());
|
||||
}
|
||||
else if (entry.getKey() instanceof URI) {
|
||||
action = (URI) entry.getKey();
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Invalid key [" + entry.getKey() + "]; expected String or URI");
|
||||
}
|
||||
this.temporaryEndpointMap.put(action, entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
public void setDestination(URI destination) {
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
registerEndpoints(temporaryEndpointMap);
|
||||
}
|
||||
|
||||
protected Object getEndpointInternal(MessageAddressingProperties map) {
|
||||
// MAP address much match the defined EPR address
|
||||
if (destination != null && !destination.equals(map.getTo())) {
|
||||
return null;
|
||||
}
|
||||
return endpointMap.get(map.getAction());
|
||||
}
|
||||
|
||||
protected void registerEndpoints(Map endpointMap) throws BeansException {
|
||||
if (endpointMap.isEmpty()) {
|
||||
logger.warn("Neither 'actionMap' nor 'mappings' set on WsAddressingActionEndpointMapping");
|
||||
}
|
||||
else {
|
||||
Iterator it = endpointMap.entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry entry = (Map.Entry) it.next();
|
||||
URI action = (URI) entry.getKey();
|
||||
Object endpoint = entry.getValue();
|
||||
// Remove whitespace from endpoint bean name.
|
||||
if (endpoint instanceof String) {
|
||||
endpoint = ((String) endpoint).trim();
|
||||
}
|
||||
registerEndpoint(action, endpoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void registerEndpoint(URI action, Object endpoint) throws BeansException, IllegalStateException {
|
||||
Assert.notNull(action, "Action must not be null");
|
||||
Assert.notNull(endpoint, "Endpoint object must not be null");
|
||||
Object resolvedEndpoint = endpoint;
|
||||
|
||||
if (endpoint instanceof String) {
|
||||
String endpointName = (String) endpoint;
|
||||
if (applicationContext.isSingleton(endpointName)) {
|
||||
resolvedEndpoint = applicationContext.getBean(endpointName);
|
||||
}
|
||||
}
|
||||
Object mappedEndpoint = this.endpointMap.get(action);
|
||||
if (mappedEndpoint != null) {
|
||||
if (mappedEndpoint != resolvedEndpoint) {
|
||||
throw new IllegalStateException("Cannot map endpoint [" + endpoint + "] to action [" + action +
|
||||
"]: There is already endpoint [" + resolvedEndpoint + "] mapped.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.endpointMap.put(action, resolvedEndpoint);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Mapped Action [" + action + "] onto endpoint [" + resolvedEndpoint + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2008 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.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author Arjen Poutsma
|
||||
* @since 1.5.0
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface Action {
|
||||
|
||||
}
|
||||
@@ -19,9 +19,9 @@ 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 {
|
||||
public abstract class AbstractAddressingInterceptorTestCase extends AbstractWsAddressingTestCase {
|
||||
|
||||
private WsAddressingEndpointInterceptor interceptor;
|
||||
private AddressingEndpointInterceptor interceptor;
|
||||
|
||||
private MockControl strategyControl;
|
||||
|
||||
@@ -31,7 +31,10 @@ public abstract class AbstractWsAddressingInterceptorTestCase extends AbstractWs
|
||||
strategyControl = MockControl.createControl(MessageIdStrategy.class);
|
||||
strategyMock = (MessageIdStrategy) strategyControl.getMock();
|
||||
strategyControl.expectAndDefaultReturn(strategyMock.isDuplicate(null), false);
|
||||
interceptor = new WsAddressingEndpointInterceptor(getVersion(), strategyMock, new WebServiceMessageSender[0]);
|
||||
URI replyAction = new URI("urn:replyAction");
|
||||
URI faultAction = new URI("urn:faultAction");
|
||||
interceptor = new AddressingEndpointInterceptor(getVersion(), strategyMock, new WebServiceMessageSender[0],
|
||||
replyAction, faultAction);
|
||||
}
|
||||
|
||||
public void testUnderstands() throws Exception {
|
||||
@@ -128,8 +131,10 @@ public abstract class AbstractWsAddressingInterceptorTestCase extends AbstractWs
|
||||
MockControl senderControl = MockControl.createControl(WebServiceMessageSender.class);
|
||||
WebServiceMessageSender senderMock = (WebServiceMessageSender) senderControl.getMock();
|
||||
|
||||
interceptor = new WsAddressingEndpointInterceptor(getVersion(), strategyMock,
|
||||
new WebServiceMessageSender[]{senderMock});
|
||||
URI replyAction = new URI("urn:replyAction");
|
||||
URI faultAction = new URI("urn:replyAction");
|
||||
interceptor = new AddressingEndpointInterceptor(getVersion(), strategyMock,
|
||||
new WebServiceMessageSender[]{senderMock}, replyAction, faultAction);
|
||||
|
||||
MockControl connectionControl = MockControl.createControl(WebServiceConnection.class);
|
||||
WebServiceConnection connectionMock = (WebServiceConnection) connectionControl.getMock();
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
package org.springframework.ws.soap.addressing;
|
||||
|
||||
public class WsAddressingInterceptor200408Test extends AbstractWsAddressingInterceptorTestCase {
|
||||
public class AddressingInterceptor200408Test extends AbstractAddressingInterceptorTestCase {
|
||||
|
||||
protected WsAddressingVersion getVersion() {
|
||||
return new WsAddressing200408();
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
package org.springframework.ws.soap.addressing;
|
||||
|
||||
public class WsAddressingInterceptor200605Test extends AbstractWsAddressingInterceptorTestCase {
|
||||
public class AddressingInterceptor200605Test extends AbstractAddressingInterceptorTestCase {
|
||||
|
||||
protected WsAddressingVersion getVersion() {
|
||||
return new WsAddressing200605();
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright ${YEAR} 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.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.ws.context.DefaultMessageContext;
|
||||
import org.springframework.ws.context.MessageContext;
|
||||
import org.springframework.ws.server.EndpointInterceptor;
|
||||
import org.springframework.ws.server.EndpointInvocationChain;
|
||||
import org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor;
|
||||
import org.springframework.ws.soap.saaj.SaajSoapMessage;
|
||||
import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
|
||||
import org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor;
|
||||
|
||||
public class WsAddressingActionEndpointMappingTest extends AbstractWsAddressingTestCase {
|
||||
|
||||
private WsAddressingActionEndpointMapping mapping;
|
||||
|
||||
private Endpoint1 endpoint1;
|
||||
|
||||
private Endpoint2 endpoint2;
|
||||
|
||||
protected void onSetUp() throws Exception {
|
||||
mapping = new WsAddressingActionEndpointMapping();
|
||||
Map map = new HashMap();
|
||||
endpoint1 = new Endpoint1();
|
||||
endpoint2 = new Endpoint2();
|
||||
map.put("http://fabrikam123.example/mail/Delete", endpoint1);
|
||||
map.put("http://fabrikam123.example/mail/Add", endpoint2);
|
||||
mapping.setPreInterceptors(new EndpointInterceptor[]{new PayloadLoggingInterceptor()});
|
||||
mapping.setPostInterceptors(new EndpointInterceptor[]{new PayloadValidatingInterceptor()});
|
||||
mapping.setActionMap(map);
|
||||
mapping.setApplicationContext(null);
|
||||
mapping.afterPropertiesSet();
|
||||
}
|
||||
|
||||
public void testMatch() throws Exception {
|
||||
SaajSoapMessage message = loadSaajMessage("200408/valid.xml");
|
||||
MessageContext messageContext = new DefaultMessageContext(message, new SaajSoapMessageFactory(messageFactory));
|
||||
|
||||
EndpointInvocationChain endpoint = mapping.getEndpoint(messageContext);
|
||||
assertNotNull("No endpoint returned", endpoint);
|
||||
assertEquals("Invalid endpoint returned", endpoint1, endpoint.getEndpoint());
|
||||
EndpointInterceptor[] interceptors = endpoint.getInterceptors();
|
||||
assertEquals("Invalid amount of interceptors returned", 3, interceptors.length);
|
||||
assertTrue("Invalid first interceptor", interceptors[0] instanceof PayloadLoggingInterceptor);
|
||||
assertTrue("Invalid first interceptor", interceptors[1] instanceof AddressingEndpointInterceptor);
|
||||
assertTrue("Invalid first interceptor", interceptors[2] instanceof PayloadValidatingInterceptor);
|
||||
}
|
||||
|
||||
public void testNoMatch() throws Exception {
|
||||
SaajSoapMessage message = loadSaajMessage("200408/response-no-message-id.xml");
|
||||
MessageContext messageContext = new DefaultMessageContext(message, new SaajSoapMessageFactory(messageFactory));
|
||||
|
||||
EndpointInvocationChain endpoint = mapping.getEndpoint(messageContext);
|
||||
assertNull("Endpoint returned", endpoint);
|
||||
}
|
||||
|
||||
private static class Endpoint1 {
|
||||
|
||||
}
|
||||
|
||||
private static class Endpoint2 {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
<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>
|
||||
<wsa:Action>urn:replyAction</wsa:Action>
|
||||
</env:Header>
|
||||
<env:Body/>
|
||||
</env:Envelope>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<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>
|
||||
<wsa:Action>urn:faultAction</wsa:Action>
|
||||
</env:Header>
|
||||
<env:Body>
|
||||
<env:Fault>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
<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>
|
||||
<wsa:Action>urn:replyAction</wsa:Action>
|
||||
</env:Header>
|
||||
<env:Body/>
|
||||
</env:Envelope>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
<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>
|
||||
<wsa:Action>urn:faultAction</wsa:Action>
|
||||
</env:Header>
|
||||
<env:Body>
|
||||
<env:Fault>
|
||||
|
||||
Reference in New Issue
Block a user