HeaderMapper refactoring

INT-2083
added outbound namespace support for XMPP header mapper

INT-2083
added inbound namespace support for XMPP header mapper

INT-2083
polished XMPP inbound/outbound header mappings, added namespace support for AMQP inbound adapter/gateway header mappings

INT-2083
added support and tests for AMQP outbound gateways and adapters

INT-2083
polishing and adding more tests for AMQP support for header mappings

INT-2083
polishing AMQP and XMPP header mappings, generalized headerMapper configuration in IntegrationNamespaceUtils.configureHeaderMapper(..) method

INT-2803
added headermapping support to WS outbound gateways

INT-2803 polishing

INT-2083
refactored SimpleWebServiceOutboundGateway, added full request/reply test

INT-2083
polished MarshallingWebServiceOutboundGateway to add marshalling callback handlers, added test for marshalling call

INT-2083
polishing based on PR comments

INT-2083 interim commit

INT-2083
added RequestReplyHeaderMapper startegy and migrated AMQP Header Mapper to use it

INT-2083
migrated WS and XMPP to use a new RequestReplyHeaderMapper strategy

INT-2083 polishing with PR comments

INT-2083 polishing
removed introspection method, simplified things

INT-2083 polishing based on recent PR comments

INT-2083 interim commit

INT-2083 polishing WS module

INT-2083
refactored to make sure that Soap action header is set within HeaderMapper

INT-2083 polishing
ensured the Soap header is set to default value if not provided

INT-2083 polishing, putting tests back
This commit is contained in:
Mark Fisher
2011-10-06 10:24:13 -04:00
parent ff7bbfa404
commit adf93e5560
50 changed files with 2330 additions and 500 deletions

View File

@@ -21,14 +21,12 @@ import org.springframework.expression.ExpressionException;
import org.springframework.integration.Message;
import org.springframework.integration.MessagingException;
import org.springframework.integration.gateway.MessagingGatewaySupport;
import org.springframework.integration.mapping.HeaderMapper;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.endpoint.MessageEndpoint;
import org.springframework.ws.soap.SoapHeader;
import org.springframework.ws.soap.SoapMessage;
/**
@@ -37,13 +35,13 @@ import org.springframework.ws.soap.SoapMessage;
*/
abstract public class AbstractWebServiceInboundGateway extends MessagingGatewaySupport implements MessageEndpoint {
protected volatile HeaderMapper<SoapHeader> headerMapper = new DefaultSoapHeaderMapper();
protected volatile SoapHeaderMapper headerMapper = new DefaultSoapHeaderMapper();
public String getComponentType() {
return "ws:outbound-gateway";
return "ws:inbound-gateway";
}
public void setHeaderMapper(HeaderMapper<SoapHeader> headerMapper) {
public void setHeaderMapper(SoapHeaderMapper headerMapper) {
Assert.notNull(headerMapper, "headerMapper must not be null");
this.headerMapper = headerMapper;
}
@@ -73,7 +71,7 @@ abstract public class AbstractWebServiceInboundGateway extends MessagingGatewayS
}
if (request instanceof SoapMessage) {
SoapMessage soapMessage = (SoapMessage) request;
Map<String, ?> headers = this.headerMapper.toHeaders(soapMessage.getSoapHeader());
Map<String, ?> headers = this.headerMapper.toHeadersFromRequest(soapMessage);
if (!CollectionUtils.isEmpty(headers)) {
builder.copyHeaders(headers);
}
@@ -82,8 +80,8 @@ abstract public class AbstractWebServiceInboundGateway extends MessagingGatewayS
protected void toSoapHeaders(WebServiceMessage response, Message<?> replyMessage){
if (response instanceof SoapMessage) {
this.headerMapper.fromHeaders(
replyMessage.getHeaders(), ((SoapMessage) response).getSoapHeader());
this.headerMapper.fromHeadersToReply(
replyMessage.getHeaders(), (SoapMessage) response);
}
}

View File

@@ -23,6 +23,8 @@ import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
import javax.xml.transform.TransformerException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.context.expression.MapAccessor;
@@ -33,8 +35,8 @@ import org.springframework.expression.spel.support.StandardTypeConverter;
import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.MessageDeliveryException;
import org.springframework.integration.MessagingException;
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.util.UriTemplate;
@@ -43,12 +45,13 @@ import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.WebServiceMessageFactory;
import org.springframework.ws.client.core.FaultMessageResolver;
import org.springframework.ws.client.core.WebServiceMessageCallback;
import org.springframework.ws.client.core.WebServiceMessageExtractor;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.client.support.destination.DestinationProvider;
import org.springframework.ws.client.support.interceptor.ClientInterceptor;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.ws.soap.client.core.SoapActionCallback;
import org.springframework.ws.transport.WebServiceMessageSender;
import org.springframework.xml.transform.TransformerObjectSupport;
/**
* Base class for outbound Web Service-invoking Messaging Gateways.
@@ -71,7 +74,8 @@ public abstract class AbstractWebServiceOutboundGateway extends AbstractReplyPro
private volatile WebServiceMessageCallback requestCallback;
private volatile boolean ignoreEmptyResponses = true;
protected volatile SoapHeaderMapper headerMapper = new DefaultSoapHeaderMapper();
public AbstractWebServiceOutboundGateway(String uri, WebServiceMessageFactory messageFactory) {
Assert.hasText(uri, "URI must not be empty");
@@ -92,6 +96,9 @@ public abstract class AbstractWebServiceOutboundGateway extends AbstractReplyPro
this.uriTemplate = null;
}
public void setHeaderMapper(SoapHeaderMapper headerMapper) {
this.headerMapper = headerMapper;
}
/**
* Set the Map of URI variable expressions to evaluate against the outbound message
@@ -160,13 +167,13 @@ public abstract class AbstractWebServiceOutboundGateway extends AbstractReplyPro
}
@Override
public final Object handleRequestMessage(Message<?> message) {
URI uri = prepareUri(message);
public final Object handleRequestMessage(Message<?> requestMessage) {
URI uri = prepareUri(requestMessage);
if (uri == null) {
throw new MessageDeliveryException(message, "Failed to determine URI for " +
throw new MessageDeliveryException(requestMessage, "Failed to determine URI for " +
"Web Service request in outbound gateway: " + this.getComponentName());
}
Object responsePayload = this.doHandle(uri.toString(), message.getPayload(), this.getRequestCallback(message));
Object responsePayload = this.doHandle(uri.toString(), requestMessage, this.requestCallback);
if (responsePayload != null) {
boolean shouldIgnore = (this.ignoreEmptyResponses
&& responsePayload instanceof String && !StringUtils.hasText((String) responsePayload));
@@ -177,7 +184,7 @@ public abstract class AbstractWebServiceOutboundGateway extends AbstractReplyPro
return null;
}
protected abstract Object doHandle(String uri, Object requestPayload, WebServiceMessageCallback requestCallback);
protected abstract Object doHandle(String uri, Message<?> requestMessage, WebServiceMessageCallback requestCallback);
private URI prepareUri(Message<?> requestMessage) {
@@ -191,39 +198,51 @@ public abstract class AbstractWebServiceOutboundGateway extends AbstractReplyPro
}
return this.uriTemplate.expand(uriVariables);
}
private WebServiceMessageCallback getRequestCallback(Message<?> requestMessage) {
String soapAction = requestMessage.getHeaders().get(WebServiceHeaders.SOAP_ACTION, String.class);
return (soapAction != null) ?
new TypeCheckingSoapActionCallback(soapAction, this.requestCallback) : this.requestCallback;
}
private static class TypeCheckingSoapActionCallback extends SoapActionCallback {
private final WebServiceMessageCallback callbackDelegate;
TypeCheckingSoapActionCallback(String soapAction, WebServiceMessageCallback callbackDelegate) {
super(soapAction);
this.callbackDelegate = callbackDelegate;
protected abstract class RequestMessageCallback extends TransformerObjectSupport implements WebServiceMessageCallback {
private final WebServiceMessageCallback requestCallback;
private final Message<?> requestMessage;
public RequestMessageCallback(WebServiceMessageCallback requestCallback, Message<?> requestMessage){
this.requestCallback = requestCallback;
this.requestMessage = requestMessage;
}
@Override
public void doWithMessage(WebServiceMessage message) throws IOException {
if (message instanceof SoapMessage) {
super.doWithMessage(message);
public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException {
Object payload = this.requestMessage.getPayload();
if (message instanceof SoapMessage){
this.doWithMessageInternal(message, payload);
headerMapper.fromHeadersToRequest(this.requestMessage.getHeaders(), (SoapMessage)message);
if (requestCallback != null) {
requestCallback.doWithMessage(message);
}
}
if (this.callbackDelegate != null) {
try {
this.callbackDelegate.doWithMessage(message);
}
catch (Exception e) {
throw new MessagingException("error occurred in WebServiceMessageCallback", e);
}
}
}
}
public abstract void doWithMessageInternal(WebServiceMessage message, Object payload) throws IOException, TransformerException;
}
protected abstract class ResponseMessageExtractor extends TransformerObjectSupport implements WebServiceMessageExtractor<Object> {
public Object extractData(WebServiceMessage message)
throws IOException, TransformerException {
Object resultObject = this.doExtractData(message);
if (message instanceof SoapMessage){
Map<String, Object> mappedMessageHeaders = headerMapper.toHeadersFromReply((SoapMessage) message);
Message<?> siMessage = MessageBuilder.withPayload(resultObject).copyHeaders(mappedMessageHeaders).build();
return siMessage;
}
else {
return message.getPayloadSource();
}
}
public abstract Object doExtractData(WebServiceMessage message) throws IOException, TransformerException;
}
/**
* HTTP-specific subclass of UriTemplate, overriding the encode method.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 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.
@@ -16,19 +16,21 @@
package org.springframework.integration.ws;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.xml.namespace.QName;
import org.springframework.integration.MessageHeaders;
import org.springframework.integration.mapping.AbstractHeaderMapper;
import org.springframework.integration.mapping.HeaderMapper;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.PatternMatchUtils;
import org.springframework.util.StringUtils;
import org.springframework.ws.soap.SoapHeader;
import org.springframework.ws.soap.SoapHeaderElement;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.xml.namespace.QNameUtils;
/**
@@ -41,85 +43,77 @@ import org.springframework.xml.namespace.QNameUtils;
* one should implement the HeaderMapper interface directly.
*
* @author Mark Fisher
* @author Oleg Zhurakousky
* @since 2.0
*/
public class DefaultSoapHeaderMapper implements HeaderMapper<SoapHeader> {
public class DefaultSoapHeaderMapper extends AbstractHeaderMapper<SoapMessage> implements SoapHeaderMapper {
private static final List<String> STANDARD_HEADER_NAMES = new ArrayList<String>();
private volatile String[] outboundHeaderNames = new String[0];
private volatile String[] inboundHeaderNames = new String[] { "*" };
public void setOutboundHeaderNames(String[] outboundHeaderNames) {
this.outboundHeaderNames = (outboundHeaderNames != null) ? outboundHeaderNames : new String[0];
static {
STANDARD_HEADER_NAMES.add(WebServiceHeaders.SOAP_ACTION);
}
@Override
protected Map<String, Object> extractStandardHeaders(SoapMessage source) {
return Collections.emptyMap();
}
public void setInboundHeaderNames(String[] inboundHeaderNames) {
this.inboundHeaderNames = (inboundHeaderNames != null) ? inboundHeaderNames : new String[0];
}
public void fromHeaders(MessageHeaders headers, SoapHeader target) {
if (target != null && !CollectionUtils.isEmpty(headers)) {
for (String headerName : headers.keySet()) {
if (this.shouldMapOutboundHeader(headerName)) {
Object value = headers.get(headerName);
if (value instanceof String) {
QName qname = QNameUtils.parseQNameString(headerName);
target.addAttribute(qname, (String) value);
}
}
}
}
}
public Map<String, Object> toHeaders(SoapHeader source) {
@Override
protected Map<String, Object> extractUserDefinedHeaders(SoapMessage source) {
SoapHeader soapHeader = source.getSoapHeader();
Map<String, Object> headers = new HashMap<String, Object>();
if (source != null) {
Iterator<?> attributeIter = source.getAllAttributes();
Iterator<?> attributeIter = soapHeader.getAllAttributes();
while (attributeIter.hasNext()) {
Object name = attributeIter.next();
if (name instanceof QName) {
String qnameString = QNameUtils.toQualifiedName((QName) name);
if (this.shouldMapInboundHeader(qnameString)) {
String value = source.getAttributeValue((QName) name);
if (value != null) {
headers.put(qnameString, value);
}
String value = soapHeader.getAttributeValue((QName) name);
if (value != null) {
headers.put(qnameString, value);
}
}
}
Iterator<?> elementIter = source.examineAllHeaderElements();
Iterator<?> elementIter = soapHeader.examineAllHeaderElements();
while (elementIter.hasNext()) {
Object element = elementIter.next();
if (element instanceof SoapHeaderElement) {
QName qname = ((SoapHeaderElement) element).getName();
String qnameString = QNameUtils.toQualifiedName(qname);
if (this.shouldMapInboundHeader(qnameString)) {
headers.put(qnameString, element);
}
headers.put(qnameString, element);
}
}
}
return headers;
}
private boolean shouldMapInboundHeader(String headerName) {
return matchesAny(this.inboundHeaderNames, headerName);
@Override
protected void populateStandardHeaders(Map<String, Object> headers, SoapMessage target) {
String soapAction = getHeaderIfAvailable(headers, WebServiceHeaders.SOAP_ACTION, String.class);
if (!StringUtils.hasText(soapAction)) {
soapAction = "\"\"";
}
target.setSoapAction(soapAction);
}
private boolean shouldMapOutboundHeader(String headerName) {
return matchesAny(this.outboundHeaderNames, headerName);
}
private static boolean matchesAny(String[] patterns, String candidate) {
if (!ObjectUtils.isEmpty(patterns) && QNameUtils.validateQName(candidate)) {
for (String pattern : patterns) {
if (PatternMatchUtils.simpleMatch(pattern, candidate)) {
return true;
}
}
@Override
protected void populateUserDefinedHeader(String headerName, Object headerValue, SoapMessage target) {
SoapHeader soapHeader = target.getSoapHeader();
if (headerValue instanceof String) {
QName qname = QNameUtils.parseQNameString(headerName);
soapHeader.addAttribute(qname, (String) headerValue);
}
return false;
}
@Override
protected List<String> getStandardRequestHeaderNames() {
return STANDARD_HEADER_NAMES;
}
@Override
protected String getStandardHeaderPrefix() {
return WebServiceHeaders.PREFIX;
}
}

View File

@@ -16,22 +16,31 @@
package org.springframework.integration.ws;
import java.io.IOException;
import org.springframework.integration.Message;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;
import org.springframework.util.Assert;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.WebServiceMessageFactory;
import org.springframework.ws.client.core.WebServiceMessageCallback;
import org.springframework.ws.client.support.destination.DestinationProvider;
import org.springframework.ws.support.MarshallingUtils;
/**
* An outbound Messaging Gateway for invoking Web Services that also supports
* marshalling and unmarshalling of the request and response messages.
*
* @author Mark Fisher
* @author Oleg Zhurakousky
* @see Marshaller
* @see Unmarshaller
*/
public class MarshallingWebServiceOutboundGateway extends AbstractWebServiceOutboundGateway {
private volatile Marshaller marshaller;
private volatile Unmarshaller unmarshaller;
public MarshallingWebServiceOutboundGateway(DestinationProvider destinationProvider, Marshaller marshaller, Unmarshaller unmarshaller, WebServiceMessageFactory messageFactory) {
super(destinationProvider, messageFactory);
@@ -43,8 +52,7 @@ public class MarshallingWebServiceOutboundGateway extends AbstractWebServiceOutb
}
public MarshallingWebServiceOutboundGateway(DestinationProvider destinationProvider, Marshaller marshaller, WebServiceMessageFactory messageFactory) {
super(destinationProvider, messageFactory);
this.configureMarshallers(marshaller);
this(destinationProvider, marshaller, null, messageFactory);
}
public MarshallingWebServiceOutboundGateway(DestinationProvider destinationProvider, Marshaller marshaller) {
@@ -61,8 +69,7 @@ public class MarshallingWebServiceOutboundGateway extends AbstractWebServiceOutb
}
public MarshallingWebServiceOutboundGateway(String uri, Marshaller marshaller, WebServiceMessageFactory messageFactory) {
super(uri, messageFactory);
this.configureMarshallers(marshaller);
this(uri, marshaller, null, messageFactory);
}
public MarshallingWebServiceOutboundGateway(String uri, Marshaller marshaller) {
@@ -76,28 +83,43 @@ public class MarshallingWebServiceOutboundGateway extends AbstractWebServiceOutb
*/
private void configureMarshallers(Marshaller marshaller, Unmarshaller unmarshaller) {
Assert.notNull(marshaller, "marshaller must not be null");
if (unmarshaller == null){
Assert.isInstanceOf(Unmarshaller.class, marshaller,
"Marshaller [" + marshaller + "] does not implement the Unmarshaller interface. " +
"Please set an Unmarshaller explicitly by using one of the constructors that accepts " +
"both Marshaller and Unmarshaller arguments.");
unmarshaller = (Unmarshaller) marshaller;
}
Assert.notNull(unmarshaller, "unmarshaller must not be null");
this.getWebServiceTemplate().setMarshaller(marshaller);
this.getWebServiceTemplate().setUnmarshaller(unmarshaller);
}
/**
* Sets the provided Marshaller on this gateway's WebServiceTemplate as both its
* Marshaller and Unmarshaller. Therefore, it must implement both, and it must not be null.
*/
private void configureMarshallers(Marshaller marshaller) {
Assert.notNull(marshaller, "marshaller must not be null");
Assert.isInstanceOf(Unmarshaller.class, marshaller,
"Marshaller [" + marshaller + "] does not implement the Unmarshaller interface. " +
"Please set an Unmarshaller explicitly by using one of the constructors that accepts " +
"both Marshaller and Unmarshaller arguments.");
this.getWebServiceTemplate().setMarshaller(marshaller);
this.getWebServiceTemplate().setUnmarshaller((Unmarshaller) marshaller);
this.marshaller = marshaller;
this.unmarshaller = unmarshaller;
}
@Override
protected Object doHandle(String uri, Object requestPayload, WebServiceMessageCallback requestCallback) {
return this.getWebServiceTemplate().marshalSendAndReceive(uri, requestPayload, requestCallback);
protected Object doHandle(String uri, Message<?> requestMessage, WebServiceMessageCallback requestCallback) {
Object reply = this.getWebServiceTemplate().sendAndReceive(uri,
new MarshallingRequestMessageCallback(requestCallback, requestMessage), new MarshallingResponseMessageExtractor());
return reply;
}
private class MarshallingRequestMessageCallback extends RequestMessageCallback {
public MarshallingRequestMessageCallback(WebServiceMessageCallback requestCallback, Message<?> requestMessage){
super(requestCallback, requestMessage);
}
@Override
public void doWithMessageInternal(WebServiceMessage message, Object payload) throws IOException{
MarshallingUtils.marshal(marshaller, payload, message);
}
}
private class MarshallingResponseMessageExtractor extends ResponseMessageExtractor {
@Override
public Object doExtractData(WebServiceMessage message) throws IOException{
return MarshallingUtils.unmarshal(unmarshaller, message);
}
}
}

View File

@@ -18,6 +18,7 @@ package org.springframework.integration.ws;
import java.io.IOException;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMResult;
@@ -25,7 +26,10 @@ import javax.xml.transform.dom.DOMSource;
import org.w3c.dom.Document;
import org.springframework.integration.Message;
import org.springframework.integration.MessagingException;
import org.springframework.util.Assert;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.WebServiceMessageFactory;
import org.springframework.ws.client.core.SourceExtractor;
import org.springframework.ws.client.core.WebServiceMessageCallback;
@@ -41,10 +45,9 @@ import org.springframework.xml.transform.TransformerObjectSupport;
* @author Oleg Zhurakousky
*/
public class SimpleWebServiceOutboundGateway extends AbstractWebServiceOutboundGateway {
private final SourceExtractor<?> sourceExtractor;
public SimpleWebServiceOutboundGateway(DestinationProvider destinationProvider) {
this(destinationProvider, null, null);
}
@@ -73,30 +76,92 @@ public class SimpleWebServiceOutboundGateway extends AbstractWebServiceOutboundG
@Override
protected Object doHandle(String uri, Object requestPayload, WebServiceMessageCallback requestCallback) {
if (requestPayload instanceof Source) {
return this.getWebServiceTemplate().sendSourceAndReceive(
uri, (Source) requestPayload, requestCallback, this.sourceExtractor);
}
protected Object doHandle(String uri, final Message<?> requestMessage, final WebServiceMessageCallback requestCallback) {
Object requestPayload = requestMessage.getPayload();
Result responseResultInstance = null;
if (requestPayload instanceof String) {
StringResult result = new StringResult();
this.getWebServiceTemplate().sendSourceAndReceiveToResult(
uri, new StringSource((String) requestPayload), requestCallback, result);
return result.toString();
responseResultInstance = new StringResult();
}
if (requestPayload instanceof Document) {
DOMResult result = new DOMResult();
this.getWebServiceTemplate().sendSourceAndReceiveToResult(
uri, new DOMSource((Document) requestPayload), requestCallback, result);
return result.getNode();
else if (requestPayload instanceof Document) {
responseResultInstance = new DOMResult();
}
throw new MessagingException("Unsupported payload type '" + requestPayload.getClass() +
"'. " + this.getClass().getName() + " only supports 'java.lang.String', '" + Source.class.getName() +
"', and '" + Document.class.getName() + "'. Consider either using the '"
+ MarshallingWebServiceOutboundGateway.class.getName() + "' or a Message Transformer.");
Object reply = this.getWebServiceTemplate().sendAndReceive(uri,
new SimpleRequestMessageCallback(requestCallback, requestMessage), new SimpleResponseMessageExtractor(responseResultInstance));
return reply;
}
private class SimpleRequestMessageCallback extends RequestMessageCallback {
public SimpleRequestMessageCallback(WebServiceMessageCallback requestCallback, Message<?> requestMessage){
super(requestCallback, requestMessage);
}
@Override
public void doWithMessageInternal(WebServiceMessage message, Object payload) throws IOException, TransformerException {
Source source = this.extractSource(payload);
this.transform(source, message.getPayloadResult());
}
private Source extractSource(Object requestPayload) throws IOException, TransformerException{
Source source = null;
if (requestPayload instanceof Source) {
source = (Source) requestPayload;
Object o = sourceExtractor.extractData(source);
Assert.isInstanceOf(Source.class, o);
source = (Source) o;
}
else if (requestPayload instanceof String) {
source = new StringSource((String) requestPayload);
}
else if (requestPayload instanceof Document) {
source = new DOMSource((Document) requestPayload);
}
else {
throw new MessagingException("Unsupported payload type '" + requestPayload.getClass() +
"'. " + this.getClass().getName() + " only supports 'java.lang.String', '" + Source.class.getName() +
"', and '" + Document.class.getName() + "'. Consider either using the '"
+ MarshallingWebServiceOutboundGateway.class.getName() + "' or a Message Transformer.");
}
return source;
}
}
private class SimpleResponseMessageExtractor extends ResponseMessageExtractor {
private final Result result;
public SimpleResponseMessageExtractor(Result result){
super();
this.result = result;
}
@Override
public Object doExtractData(WebServiceMessage message) throws IOException, TransformerException{
Source payloadSource = message.getPayloadSource();
Object payload = null;
if (this.result != null){
this.transform(payloadSource, this.result);
if (this.result instanceof StringResult){
payload = this.result.toString();
}
else if (this.result instanceof DOMResult){
payload = ((DOMResult)this.result).getNode();
}
else {
payload = this.result;
}
}
else {
payload = payloadSource;
}
return payload;
}
}
private static class DefaultSourceExtractor extends TransformerObjectSupport implements SourceExtractor<DOMSource> {
public DOMSource extractData(Source source) throws IOException, TransformerException {
@@ -108,5 +173,4 @@ public class SimpleWebServiceOutboundGateway extends AbstractWebServiceOutboundG
return new DOMSource(result.getNode());
}
}
}

View File

@@ -0,0 +1,20 @@
/**
*
*/
package org.springframework.integration.ws;
import org.springframework.integration.mapping.HeaderMapper;
import org.springframework.integration.mapping.RequestReplyHeaderMapper;
import org.springframework.ws.soap.SoapHeader;
import org.springframework.ws.soap.SoapMessage;
/**
* A convenience interface that extends {@link HeaderMapper}
* but parameterized with {@link SoapHeader}.
*
* @author Oleg Zhurakousky
* @since 2.1
*/
public interface SoapHeaderMapper extends RequestReplyHeaderMapper<SoapMessage>{
}

View File

@@ -16,14 +16,15 @@
package org.springframework.integration.ws.config;
import org.w3c.dom.Element;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.AbstractInboundGatewayParser;
import org.springframework.util.Assert;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.integration.ws.DefaultSoapHeaderMapper;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* @author Iwein Fuld
@@ -66,12 +67,10 @@ public class WebServiceInboundGatewayParser extends AbstractInboundGatewayParser
logger.warn("Setting 'extract-payload' attribute has no effect when used with a marshalling Web Service Inbound Gateway.");
}
}
String headerMapperRef = element.getAttribute("header-mapper");
if (StringUtils.hasText(headerMapperRef)) {
Assert.isTrue(!StringUtils.hasText(marshallerRef),
"The 'header-mapper' attribute cannot be used when a 'marshaller' is provided.");
builder.addPropertyReference("headerMapper", headerMapperRef);
}
}
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
super.doParse(element, parserContext, builder);
IntegrationNamespaceUtils.configureHeaderMapper(element, builder, parserContext, DefaultSoapHeaderMapper.class, null);
}
}

View File

@@ -28,6 +28,7 @@ import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.ExpressionFactoryBean;
import org.springframework.integration.config.xml.AbstractOutboundGatewayParser;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.integration.ws.DefaultSoapHeaderMapper;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
@@ -84,6 +85,9 @@ public class WebServiceOutboundGatewayParser extends AbstractOutboundGatewayPars
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "reply-channel");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "ignore-empty-responses");
this.postProcessGateway(builder, element, parserContext);
IntegrationNamespaceUtils.configureHeaderMapper(element, builder, parserContext, DefaultSoapHeaderMapper.class, null);
return builder;
}

View File

@@ -204,6 +204,38 @@
</xsd:attribute>
<xsd:attribute name="order" type="xsd:string"/>
<xsd:attribute name="auto-startup" type="xsd:string" default="true"/>
<xsd:attribute name="header-mapper">
<xsd:annotation>
<xsd:documentation>
Reference to a HeaderMapper&lt;SoapHeader&gt; implementation
that this gateway will use to map between Spring Integration
MessageHeaders and the SoapHeader.
</xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.mapping.HeaderMapper"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="mapped-request-headers" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Comma-separated list of names of SOAP Headers to be mapped from the SOAP request into the MessageHeaders.
This can only be provided if the 'header-mapper' reference is not being set directly. The values in
this list can also be simple patterns to be matched against the header names (e.g. "foo*" or "*foo").
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="mapped-reply-headers" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Comma-separated list of names of MessageHeaders to be mapped into the SOAP Headers of the SOAP reply.
This can only be provided if the 'header-mapper' reference is not being set directly. The values in
this list can also be simple patterns to be matched against the header names (e.g. "foo*" or "*foo").
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
@@ -295,8 +327,7 @@
<xsd:documentation>
Reference to a HeaderMapper&lt;SoapHeader&gt; implementation
that this gateway will use to map between Spring Integration
MessageHeaders and the SoapHeader. This strategy can only be
applied when a 'marshaller' is not being configured.
MessageHeaders and the SoapHeader.
</xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
@@ -305,6 +336,24 @@
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="mapped-request-headers" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Comma-separated list of names of SOAP Headers to be mapped from the SOAP request into the MessageHeaders.
This can only be provided if the 'header-mapper' reference is not being set directly. The values in
this list can also be simple patterns to be matched against the header names (e.g. "foo*" or "*foo").
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="mapped-reply-headers" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Comma-separated list of names of MessageHeaders to be mapped into the SOAP Headers of the SOAP reply.
This can only be provided if the 'header-mapper' reference is not being set directly. The values in
this list can also be simple patterns to be matched against the header names (e.g. "foo*" or "*foo").
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2011 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.
@@ -25,6 +25,7 @@ import javax.xml.transform.Source;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
@@ -33,17 +34,17 @@ import org.springframework.integration.MessageChannel;
import org.springframework.integration.MessageHeaders;
import org.springframework.integration.core.PollableChannel;
import org.springframework.integration.history.MessageHistory;
import org.springframework.integration.mapping.HeaderMapper;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.integration.ws.MarshallingWebServiceInboundGateway;
import org.springframework.integration.ws.SimpleWebServiceInboundGateway;
import org.springframework.integration.ws.SoapHeaderMapper;
import org.springframework.oxm.Unmarshaller;
import org.springframework.oxm.support.AbstractMarshaller;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.ws.context.DefaultMessageContext;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.soap.SoapHeader;
import org.springframework.ws.soap.SoapMessage;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
@@ -149,7 +150,7 @@ public class WebServiceInboundGatewayParserTests {
assertNotNull(history);
Properties componentHistoryRecord = TestUtils.locateComponentInHistory(history, "marshalling", 0);
assertNotNull(componentHistoryRecord);
assertEquals("ws:outbound-gateway", componentHistoryRecord.get("type"));
assertEquals("ws:inbound-gateway", componentHistoryRecord.get("type"));
}
@Test
@@ -162,14 +163,14 @@ public class WebServiceInboundGatewayParserTests {
Properties componentHistoryRecord = TestUtils.locateComponentInHistory(history, "extractsPayload", 0);
System.out.println(componentHistoryRecord);
assertNotNull(componentHistoryRecord);
assertEquals("ws:outbound-gateway", componentHistoryRecord.get("type"));
assertEquals("ws:inbound-gateway", componentHistoryRecord.get("type"));
}
@Autowired
private SimpleWebServiceInboundGateway headerMappingGateway;
@Autowired
private HeaderMapper<SoapHeader> testHeaderMapper;
private SoapHeaderMapper testHeaderMapper;
@Test
public void testHeaderMapperReference() throws Exception {
@@ -180,12 +181,20 @@ public class WebServiceInboundGatewayParserTests {
@SuppressWarnings("unused")
private static class TestHeaderMapper implements HeaderMapper<SoapHeader> {
public void fromHeaders(MessageHeaders headers, SoapHeader target) {
private static class TestHeaderMapper implements SoapHeaderMapper {
public void fromHeadersToRequest(MessageHeaders headers,
SoapMessage target) {
}
public Map<String, ?> toHeaders(SoapHeader source) {
public void fromHeadersToReply(MessageHeaders headers, SoapMessage target) {
}
public Map<String, Object> toHeadersFromRequest(SoapMessage source) {
return Collections.emptyMap();
}
public Map<String, Object> toHeadersFromReply(SoapMessage source) {
return Collections.emptyMap();
}
}

View File

@@ -16,9 +16,6 @@
package org.springframework.integration.ws.config;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import org.junit.Test;
import org.springframework.beans.DirectFieldAccessor;
@@ -28,6 +25,7 @@ import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.endpoint.AbstractEndpoint;
import org.springframework.integration.endpoint.EventDrivenConsumer;
import org.springframework.integration.endpoint.PollingConsumer;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.integration.ws.MarshallingWebServiceOutboundGateway;
import org.springframework.integration.ws.SimpleWebServiceOutboundGateway;
import org.springframework.oxm.Marshaller;
@@ -40,6 +38,9 @@ import org.springframework.ws.client.core.WebServiceMessageCallback;
import org.springframework.ws.client.support.interceptor.ClientInterceptor;
import org.springframework.ws.transport.WebServiceMessageSender;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
/**
* @author Mark Fisher
*/
@@ -261,14 +262,10 @@ public class WebServiceOutboundGatewayParserTests {
"marshallingWebServiceOutboundGatewayParserTests.xml", this.getClass());
AbstractEndpoint endpoint = (AbstractEndpoint) context.getBean("gatewayWithAllInOneMarshaller");
assertEquals(EventDrivenConsumer.class, endpoint.getClass());
Object gateway = new DirectFieldAccessor(endpoint).getPropertyValue("handler");
assertEquals(MarshallingWebServiceOutboundGateway.class, gateway.getClass());
DirectFieldAccessor gatewayAccessor = new DirectFieldAccessor(gateway);
DirectFieldAccessor templateAccessor = new DirectFieldAccessor(
gatewayAccessor.getPropertyValue("webServiceTemplate"));
MarshallingWebServiceOutboundGateway gateway = (MarshallingWebServiceOutboundGateway) new DirectFieldAccessor(endpoint).getPropertyValue("handler");
Marshaller marshaller = (Marshaller) context.getBean("marshallerAndUnmarshaller");
assertEquals(marshaller, templateAccessor.getPropertyValue("marshaller"));
assertEquals(marshaller, templateAccessor.getPropertyValue("unmarshaller"));
assertEquals(marshaller, TestUtils.getPropertyValue(gateway, "marshaller", Marshaller.class));
assertEquals(marshaller, TestUtils.getPropertyValue(gateway, "unmarshaller", Unmarshaller.class));
}
@Test
@@ -277,15 +274,11 @@ public class WebServiceOutboundGatewayParserTests {
"marshallingWebServiceOutboundGatewayParserTests.xml", this.getClass());
AbstractEndpoint endpoint = (AbstractEndpoint) context.getBean("gatewayWithSeparateMarshallerAndUnmarshaller");
assertEquals(EventDrivenConsumer.class, endpoint.getClass());
Object gateway = new DirectFieldAccessor(endpoint).getPropertyValue("handler");
assertEquals(MarshallingWebServiceOutboundGateway.class, gateway.getClass());
DirectFieldAccessor gatewayAccessor = new DirectFieldAccessor(gateway);
DirectFieldAccessor templateAccessor = new DirectFieldAccessor(
gatewayAccessor.getPropertyValue("webServiceTemplate"));
MarshallingWebServiceOutboundGateway gateway = (MarshallingWebServiceOutboundGateway) new DirectFieldAccessor(endpoint).getPropertyValue("handler");
Marshaller marshaller = (Marshaller) context.getBean("marshaller");
Unmarshaller unmarshaller = (Unmarshaller) context.getBean("unmarshaller");
assertEquals(marshaller, templateAccessor.getPropertyValue("marshaller"));
assertEquals(unmarshaller, templateAccessor.getPropertyValue("unmarshaller"));
assertEquals(marshaller, TestUtils.getPropertyValue(gateway, "marshaller", Marshaller.class));
assertEquals(unmarshaller, TestUtils.getPropertyValue(gateway, "unmarshaller", Unmarshaller.class));
}
@Test
@@ -307,16 +300,13 @@ public class WebServiceOutboundGatewayParserTests {
"marshallingWebServiceOutboundGatewayParserTests.xml", this.getClass());
AbstractEndpoint endpoint = (AbstractEndpoint) context.getBean("gatewayWithAllInOneMarshallerAndMessageFactory");
assertEquals(EventDrivenConsumer.class, endpoint.getClass());
Object gateway = new DirectFieldAccessor(endpoint).getPropertyValue("handler");
assertEquals(MarshallingWebServiceOutboundGateway.class, gateway.getClass());
DirectFieldAccessor gatewayAccessor = new DirectFieldAccessor(gateway);
DirectFieldAccessor templateAccessor = new DirectFieldAccessor(
gatewayAccessor.getPropertyValue("webServiceTemplate"));
MarshallingWebServiceOutboundGateway gateway = (MarshallingWebServiceOutboundGateway) new DirectFieldAccessor(endpoint).getPropertyValue("handler");
Marshaller marshaller = (Marshaller) context.getBean("marshallerAndUnmarshaller");
assertEquals(marshaller, templateAccessor.getPropertyValue("marshaller"));
assertEquals(marshaller, templateAccessor.getPropertyValue("unmarshaller"));
assertEquals(marshaller, TestUtils.getPropertyValue(gateway, "marshaller", Marshaller.class));
assertEquals(marshaller, TestUtils.getPropertyValue(gateway, "unmarshaller", Unmarshaller.class));
WebServiceMessageFactory messageFactory = (WebServiceMessageFactory) context.getBean("messageFactory");
assertEquals(messageFactory, templateAccessor.getPropertyValue("messageFactory"));
assertEquals(messageFactory, TestUtils.getPropertyValue(gateway, "webServiceTemplate.messageFactory"));
}
@Test
@@ -325,17 +315,14 @@ public class WebServiceOutboundGatewayParserTests {
"marshallingWebServiceOutboundGatewayParserTests.xml", this.getClass());
AbstractEndpoint endpoint = (AbstractEndpoint) context.getBean("gatewayWithSeparateMarshallerAndUnmarshallerAndMessageFactory");
assertEquals(EventDrivenConsumer.class, endpoint.getClass());
Object gateway = new DirectFieldAccessor(endpoint).getPropertyValue("handler");
assertEquals(MarshallingWebServiceOutboundGateway.class, gateway.getClass());
DirectFieldAccessor gatewayAccessor = new DirectFieldAccessor(gateway);
DirectFieldAccessor templateAccessor = new DirectFieldAccessor(
gatewayAccessor.getPropertyValue("webServiceTemplate"));
MarshallingWebServiceOutboundGateway gateway = (MarshallingWebServiceOutboundGateway) new DirectFieldAccessor(endpoint).getPropertyValue("handler");
Marshaller marshaller = (Marshaller) context.getBean("marshaller");
Unmarshaller unmarshaller = (Unmarshaller) context.getBean("unmarshaller");
assertEquals(marshaller, templateAccessor.getPropertyValue("marshaller"));
assertEquals(unmarshaller, templateAccessor.getPropertyValue("unmarshaller"));
assertEquals(marshaller, TestUtils.getPropertyValue(gateway, "marshaller", Marshaller.class));
assertEquals(unmarshaller, TestUtils.getPropertyValue(gateway, "unmarshaller", Unmarshaller.class));
WebServiceMessageFactory messageFactory = (WebServiceMessageFactory) context.getBean("messageFactory");
assertEquals(messageFactory, templateAccessor.getPropertyValue("messageFactory"));
assertEquals(messageFactory, TestUtils.getPropertyValue(gateway, "webServiceTemplate.messageFactory"));
}
@Test

View File

@@ -0,0 +1,215 @@
/*
* Copyright 2002-2011 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.integration.ws.config;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.URI;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMSource;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.integration.ws.AbstractWebServiceOutboundGateway;
import org.springframework.integration.ws.DefaultSoapHeaderMapper;
import org.springframework.integration.ws.SimpleWebServiceOutboundGateway;
import org.springframework.integration.ws.WebServiceHeaders;
import org.springframework.oxm.Unmarshaller;
import org.springframework.oxm.XmlMappingException;
import org.springframework.util.xml.DomUtils;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.WebServiceMessageFactory;
import org.springframework.ws.soap.SoapHeader;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.ws.soap.SoapMessageFactory;
import org.springframework.ws.transport.WebServiceConnection;
import org.springframework.ws.transport.WebServiceMessageSender;
import org.springframework.xml.namespace.QNameUtils;
import static junit.framework.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
/**
* @author Oleg Zhurakousky
*
*/
public class WebServiceOutboundGatewayWithHeaderMapperTests {
String responseMessage = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?> " +
"<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"> " +
"<SOAP-ENV:Header/>" +
"<SOAP-ENV:Body> " +
"<root><name>jane</name></root>" +
"</SOAP-ENV:Body> " +
"</SOAP-ENV:Envelope>";
@SuppressWarnings("unchecked")
@Test
public void headerMapperParserTest() throws Exception{
ApplicationContext context = new ClassPathXmlApplicationContext("ws-outbound-gateway-with-headermappers.xml", this.getClass());
SimpleWebServiceOutboundGateway gateway = TestUtils.getPropertyValue(context.getBean("withHeaderMapper"), "handler", SimpleWebServiceOutboundGateway.class);
DefaultSoapHeaderMapper headerMapper = TestUtils.getPropertyValue(gateway, "headerMapper", DefaultSoapHeaderMapper.class);
assertNotNull(headerMapper);
List<String> requestHeaderNames = TestUtils.getPropertyValue(headerMapper, "requestHeaderNames", List.class);
assertEquals(2, requestHeaderNames.size());
assertEquals("foo*", requestHeaderNames.get(0));
assertEquals("*baz*", requestHeaderNames.get(1));
List<String> responseHeaderNames = TestUtils.getPropertyValue(headerMapper, "replyHeaderNames", List.class);
assertEquals(1, responseHeaderNames.size());
assertEquals("bar*", responseHeaderNames.get(0));
}
@Test
public void withHeaderMapperString() throws Exception{
String payload = "<root><name>bill</name></root>";
this.process(payload, "withHeaderMapper", "inputChannel");
}
@Test
public void withHeaderMapperSource() throws Exception{
DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
Document document = docBuilder.parse(new ByteArrayInputStream("<root><name>bill</name></root>".getBytes()));
DOMSource payload = new DOMSource(document);
this.process(payload, "withHeaderMapper", "inputChannel");
}
@Test
public void withHeaderMapperDocument() throws Exception{
DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
Document payload = docBuilder.parse(new ByteArrayInputStream("<root><name>bill</name></root>".getBytes()));
this.process(payload, "withHeaderMapper", "inputChannel");
}
@Test
public void withHeaderMapperAndMarshaller() throws Exception{
Person person = new Person();
person.setName("Bill Clinton");
this.process(person, "marshallingWithHeaderMapper", "inputMarshallingChannel");
}
@SuppressWarnings("rawtypes")
public void process(Object payload, String gatewayName, String channelName) throws Exception{
ApplicationContext context = new ClassPathXmlApplicationContext("ws-outbound-gateway-with-headermappers.xml", this.getClass());
AbstractWebServiceOutboundGateway gateway = TestUtils.getPropertyValue(context.getBean(gatewayName), "handler", AbstractWebServiceOutboundGateway.class);
WebServiceMessageSender messageSender = Mockito.mock(WebServiceMessageSender.class);
WebServiceConnection wsConnection = Mockito.mock(WebServiceConnection.class);
Mockito.when(messageSender.createConnection(Mockito.any(URI.class))).thenReturn(wsConnection);
Mockito.when(messageSender.supports(Mockito.any(URI.class))).thenReturn(true);
Mockito.doAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
SoapMessage soapMessage = (SoapMessage) args[0];
// try { // uncomment if you want to see a pretty-print of SOAP message
// Transformer transformer = TransformerFactory.newInstance().newTransformer();
// transformer.setOutputProperty(OutputKeys.INDENT, "yes");
// transformer.transform(new DOMSource(soapMessage.getDocument()), new StreamResult(System.out));
// } catch (Exception e) {
// // ignore
// }
SoapHeader soapHeader = soapMessage.getSoapHeader();
assertNotNull(soapHeader.getAttributeValue(QNameUtils.parseQNameString("foo")));
assertNotNull(soapHeader.getAttributeValue(QNameUtils.parseQNameString("foobar")));
assertNotNull(soapHeader.getAttributeValue(QNameUtils.parseQNameString("abaz")));
assertNull(soapHeader.getAttributeValue(QNameUtils.parseQNameString("bar")));
return null;
}})
.when(wsConnection).send(Mockito.any(WebServiceMessage.class));
Mockito.doAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) throws Exception{
Object[] args = invocation.getArguments();
SoapMessageFactory factory = (SoapMessageFactory) args[0];
SoapMessage soapMessage = factory.createWebServiceMessage(new ByteArrayInputStream(responseMessage.getBytes()));
soapMessage.getSoapHeader().addAttribute(QNameUtils.parseQNameString("bar"), "bar");
soapMessage.getSoapHeader().addAttribute(QNameUtils.parseQNameString("baz"), "baz");
// try { // uncomment if you want to see a pretty-print of SOAP message
// Transformer transformer = TransformerFactory.newInstance().newTransformer();
// transformer.setOutputProperty(OutputKeys.INDENT, "yes");
// transformer.transform(new DOMSource(soapMessage.getDocument()), new StreamResult(System.out));
// } catch (Exception e) {
// // ignore
// }
return soapMessage;
}})
.when(wsConnection).receive(Mockito.any(WebServiceMessageFactory.class));
gateway.setMessageSender(messageSender);
MessageChannel inputChannel = context.getBean(channelName, MessageChannel.class);
Message<?> message =
MessageBuilder.withPayload(payload).
setHeader("foo", "foo").setHeader("foobar", "foobar").setHeader("abaz", "abaz").setHeader("bar", "bar").
setHeader(WebServiceHeaders.SOAP_ACTION, "someAction").build();
inputChannel.send(message);
QueueChannel outputChannel = context.getBean("outputChannel", QueueChannel.class);
Message<?> replyMessage = outputChannel.receive(0);
assertEquals("bar", replyMessage.getHeaders().get("bar"));
assertNull(replyMessage.getHeaders().get("baz"));
}
public static class Person{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public static class SampleUnmarshaller implements Unmarshaller {
public boolean supports(Class<?> clazz) {
return true;
}
public Object unmarshal(Source source) throws IOException, XmlMappingException {
Element documentElement = (Element) ((DOMSource) source).getNode();
String name = DomUtils.getChildElementValueByTagName(documentElement, "name");
Person person = new Person();
person.setName(name);
return person;
}
}
}

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int-ws="http://www.springframework.org/schema/integration/ws"
xmlns:int="http://www.springframework.org/schema/integration"
xsi:schemaLocation="http://www.springframework.org/schema/integration/ws http://www.springframework.org/schema/integration/ws/spring-integration-ws-2.1.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<int:channel id="inputChannel"/>
<int:channel id="inputMarshallingChannel"/>
<int-ws:outbound-gateway id="withHeaderMapper"
request-channel="inputChannel"
reply-channel="outputChannel"
uri="http://example.org"
mapped-request-headers="foo*, *baz*"
mapped-reply-headers="bar*"/>
<int-ws:outbound-gateway id="marshallingWithHeaderMapper"
request-channel="inputMarshallingChannel"
reply-channel="outputChannel"
uri="http://example.org"
marshaller="marshaller"
unmarshaller="ubmarshaller"
mapped-request-headers="foo*, *baz*"
mapped-reply-headers="bar*"/>
<bean id="marshaller" class="org.springframework.oxm.xstream.XStreamMarshaller"/>
<bean id="ubmarshaller" class="org.springframework.integration.ws.config.WebServiceOutboundGatewayWithHeaderMapperTests.SampleUnmarshaller"/>
<int:channel id="outputChannel">
<int:queue/>
</int:channel>
</beans>