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

@@ -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>