/*
* Copyright 2002-2017 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 static org.hamcrest.Matchers.instanceOf;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.URI;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.mapping.AbstractHeaderMapper;
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.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.oxm.Unmarshaller;
import org.springframework.oxm.XmlMappingException;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.xml.DomUtils;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.WebServiceMessageFactory;
import org.springframework.ws.client.core.WebServiceTemplate;
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 org.springframework.xml.transform.StringResult;
/**
* @author Oleg Zhurakousky
* @author Gunnar Hillert
* @author Artem Bilan
*/
@RunWith(SpringRunner.class)
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class WebServiceOutboundGatewayWithHeaderMapperTests {
private static String responseSoapMessage = "<?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>";
private static String responseNonSoapMessage = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?> " +
"<person><name>oleg</name></person>";
@Autowired
private ApplicationContext context;
@Test
public void headerMapperParserTest() throws Exception {
SimpleWebServiceOutboundGateway gateway =
TestUtils.getPropertyValue(this.context.getBean("withHeaderMapper"),
"handler", SimpleWebServiceOutboundGateway.class);
DefaultSoapHeaderMapper headerMapper = TestUtils.getPropertyValue(gateway, "headerMapper",
DefaultSoapHeaderMapper.class);
assertNotNull(headerMapper);
AbstractHeaderMapper.HeaderMatcher requestHeaderMatcher = TestUtils.getPropertyValue(headerMapper,
"requestHeaderMatcher", AbstractHeaderMapper.HeaderMatcher.class);
assertTrue(requestHeaderMatcher.matchHeader("foo"));
assertTrue(requestHeaderMatcher.matchHeader("foo123"));
assertTrue(requestHeaderMatcher.matchHeader("baz"));
assertTrue(requestHeaderMatcher.matchHeader("123baz123"));
assertFalse(requestHeaderMatcher.matchHeader("bar"));
assertFalse(requestHeaderMatcher.matchHeader("bar123"));
AbstractHeaderMapper.HeaderMatcher replyHeaderMatcher = TestUtils.getPropertyValue(headerMapper,
"replyHeaderMatcher", AbstractHeaderMapper.HeaderMatcher.class);
assertFalse(replyHeaderMatcher.matchHeader("foo"));
assertFalse(replyHeaderMatcher.matchHeader("foo123"));
assertFalse(replyHeaderMatcher.matchHeader("baz"));
assertFalse(replyHeaderMatcher.matchHeader("123baz123"));
assertTrue(replyHeaderMatcher.matchHeader("bar"));
assertTrue(replyHeaderMatcher.matchHeader("bar123"));
}
@Test
public void withHeaderMapperString() throws Exception {
String payload = "<root><name>bill</name></root>";
Message<?> replyMessage = process(payload, "withHeaderMapper", "inputChannel", true);
assertTrue(replyMessage.getPayload() instanceof String);
assertEquals("bar", replyMessage.getHeaders().get("bar"));
assertNull(replyMessage.getHeaders().get("baz"));
}
@Test
public void withHeaderMapperAndExtractPayloadFalse() throws Exception {
SimpleWebServiceOutboundGateway gateway =
this.context.getBean("withHeaderMapper.handler", SimpleWebServiceOutboundGateway.class);
gateway.setExtractPayload(false);
String payload = "<root><name>bill</name></root>";
Message<?> replyMessage = process(payload, "withHeaderMapper", "inputChannel", true);
assertThat(replyMessage.getPayload(), instanceOf(WebServiceMessage.class));
assertEquals("bar", replyMessage.getHeaders().get("bar"));
assertNull(replyMessage.getHeaders().get("baz"));
}
@Test
public void withHeaderMapperStringPOX() throws Exception {
String payload = "<root><name>bill</name></root>";
Message<?> replyMessage = process(payload, "withHeaderMapper", "inputChannel", false);
assertTrue(replyMessage.getPayload() instanceof String);
assertTrue(((String) replyMessage.getPayload()).contains("<person><name>oleg</name></person>"));
}
@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);
Message<?> replyMessage = process(payload, "withHeaderMapper", "inputChannel", true);
assertTrue(replyMessage.getPayload() instanceof DOMSource);
assertEquals("bar", replyMessage.getHeaders().get("bar"));
assertNull(replyMessage.getHeaders().get("baz"));
}
@Test
public void withHeaderMapperSourcePOX() 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);
Message<?> replyMessage = process(payload, "withHeaderMapper", "inputChannel", false);
assertTrue(replyMessage.getPayload() instanceof DOMSource);
assertTrue(this.extractStringResult(replyMessage).contains("<person><name>oleg</name></person>"));
}
@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()));
Message<?> replyMessage = process(payload, "withHeaderMapper", "inputChannel", true);
assertTrue(replyMessage.getPayload() instanceof Document);
assertEquals("bar", replyMessage.getHeaders().get("bar"));
assertNull(replyMessage.getHeaders().get("baz"));
}
@Test
public void withHeaderMapperDocumentPOX() throws Exception {
DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
Document payload = docBuilder.parse(new ByteArrayInputStream("<root><name>bill</name></root>".getBytes()));
Message<?> replyMessage = process(payload, "withHeaderMapper", "inputChannel", false);
assertTrue(replyMessage.getPayload() instanceof Document);
assertTrue(this.extractStringResult(replyMessage).contains("<person><name>oleg</name></person>"));
}
@Test
public void withHeaderMapperAndMarshaller() throws Exception {
Person person = new Person();
person.setName("Bill Clinton");
Message<?> replyMessage = process(person, "marshallingWithHeaderMapper", "inputMarshallingChannel", true);
assertEquals("bar", replyMessage.getHeaders().get("bar"));
assertNull(replyMessage.getHeaders().get("baz"));
}
private Message<?> process(Object payload, String gatewayName, String channelName, final boolean soap) throws Exception {
AbstractWebServiceOutboundGateway gateway =
TestUtils.getPropertyValue(this.context.getBean(gatewayName), "handler",
AbstractWebServiceOutboundGateway.class);
if (!soap) {
WebServiceTemplate template = TestUtils.getPropertyValue(gateway, "webServiceTemplate", WebServiceTemplate.class);
template.setMessageFactory(new StubMessageFactory());
}
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(invocation -> {
Object[] args = invocation.getArguments();
WebServiceMessage wsMessage = (WebServiceMessage) 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
// }
if (soap) {
SoapHeader soapHeader = ((SoapMessage) wsMessage).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(invocation -> {
Object[] args = invocation.getArguments();
WebServiceMessageFactory factory = (WebServiceMessageFactory) args[0];
String responseMessage = factory instanceof SoapMessageFactory ? responseSoapMessage
: responseNonSoapMessage;
WebServiceMessage wsMessage = factory
.createWebServiceMessage(new ByteArrayInputStream(responseMessage.getBytes()));
if (soap) {
((SoapMessage) wsMessage).getSoapHeader().addAttribute(QNameUtils.parseQNameString("bar"), "bar");
((SoapMessage) wsMessage).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 wsMessage;
}).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);
return outputChannel.receive(0);
}
private String extractStringResult(Message<?> replyMessage) throws Exception {
Transformer transformer = TransformerFactory.newInstance().newTransformer();
StringResult result = new StringResult();
Object payload = replyMessage.getPayload();
if (payload instanceof DOMSource) {
transformer.transform(((DOMSource) replyMessage.getPayload()), result);
}
else if (payload instanceof Document) {
transformer.transform(new DOMSource((Document) replyMessage.getPayload()), result);
}
else {
throw new IllegalArgumentException("Unsupported payload type: " + payload.getClass().getName());
}
return result.toString();
}
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 {
@Override
public boolean supports(Class<?> clazz) {
return true;
}
@Override
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;
}
}
}