INT-2720: UriTemplate Support for S-WS Transports
Remove deprecation in the WS module JIRA: https://jira.springsource.org/browse/INT-2720 https://jira.springsource.org/browse/INT-2530 INT-2720: Polishing after rebase INT-2720: Add a note to the Reference Manual Polishing <authorgroup> to avoid extra whitespace before name INT-2720: Pr comments & polishing * Revert removed public API * Revert tabs in What's new * Change real URL to fake to allow for tests to work off-line * Add smackx dependency to avoid error messages in logs
This commit is contained in:
committed by
Gary Russell
parent
7d99a9a07a
commit
6b7ae6ceed
10
build.gradle
10
build.gradle
@@ -535,6 +535,16 @@ project('spring-integration-ws') {
|
||||
testCompile project(":spring-integration-test")
|
||||
testCompile "stax:stax-api:1.0.1"
|
||||
testCompile "xstream:xstream:1.2.2"
|
||||
testCompile ("org.springframework.ws:spring-ws-support:$springWsVersion") {
|
||||
exclude group: 'org.springframework'
|
||||
}
|
||||
testCompile ("org.springframework:spring-jms:$springVersion") {
|
||||
exclude group: 'org.springframework'
|
||||
}
|
||||
testCompile "org.apache.geronimo.specs:geronimo-jms_1.1_spec:1.1"
|
||||
testCompile "org.igniterealtime.smack:smack:3.2.1"
|
||||
testCompile "org.igniterealtime.smack:smackx:3.2.1"
|
||||
testCompile "javax.mail:mail:1.4.5"
|
||||
}
|
||||
|
||||
// suppress saaj path warnings
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
@@ -17,31 +17,24 @@
|
||||
package org.springframework.integration.ws;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
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;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
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.expression.ExpressionUtils;
|
||||
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.util.UriTemplate;
|
||||
import org.springframework.web.util.UriUtils;
|
||||
import org.springframework.ws.WebServiceMessage;
|
||||
import org.springframework.ws.WebServiceMessageFactory;
|
||||
import org.springframework.ws.client.core.FaultMessageResolver;
|
||||
@@ -61,6 +54,7 @@ import org.springframework.xml.transform.TransformerObjectSupport;
|
||||
* @author Jonas Partner
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Gary Russell
|
||||
* @author Artem Bilan
|
||||
*/
|
||||
public abstract class AbstractWebServiceOutboundGateway extends AbstractReplyProducingMessageHandler {
|
||||
|
||||
@@ -72,7 +66,7 @@ public abstract class AbstractWebServiceOutboundGateway extends AbstractReplyPro
|
||||
|
||||
private final Map<String, Expression> uriVariableExpressions = new HashMap<String, Expression>();
|
||||
|
||||
private final StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
|
||||
private volatile StandardEvaluationContext evaluationContext;
|
||||
|
||||
private volatile WebServiceMessageCallback requestCallback;
|
||||
|
||||
@@ -82,30 +76,14 @@ public abstract class AbstractWebServiceOutboundGateway extends AbstractReplyPro
|
||||
|
||||
public AbstractWebServiceOutboundGateway(final String uri, WebServiceMessageFactory messageFactory) {
|
||||
Assert.hasText(uri, "URI must not be empty");
|
||||
this.webServiceTemplate = (messageFactory != null) ?
|
||||
new WebServiceTemplate(messageFactory) : new WebServiceTemplate();
|
||||
if (uri.toLowerCase().startsWith("http")) {
|
||||
this.uriTemplate = new HttpUrlTemplate(uri);
|
||||
this.destinationProvider = null;
|
||||
}
|
||||
else {
|
||||
this.uriTemplate = null;
|
||||
this.destinationProvider = new DestinationProvider() {
|
||||
private volatile URI cachedUri;
|
||||
public URI getDestination() {
|
||||
if (this.cachedUri == null) {
|
||||
this.cachedUri = URI.create(uri);
|
||||
}
|
||||
return this.cachedUri;
|
||||
}
|
||||
};
|
||||
}
|
||||
this.webServiceTemplate = new WebServiceTemplate(messageFactory);
|
||||
this.destinationProvider = null;
|
||||
this.uriTemplate = new UriTemplate(uri);
|
||||
}
|
||||
|
||||
public AbstractWebServiceOutboundGateway(DestinationProvider destinationProvider, WebServiceMessageFactory messageFactory) {
|
||||
Assert.notNull(destinationProvider, "DestinationProvider must not be null");
|
||||
this.webServiceTemplate = (messageFactory != null) ?
|
||||
new WebServiceTemplate(messageFactory) : new WebServiceTemplate();
|
||||
this.webServiceTemplate = new WebServiceTemplate(messageFactory);
|
||||
this.destinationProvider = destinationProvider;
|
||||
// we always call WebServiceTemplate methods with an explicit URI argument,
|
||||
// but in case the WebServiceTemplate is accessed directly we'll set this:
|
||||
@@ -157,29 +135,25 @@ public abstract class AbstractWebServiceOutboundGateway extends AbstractReplyPro
|
||||
this.webServiceTemplate.setMessageSender(messageSender);
|
||||
}
|
||||
|
||||
public void setMessageSenders(WebServiceMessageSender[] messageSenders) {
|
||||
public void setMessageSenders(WebServiceMessageSender... messageSenders) {
|
||||
this.webServiceTemplate.setMessageSenders(messageSenders);
|
||||
}
|
||||
|
||||
public void setInterceptors(ClientInterceptor[] interceptors) {
|
||||
public void setInterceptors(ClientInterceptor... interceptors) {
|
||||
this.webServiceTemplate.setInterceptors(interceptors);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInit() {
|
||||
super.onInit();
|
||||
BeanFactory beanFactory = this.getBeanFactory();
|
||||
if (beanFactory != null) {
|
||||
this.evaluationContext.setBeanResolver(new BeanFactoryResolver(beanFactory));
|
||||
if (this.getBeanFactory() != null) {
|
||||
this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(this.getBeanFactory());
|
||||
}
|
||||
ConversionService conversionService = this.getConversionService();
|
||||
if (conversionService != null) {
|
||||
this.evaluationContext.setTypeConverter(new StandardTypeConverter(conversionService));
|
||||
else {
|
||||
this.evaluationContext = ExpressionUtils.createStandardEvaluationContext();
|
||||
}
|
||||
this.evaluationContext.addPropertyAccessor(new MapAccessor());
|
||||
Assert.state(this.destinationProvider != null ? CollectionUtils.isEmpty(this.uriVariableExpressions) : true,
|
||||
"uri variables are not supported when a DestinationProvider is supplied, or the uri " +
|
||||
"scheme is not http: or https:");
|
||||
Assert.state(this.destinationProvider == null || CollectionUtils.isEmpty(this.uriVariableExpressions),
|
||||
"uri variables are not supported when a DestinationProvider is supplied.");
|
||||
}
|
||||
|
||||
protected WebServiceTemplate getWebServiceTemplate() {
|
||||
@@ -188,7 +162,7 @@ public abstract class AbstractWebServiceOutboundGateway extends AbstractReplyPro
|
||||
|
||||
@Override
|
||||
public final Object handleRequestMessage(Message<?> requestMessage) {
|
||||
URI uri = prepareUri(requestMessage);
|
||||
URI uri = this.prepareUri(requestMessage);
|
||||
if (uri == null) {
|
||||
throw new MessageDeliveryException(requestMessage, "Failed to determine URI for " +
|
||||
"Web Service request in outbound gateway: " + this.getComponentName());
|
||||
@@ -222,6 +196,7 @@ public abstract class AbstractWebServiceOutboundGateway extends AbstractReplyPro
|
||||
protected abstract class RequestMessageCallback extends TransformerObjectSupport implements WebServiceMessageCallback {
|
||||
|
||||
private final WebServiceMessageCallback requestCallback;
|
||||
|
||||
private final Message<?> requestMessage;
|
||||
|
||||
public RequestMessageCallback(WebServiceMessageCallback requestCallback, Message<?> requestMessage){
|
||||
@@ -233,15 +208,17 @@ public abstract class AbstractWebServiceOutboundGateway extends AbstractReplyPro
|
||||
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);
|
||||
}
|
||||
AbstractWebServiceOutboundGateway.this.headerMapper.fromHeadersToRequest(this.requestMessage.getHeaders(),
|
||||
(SoapMessage) message);
|
||||
if (this.requestCallback != null) {
|
||||
this.requestCallback.doWithMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public abstract void doWithMessageInternal(WebServiceMessage message, Object payload) throws IOException, TransformerException;
|
||||
|
||||
}
|
||||
|
||||
protected abstract class ResponseMessageExtractor extends TransformerObjectSupport implements WebServiceMessageExtractor<Object> {
|
||||
@@ -251,10 +228,10 @@ public abstract class AbstractWebServiceOutboundGateway extends AbstractReplyPro
|
||||
|
||||
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;
|
||||
if (message instanceof SoapMessage){
|
||||
Map<String, Object> mappedMessageHeaders =
|
||||
AbstractWebServiceOutboundGateway.this.headerMapper.toHeadersFromReply((SoapMessage) message);
|
||||
return MessageBuilder.withPayload(resultObject).copyHeaders(mappedMessageHeaders).build();
|
||||
}
|
||||
else {
|
||||
return resultObject;
|
||||
@@ -262,34 +239,7 @@ public abstract class AbstractWebServiceOutboundGateway extends AbstractReplyPro
|
||||
}
|
||||
|
||||
public abstract Object doExtractData(WebServiceMessage message) throws IOException, TransformerException;
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP-specific subclass of UriTemplate, overriding the encode method.
|
||||
* This was copied from RestTemplate in version 3.0.6 (since it's private)
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
private static class HttpUrlTemplate extends UriTemplate {
|
||||
|
||||
public HttpUrlTemplate(String uriTemplate) {
|
||||
super(uriTemplate);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
protected URI encodeUri(String uri) {
|
||||
try {
|
||||
String encoded = UriUtils.encodeHttpUrl(uri, "UTF-8");
|
||||
return new URI(encoded);
|
||||
}
|
||||
catch (UnsupportedEncodingException ex) {
|
||||
// should not happen, UTF-8 is always supported
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
catch (URISyntaxException ex) {
|
||||
throw new IllegalArgumentException("Could not create HTTP URL from [" + uri + "]: " + ex, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
@@ -20,9 +20,7 @@ import java.util.List;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.support.ManagedMap;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.config.ExpressionFactoryBean;
|
||||
@@ -32,6 +30,8 @@ import org.springframework.integration.ws.DefaultSoapHeaderMapper;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.springframework.integration.ws.MarshallingWebServiceOutboundGateway;
|
||||
import org.springframework.integration.ws.SimpleWebServiceOutboundGateway;
|
||||
|
||||
/**
|
||||
* Parser for the <outbound-gateway/> element in the 'ws' namespace.
|
||||
@@ -39,18 +39,15 @@ import org.springframework.util.xml.DomUtils;
|
||||
* @author Mark Fisher
|
||||
* @author Jonas Partner
|
||||
* @author Gunnar Hillert
|
||||
* @author Artem Bilan
|
||||
*
|
||||
*/
|
||||
public class WebServiceOutboundGatewayParser extends AbstractOutboundGatewayParser {
|
||||
|
||||
private static final String BASE_PACKAGE = "org.springframework.integration.ws";
|
||||
|
||||
|
||||
@Override
|
||||
protected String getGatewayClassName(Element element) {
|
||||
String simpleClassName = (StringUtils.hasText(element.getAttribute("marshaller"))) ?
|
||||
"MarshallingWebServiceOutboundGateway" : "SimpleWebServiceOutboundGateway";
|
||||
return BASE_PACKAGE + "." + simpleClassName;
|
||||
return ((StringUtils.hasText(element.getAttribute("marshaller"))) ?
|
||||
MarshallingWebServiceOutboundGateway.class : SimpleWebServiceOutboundGateway.class).getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -117,14 +114,9 @@ public class WebServiceOutboundGatewayParser extends AbstractOutboundGatewayPars
|
||||
if (StringUtils.hasText(messageFactoryRef)) {
|
||||
builder.addConstructorArgReference(messageFactoryRef);
|
||||
}
|
||||
String requestCallbackRef = element.getAttribute("request-callback");
|
||||
if (StringUtils.hasText(requestCallbackRef)) {
|
||||
builder.addPropertyReference("requestCallback", requestCallbackRef);
|
||||
}
|
||||
String faultMessageResolverRef = element.getAttribute("fault-message-resolver");
|
||||
if (StringUtils.hasText(faultMessageResolverRef)) {
|
||||
builder.addPropertyReference("faultMessageResolver", faultMessageResolverRef);
|
||||
}
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "request-callback");
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "fault-message-resolver");
|
||||
|
||||
String messageSenderRef = element.getAttribute("message-sender");
|
||||
String messageSenderListRef = element.getAttribute("message-senders");
|
||||
if (StringUtils.hasText(messageSenderRef) && StringUtils.hasText(messageSenderListRef)) {
|
||||
@@ -144,9 +136,7 @@ public class WebServiceOutboundGatewayParser extends AbstractOutboundGatewayPars
|
||||
"Only one of interceptor or interceptors should be specified.", element);
|
||||
}
|
||||
if (StringUtils.hasText(interceptorRef)) {
|
||||
ManagedList<RuntimeBeanReference> interceptors = new ManagedList<RuntimeBeanReference>();
|
||||
interceptors.add(new RuntimeBeanReference(interceptorRef));
|
||||
builder.addPropertyValue("interceptors", interceptors);
|
||||
builder.addPropertyReference("interceptors", interceptorRef);
|
||||
}
|
||||
if (StringUtils.hasText(interceptorListRef)) {
|
||||
builder.addPropertyReference("interceptors", interceptorListRef);
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
|
||||
package org.springframework.integration.ws;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
@@ -43,8 +47,6 @@ import org.springframework.ws.soap.SoapMessage;
|
||||
import org.springframework.ws.transport.WebServiceConnection;
|
||||
import org.springframework.ws.transport.WebServiceMessageSender;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
* @author Artem Bilan
|
||||
|
||||
@@ -1,17 +1,76 @@
|
||||
<?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:ws="http://www.springframework.org/schema/integration/ws"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:ws="http://www.springframework.org/schema/integration/ws"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration/ws
|
||||
http://www.springframework.org/schema/integration/ws/spring-integration-ws.xsd">
|
||||
|
||||
<ws:outbound-gateway id="gateway" request-channel="input" uri="http://springsource.org/{foo}-{bar}" interceptor="interceptor">
|
||||
<ws:uri-variable name="foo" expression="payload.substring(1,7)"/>
|
||||
<ws:uri-variable name="bar" expression="headers.x"/>
|
||||
</ws:outbound-gateway>
|
||||
|
||||
<bean id="interceptor" class="org.springframework.integration.ws.config.UriVariableTests$TestClientInterceptor"/>
|
||||
|
||||
<!--HTTP Transport-->
|
||||
<ws:outbound-gateway request-channel="inputHttp"
|
||||
uri="http://test.org/{foo}-{bar}?param={param}"
|
||||
interceptor="interceptor">
|
||||
<ws:uri-variable name="foo" expression="payload.substring(1,7)"/>
|
||||
<ws:uri-variable name="bar" expression="headers.x"/>
|
||||
<ws:uri-variable name="param" expression="headers.param"/>
|
||||
</ws:outbound-gateway>
|
||||
|
||||
<!--JMS Transport-->
|
||||
<ws:outbound-gateway request-channel="inputJms"
|
||||
uri="jms:{destination}?deliveryMode={deliveryMode}&priority={priority}"
|
||||
interceptor="interceptor"
|
||||
message-sender="jmsMessageSender">
|
||||
<ws:uri-variable name="destination" expression="headers.jmsQueue"/>
|
||||
<ws:uri-variable name="deliveryMode" expression="headers.deliveryMode"/>
|
||||
<ws:uri-variable name="priority" expression="headers.jms_priority"/>
|
||||
</ws:outbound-gateway>
|
||||
|
||||
<bean id="jmsMessageSender" class="org.mockito.Mockito" factory-method="spy">
|
||||
<constructor-arg>
|
||||
<bean class="org.springframework.ws.transport.jms.JmsMessageSender">
|
||||
<property name="connectionFactory" ref="jmsConnectionFactory"/>
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="jmsConnectionFactory" class="org.mockito.Mockito" factory-method="mock">
|
||||
<constructor-arg value="javax.jms.ConnectionFactory"/>
|
||||
</bean>
|
||||
|
||||
<!--Email Transport-->
|
||||
<ws:outbound-gateway request-channel="inputEmail"
|
||||
uri="mailto:{to}?subject={subject}"
|
||||
interceptor="emailInterceptor"
|
||||
message-sender="emailMessageSender">
|
||||
<ws:uri-variable name="to" expression="headers.to"/>
|
||||
<ws:uri-variable name="subject" expression="headers.subject"/>
|
||||
</ws:outbound-gateway>
|
||||
|
||||
<bean id="emailMessageSender" class="org.springframework.ws.transport.mail.MailMessageSender">
|
||||
<property name="from" value="spring-integration-ws SOAP Client <client@example.com>"/>
|
||||
<property name="transportUri" value="smtp://client:s04p@smtp.example.com"/>
|
||||
<property name="storeUri" value="imap://client:s04p@imap.example.com/INBOX"/>
|
||||
</bean>
|
||||
|
||||
<bean id="emailInterceptor" class="org.springframework.integration.ws.config.UriVariableTests$Int2720EmailTestClientInterceptor"/>
|
||||
|
||||
<!--XMPP Transport-->
|
||||
<ws:outbound-gateway request-channel="inputXmpp"
|
||||
uri="xmpp:{user}@jabber.org"
|
||||
interceptor="interceptor"
|
||||
message-sender="xmppMessageSender">
|
||||
<ws:uri-variable name="user" expression="headers.to"/>
|
||||
</ws:outbound-gateway>
|
||||
|
||||
<bean id="xmppMessageSender" class="org.springframework.ws.transport.xmpp.XmppMessageSender">
|
||||
<property name="connection" ref="xmppConnection"/>
|
||||
</bean>
|
||||
|
||||
<bean id="xmppConnection" class="org.mockito.Mockito" factory-method="mock">
|
||||
<constructor-arg value="org.jivesoftware.smack.XMPPConnection"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
@@ -19,31 +19,48 @@ package org.springframework.integration.ws.config;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import javax.jms.BytesMessage;
|
||||
import javax.jms.Connection;
|
||||
import javax.jms.ConnectionFactory;
|
||||
import javax.jms.DeliveryMode;
|
||||
import javax.jms.JMSException;
|
||||
import javax.jms.MessageProducer;
|
||||
import javax.jms.Queue;
|
||||
import javax.jms.Session;
|
||||
|
||||
import org.jivesoftware.smack.XMPPConnection;
|
||||
import org.jivesoftware.smack.packet.Packet;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.MessageChannel;
|
||||
import org.springframework.integration.MessageHandlingException;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.ws.client.WebServiceClientException;
|
||||
import org.springframework.ws.client.WebServiceIOException;
|
||||
import org.springframework.ws.client.WebServiceTransportException;
|
||||
import org.springframework.ws.client.support.interceptor.ClientInterceptor;
|
||||
import org.springframework.ws.context.MessageContext;
|
||||
import org.springframework.ws.soap.SoapMessageCreationException;
|
||||
import org.springframework.ws.transport.WebServiceConnection;
|
||||
import org.springframework.ws.transport.WebServiceMessageSender;
|
||||
import org.springframework.ws.transport.context.TransportContext;
|
||||
import org.springframework.ws.transport.context.TransportContextHolder;
|
||||
import org.springframework.ws.transport.http.HttpUrlConnection;
|
||||
import org.springframework.ws.transport.mail.MailSenderConnection;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
* @author Artem Bilan
|
||||
* @since 2.1
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@@ -51,15 +68,40 @@ import org.springframework.ws.transport.http.HttpUrlConnection;
|
||||
public class UriVariableTests {
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext context;
|
||||
private TestClientInterceptor interceptor;
|
||||
|
||||
@Autowired
|
||||
private MessageChannel inputHttp;
|
||||
|
||||
@Autowired
|
||||
private MessageChannel inputJms;
|
||||
|
||||
@Autowired
|
||||
private WebServiceMessageSender jmsMessageSender;
|
||||
|
||||
@Autowired
|
||||
private ConnectionFactory jmsConnectionFactory;
|
||||
|
||||
@Autowired
|
||||
private MessageChannel inputXmpp;
|
||||
|
||||
@Autowired
|
||||
private XMPPConnection xmppConnection;
|
||||
|
||||
@Autowired
|
||||
private MessageChannel inputEmail;
|
||||
|
||||
@Autowired
|
||||
private Int2720EmailTestClientInterceptor emailInterceptor;
|
||||
|
||||
@Test
|
||||
public void checkUriVariables() {
|
||||
MessageChannel input = context.getBean("input", MessageChannel.class);
|
||||
TestClientInterceptor interceptor = context.getBean("interceptor", TestClientInterceptor.class);
|
||||
Message<?> message = MessageBuilder.withPayload("<spring/>").setHeader("x", "integration").build();
|
||||
public void testHttpUriVariables() {
|
||||
Message<?> message = MessageBuilder.withPayload("<spring/>")
|
||||
.setHeader("x", "integration")
|
||||
.setHeader("param", "test1 & test2")
|
||||
.build();
|
||||
try {
|
||||
input.send(message);
|
||||
this.inputHttp.send(message);
|
||||
}
|
||||
catch (MessageHandlingException e) {
|
||||
// expected
|
||||
@@ -67,30 +109,117 @@ public class UriVariableTests {
|
||||
assertTrue(WebServiceIOException.class.equals(causeType) // offline
|
||||
|| SoapMessageCreationException.class.equals(causeType));
|
||||
}
|
||||
assertEquals("http://springsource.org/spring-integration", interceptor.getLastUri().toString());
|
||||
assertEquals("http://test.org/spring-integration?param=test1%20%26%20test2", this.interceptor.getLastUri().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInt2720JmsUriVariables() throws JMSException, IOException {
|
||||
final String destinationName = "SPRING.INTEGRATION.QUEUE";
|
||||
|
||||
Queue queue = Mockito.mock(Queue.class);
|
||||
// Need for 'QueueSession#createQueue()'
|
||||
Mockito.when(queue.getQueueName()).thenReturn(destinationName);
|
||||
|
||||
Session session = Mockito.mock(Session.class);
|
||||
Mockito.when(session.createQueue(Mockito.anyString())).thenReturn(queue);
|
||||
Mockito.when(session.createBytesMessage()).thenReturn(Mockito.mock(BytesMessage.class));
|
||||
MessageProducer producer = Mockito.mock(MessageProducer.class);
|
||||
Mockito.when(session.createProducer(queue)).thenReturn(producer);
|
||||
// For this test it's enough to not go ahead. Invoked in the 'JmsSenderConnection#onSendAfterWrite' on the
|
||||
// 'WebServiceTemplate#sendRequest' after invocation of our 'TestClientInterceptor'
|
||||
Mockito.when(session.createTemporaryQueue()).thenThrow(new WebServiceIOException("intentional"));
|
||||
|
||||
Connection connection = Mockito.mock(Connection.class);
|
||||
Mockito.when(connection.createSession(Mockito.anyBoolean(), Mockito.anyInt())).thenReturn(session);
|
||||
Mockito.when(this.jmsConnectionFactory.createConnection()).thenReturn(connection);
|
||||
|
||||
Message<?> message = MessageBuilder.withPayload("<spring/>")
|
||||
.setHeader("jmsQueue", destinationName)
|
||||
.setHeader("deliveryMode", "NON_PERSISTENT")
|
||||
.setHeader("jms_priority", "5")
|
||||
.build();
|
||||
try {
|
||||
this.inputJms.send(message);
|
||||
}
|
||||
catch (MessageHandlingException e) {
|
||||
// expected
|
||||
Class<?> causeType = e.getCause().getClass();
|
||||
assertTrue(WebServiceIOException.class.equals(causeType)); // offline
|
||||
}
|
||||
URI uri = URI.create("jms:SPRING.INTEGRATION.QUEUE?deliveryMode=NON_PERSISTENT&priority=5");
|
||||
Mockito.verify(this.jmsMessageSender).createConnection(uri);
|
||||
|
||||
Mockito.verify(session).createQueue(destinationName);
|
||||
|
||||
assertEquals("jms:" + destinationName, this.interceptor.getLastUri().toString());
|
||||
Mockito.verify(producer).setDeliveryMode(DeliveryMode.NON_PERSISTENT);
|
||||
Mockito.verify(producer).setPriority(5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInt2720EmailUriVariables() {
|
||||
final String testEmailTo = "user@example.com";
|
||||
final String testEmailSubject = "Test subject";
|
||||
Message<?> message = MessageBuilder.withPayload("<spring/>")
|
||||
.setHeader("to", testEmailTo)
|
||||
.setHeader("subject", testEmailSubject)
|
||||
.build();
|
||||
try {
|
||||
this.inputEmail.send(message);
|
||||
}
|
||||
catch (MessageHandlingException e) {
|
||||
// expected
|
||||
Class<?> causeType = e.getCause().getClass();
|
||||
assertTrue(WebServiceTransportException.class.equals(causeType)); // offline
|
||||
}
|
||||
WebServiceConnection webServiceConnection = this.emailInterceptor.getLastWebServiceConnection();
|
||||
assertEquals(testEmailTo, TestUtils.getPropertyValue(webServiceConnection, "to").toString());
|
||||
assertEquals(testEmailSubject, TestUtils.getPropertyValue(webServiceConnection, "subject"));
|
||||
assertEquals("mailto:user@example.com?subject=Test%20subject", this.emailInterceptor.getLastUri().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInt2720XmppUriVariables() {
|
||||
|
||||
Mockito.doThrow(new WebServiceIOException("intentional")).when(this.xmppConnection).sendPacket(Mockito.any(Packet.class));
|
||||
|
||||
Message<?> message = MessageBuilder.withPayload("<spring/>").setHeader("to", "user").build();
|
||||
try {
|
||||
this.inputXmpp.send(message);
|
||||
}
|
||||
catch (MessageHandlingException e) {
|
||||
// expected
|
||||
Class<?> causeType = e.getCause().getClass();
|
||||
assertTrue(WebServiceIOException.class.equals(causeType)); // offline
|
||||
}
|
||||
|
||||
ArgumentCaptor<Packet> argument = ArgumentCaptor.forClass(Packet.class);
|
||||
Mockito.verify(this.xmppConnection).sendPacket(argument.capture());
|
||||
assertEquals("user@jabber.org", argument.getValue().getTo());
|
||||
|
||||
assertEquals("xmpp:user@jabber.org", this.interceptor.getLastUri().toString());
|
||||
}
|
||||
|
||||
private static class TestClientInterceptor implements ClientInterceptor {
|
||||
|
||||
private URI lastUri;
|
||||
private volatile URI lastUri;
|
||||
|
||||
private URI getLastUri() {
|
||||
public URI getLastUri() {
|
||||
return this.lastUri;
|
||||
}
|
||||
|
||||
public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
|
||||
TransportContext tc = TransportContextHolder.getTransportContext();
|
||||
if (tc != null && tc.getConnection() instanceof HttpUrlConnection) {
|
||||
if (tc != null) {
|
||||
try {
|
||||
this.lastUri = ((HttpUrlConnection) tc.getConnection()).getUri();
|
||||
this.lastUri = tc.getConnection().getUri();
|
||||
}
|
||||
catch (URISyntaxException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("expected HttpUrlConnection as TransportContext");
|
||||
throw new IllegalStateException("expected WebServiceConnection in the TransportContext");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -104,4 +233,27 @@ public class UriVariableTests {
|
||||
}
|
||||
}
|
||||
|
||||
private static class Int2720EmailTestClientInterceptor extends TestClientInterceptor {
|
||||
|
||||
private volatile WebServiceConnection webServiceConnection;
|
||||
|
||||
public WebServiceConnection getLastWebServiceConnection() {
|
||||
return webServiceConnection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
|
||||
TransportContext tc = TransportContextHolder.getTransportContext();
|
||||
WebServiceConnection webServiceConnection = tc.getConnection();
|
||||
if (webServiceConnection instanceof MailSenderConnection) {
|
||||
this.webServiceConnection = webServiceConnection;
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("expected MailSenderConnection in the TransportContext");
|
||||
}
|
||||
|
||||
return super.handleRequest(messageContext);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ package org.springframework.integration.ws.config;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import java.net.URI;
|
||||
@@ -43,11 +42,11 @@ import org.springframework.integration.ws.SimpleWebServiceOutboundGateway;
|
||||
import org.springframework.oxm.Marshaller;
|
||||
import org.springframework.oxm.Unmarshaller;
|
||||
import org.springframework.scheduling.support.PeriodicTrigger;
|
||||
import org.springframework.web.util.UriTemplate;
|
||||
import org.springframework.ws.WebServiceMessageFactory;
|
||||
import org.springframework.ws.client.core.FaultMessageResolver;
|
||||
import org.springframework.ws.client.core.SourceExtractor;
|
||||
import org.springframework.ws.client.core.WebServiceMessageCallback;
|
||||
import org.springframework.ws.client.support.destination.DestinationProvider;
|
||||
import org.springframework.ws.client.support.interceptor.ClientInterceptor;
|
||||
import org.springframework.ws.transport.WebServiceMessageSender;
|
||||
|
||||
@@ -399,9 +398,9 @@ public class WebServiceOutboundGatewayParserTests {
|
||||
AbstractEndpoint endpoint = (AbstractEndpoint) context.getBean("gatewayWithJmsUri");
|
||||
assertEquals(EventDrivenConsumer.class, endpoint.getClass());
|
||||
MessageHandler handler = TestUtils.getPropertyValue(endpoint, "handler", MessageHandler.class);
|
||||
DestinationProvider destinationProvider = TestUtils.getPropertyValue(handler, "destinationProvider", DestinationProvider.class);
|
||||
assertNotNull(destinationProvider);
|
||||
assertEquals(URI.create("jms:wsQueue"), destinationProvider.getDestination());
|
||||
assertNull(TestUtils.getPropertyValue(handler, "destinationProvider"));
|
||||
UriTemplate uriTemplate = TestUtils.getPropertyValue(handler, "uriTemplate", UriTemplate.class);
|
||||
assertEquals(URI.create("jms:wsQueue"), uriTemplate.expand());
|
||||
}
|
||||
|
||||
@Test(expected = BeanDefinitionParsingException.class)
|
||||
|
||||
@@ -24,48 +24,37 @@
|
||||
<author>
|
||||
<firstname>Mark</firstname>
|
||||
<surname>Fisher</surname>
|
||||
</author>
|
||||
<author>
|
||||
</author><author>
|
||||
<firstname>Marius</firstname>
|
||||
<surname>Bogoevici</surname>
|
||||
</author>
|
||||
<author>
|
||||
</author><author>
|
||||
<firstname>Iwein</firstname>
|
||||
<surname>Fuld</surname>
|
||||
</author>
|
||||
<author>
|
||||
</author><author>
|
||||
<firstname>Jonas</firstname>
|
||||
<surname>Partner</surname>
|
||||
</author>
|
||||
<author>
|
||||
</author><author>
|
||||
<firstname>Oleg</firstname>
|
||||
<surname>Zhurakousky</surname>
|
||||
</author>
|
||||
<author>
|
||||
</author><author>
|
||||
<firstname>Gary</firstname>
|
||||
<surname>Russell</surname>
|
||||
</author>
|
||||
<author>
|
||||
</author><author>
|
||||
<firstname>Dave</firstname>
|
||||
<surname>Syer</surname>
|
||||
</author>
|
||||
<author>
|
||||
</author><author>
|
||||
<firstname>Josh</firstname>
|
||||
<surname>Long</surname>
|
||||
</author>
|
||||
<author>
|
||||
</author><author>
|
||||
<firstname>David</firstname>
|
||||
<surname>Turanski</surname>
|
||||
</author>
|
||||
<author>
|
||||
</author><author>
|
||||
<firstname>Gunnar</firstname>
|
||||
<surname>Hillert</surname>
|
||||
</author>
|
||||
<author>
|
||||
</author><author>
|
||||
<firstname>Artem</firstname>
|
||||
<surname>Bilan</surname>
|
||||
</author>
|
||||
<author>
|
||||
</author><author>
|
||||
<firstname>Amol</firstname>
|
||||
<surname>Nayak</surname>
|
||||
</author>
|
||||
|
||||
@@ -71,7 +71,13 @@
|
||||
payloads to <classname>String</classname>. For more information see <xref linkend="transformer"/>.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="3.0-ws-outbound-uri-substitution">
|
||||
<title>Web Service Outbound URI Configuration</title>
|
||||
<para>
|
||||
Web Service Outbound Gateway 'uri' attribute now supports <code><uri-variable/></code> substitution for all
|
||||
URI-schemes supported by Spring Web Services. For more information see <xref linkend="outbound-uri"/>.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
</chapter>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<title>Outbound Web Service Gateways</title>
|
||||
<para>
|
||||
To invoke a Web Service upon sending a message to a channel, there are two options - both of which build
|
||||
upon the <ulink url="http://static.springframework.org/spring-ws/sites/1.5/">Spring Web Services</ulink>
|
||||
upon the <ulink url="http://static.springsource.org/spring-ws/site/">Spring Web Services</ulink>
|
||||
project: <classname>SimpleWebServiceOutboundGateway</classname> and
|
||||
<classname>MarshallingWebServiceOutboundGateway</classname>. The former will accept either a
|
||||
<classname>String</classname> or <interfacename>javax.xml.transform.Source</interfacename> as the message
|
||||
@@ -21,10 +21,10 @@
|
||||
<note>
|
||||
When using the namespace support described below, you will only need to set a URI. Internally, the parser
|
||||
will configure a fixed URI DestinationProvider implementation. If you do need dynamic resolution of the
|
||||
URI at runtime, however, then the DestinationProvider can provide such behavior as looking up the URI from
|
||||
a registry. See the Spring Web Services
|
||||
<ulink url="http://static.springsource.org/spring-ws/sites/1.5/apidocs/index.html">javadoc</ulink> for
|
||||
more information about the DestinationProvider strategy.
|
||||
URI at runtime, however, then the DestinationProvider can provide such behavior as looking up the URI from
|
||||
a registry. See the Spring Web Services
|
||||
<ulink url="http://static.springsource.org/spring-ws/site/apidocs/org/springframework/ws/client/support/destination/DestinationProvider.html">DestinationProvider</ulink>
|
||||
JavaDoc for more information about this strategy.
|
||||
</note>
|
||||
</para>
|
||||
<para>
|
||||
@@ -59,7 +59,7 @@ as per standard Spring Web Services configuration.
|
||||
</para>
|
||||
<para>
|
||||
For more detail on how to use these components, see the Spring Web Services reference guide's chapter covering
|
||||
<ulink url="http://static.springframework.org/spring-ws/sites/1.5/reference/html/server.html">creating a Web Service</ulink>.
|
||||
<ulink url="http://static.springframework.org/spring-ws/site/reference/html/server.html">creating a Web Service</ulink>.
|
||||
The chapter covering
|
||||
<ulink url="http://static.springframework.org/spring-ws/site/reference/html/oxm.html">Object/XML mapping</ulink> is also applicable again.
|
||||
</para>
|
||||
@@ -133,17 +133,26 @@ as per standard Spring Web Services configuration.
|
||||
<section id="outbound-uri">
|
||||
<title>Outbound URI Configuration</title>
|
||||
<para>
|
||||
For URIs with an <emphasis>http:</emphasis> (or <emphasis>https:</emphasis>) scheme,
|
||||
<uri-variable/> substitution is supported:
|
||||
For all URI-schemes supported by Spring Web Services
|
||||
(<ulink url="http://static.springsource.org/spring-ws/site/reference/html/client.html#client-transports">URIs and Transports</ulink>)
|
||||
<code><uri-variable/></code> substitution is provided:
|
||||
</para>
|
||||
<programlisting language="xml"><![CDATA[<ws:outbound-gateway id="gateway" request-channel="input" uri="http://springsource.org/{foo}-{bar}">
|
||||
<programlisting language="xml"><![CDATA[<ws:outbound-gateway id="gateway" request-channel="input"
|
||||
uri="http://springsource.org/{foo}-{bar}">
|
||||
<ws:uri-variable name="foo" expression="payload.substring(1,7)"/>
|
||||
<ws:uri-variable name="bar" expression="headers.x"/>
|
||||
</ws:outbound-gateway>
|
||||
|
||||
<ws:outbound-gateway request-channel="inputJms"
|
||||
uri="jms:{destination}?deliveryMode={deliveryMode}&priority={priority}"
|
||||
message-sender="jmsMessageSender">
|
||||
<ws:uri-variable name="destination" expression="headers.jmsQueue"/>
|
||||
<ws:uri-variable name="deliveryMode" expression="headers.deliveryMode"/>
|
||||
<ws:uri-variable name="priority" expression="headers.jms_priority"/>
|
||||
</ws:outbound-gateway>]]></programlisting>
|
||||
<para>
|
||||
For other schemes, such as <emphasis>jms:</emphasis>, or if a <classname>DestinationProvider</classname>
|
||||
is supplied, variable substitution is not supported and a configuration error will result if variables
|
||||
are provided.
|
||||
</para>
|
||||
<para>
|
||||
If a <classname>DestinationProvider</classname> is supplied, variable substitution is not supported
|
||||
and a configuration error will result if variables are provided.
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
||||
|
||||
Reference in New Issue
Block a user