Merge pull request #84 from markfisher/INT-1931
add URI variable Expressions to outbound gateway
This commit is contained in:
@@ -471,7 +471,8 @@ project('spring-integration-ws') {
|
||||
compile project(":spring-integration-core")
|
||||
compile "org.springframework:spring-expression:$springVersion"
|
||||
compile "org.springframework:spring-oxm:$springVersion"
|
||||
compile ("org.springframework.ws:spring-ws-core:$springWsVersion"){
|
||||
compile "org.springframework:spring-web:$springVersion"
|
||||
compile ("org.springframework.ws:spring-ws-core:$springWsVersion") {
|
||||
exclude group: 'org.springframework', module: 'spring-webmvc'
|
||||
exclude group: 'org.springframework', module: 'spring-web'
|
||||
exclude group: 'org.springframework', module: 'spring-context-support'
|
||||
|
||||
@@ -88,12 +88,6 @@
|
||||
</repository>
|
||||
</repositories>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-test</artifactId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.xml.messaging.saaj</groupId>
|
||||
<artifactId>saaj-impl</artifactId>
|
||||
@@ -101,6 +95,12 @@
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-test</artifactId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
@@ -119,6 +119,12 @@
|
||||
<version>1.2.12</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cglib</groupId>
|
||||
<artifactId>cglib-nodep</artifactId>
|
||||
<version>2.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.ws</groupId>
|
||||
<artifactId>spring-ws-core</artifactId>
|
||||
@@ -140,10 +146,10 @@
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cglib</groupId>
|
||||
<artifactId>cglib-nodep</artifactId>
|
||||
<version>2.2</version>
|
||||
<scope>test</scope>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<version>3.0.6.RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.xml.soap</groupId>
|
||||
@@ -189,12 +195,6 @@
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-core</artifactId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest-all</artifactId>
|
||||
@@ -207,6 +207,12 @@
|
||||
<version>1.8.4</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-core</artifactId>
|
||||
<version>2.1.0.BUILD-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit-dep</artifactId>
|
||||
|
||||
@@ -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.
|
||||
@@ -17,13 +17,31 @@
|
||||
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 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.ExpressionParser;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
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.MessagingException;
|
||||
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
|
||||
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;
|
||||
@@ -43,20 +61,58 @@ import org.springframework.ws.transport.WebServiceMessageSender;
|
||||
*/
|
||||
public abstract class AbstractWebServiceOutboundGateway extends AbstractReplyProducingMessageHandler {
|
||||
|
||||
private static final ExpressionParser PARSER = new SpelExpressionParser();
|
||||
|
||||
|
||||
private final WebServiceTemplate webServiceTemplate;
|
||||
|
||||
private final UriTemplate uriTemplate;
|
||||
|
||||
private final DestinationProvider destinationProvider;
|
||||
|
||||
private final Map<String, Expression> uriVariableExpressions = new HashMap<String, Expression>();
|
||||
|
||||
private final StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
|
||||
|
||||
private volatile WebServiceMessageCallback requestCallback;
|
||||
|
||||
private volatile boolean ignoreEmptyResponses = true;
|
||||
|
||||
|
||||
public AbstractWebServiceOutboundGateway(DestinationProvider destinationProvider, WebServiceMessageFactory messageFactory) {
|
||||
Assert.notNull(destinationProvider, "DestinationProvider must not be null");
|
||||
this.webServiceTemplate = (messageFactory != null) ?
|
||||
public AbstractWebServiceOutboundGateway(String uri, WebServiceMessageFactory messageFactory) {
|
||||
Assert.hasText(uri, "URI must not be empty");
|
||||
this.webServiceTemplate = (messageFactory != null) ?
|
||||
new WebServiceTemplate(messageFactory) : new WebServiceTemplate();
|
||||
this.webServiceTemplate.setDestinationProvider(destinationProvider);
|
||||
this.destinationProvider = null;
|
||||
this.uriTemplate = new HttpUrlTemplate(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.destinationProvider = destinationProvider;
|
||||
// we always call WebServiceTemplate methods with an explicit URI argument,
|
||||
// but in case the WebServiceTemplate is accessed directly we'll set this:
|
||||
this.webServiceTemplate.setDestinationProvider(destinationProvider);
|
||||
this.uriTemplate = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the Map of URI variable expressions to evaluate against the outbound message
|
||||
* when replacing the variable placeholders in a URI template.
|
||||
*/
|
||||
public void setUriVariableExpressions(Map<String, String> uriVariableExpressions) {
|
||||
synchronized (this.uriVariableExpressions) {
|
||||
this.uriVariableExpressions.clear();
|
||||
if (!CollectionUtils.isEmpty(uriVariableExpressions)) {
|
||||
for (Map.Entry<String, String> entry : uriVariableExpressions.entrySet()) {
|
||||
this.uriVariableExpressions.put(entry.getKey(), PARSER.parseExpression(entry.getValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setReplyChannel(MessageChannel replyChannel) {
|
||||
this.setOutputChannel(replyChannel);
|
||||
@@ -95,13 +151,32 @@ public abstract class AbstractWebServiceOutboundGateway extends AbstractReplyPro
|
||||
this.webServiceTemplate.setInterceptors(interceptors);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInit() {
|
||||
super.onInit();
|
||||
BeanFactory beanFactory = this.getBeanFactory();
|
||||
if (beanFactory != null) {
|
||||
this.evaluationContext.setBeanResolver(new BeanFactoryResolver(beanFactory));
|
||||
}
|
||||
ConversionService conversionService = this.getConversionService();
|
||||
if (conversionService != null) {
|
||||
this.evaluationContext.setTypeConverter(new StandardTypeConverter(conversionService));
|
||||
}
|
||||
this.evaluationContext.addPropertyAccessor(new MapAccessor());
|
||||
}
|
||||
|
||||
protected WebServiceTemplate getWebServiceTemplate() {
|
||||
return this.webServiceTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Object handleRequestMessage(Message<?> message) {
|
||||
Object responsePayload = this.doHandle(message.getPayload(), this.getRequestCallback(message));
|
||||
URI uri = prepareUri(message);
|
||||
if (uri == null) {
|
||||
throw new MessageDeliveryException(message, "Failed to determine URI for " +
|
||||
"Web Service request in outbound gateway: " + this.getComponentName());
|
||||
}
|
||||
Object responsePayload = this.doHandle(uri.toString(), message.getPayload(), this.getRequestCallback(message));
|
||||
if (responsePayload != null) {
|
||||
boolean shouldIgnore = (this.ignoreEmptyResponses
|
||||
&& responsePayload instanceof String && !StringUtils.hasText((String) responsePayload));
|
||||
@@ -112,9 +187,21 @@ public abstract class AbstractWebServiceOutboundGateway extends AbstractReplyPro
|
||||
return null;
|
||||
}
|
||||
|
||||
protected abstract Object doHandle(Object requestPayload, WebServiceMessageCallback requestCallback);
|
||||
protected abstract Object doHandle(String uri, Object requestPayload, WebServiceMessageCallback requestCallback);
|
||||
|
||||
|
||||
private URI prepareUri(Message<?> requestMessage) {
|
||||
if (this.destinationProvider != null) {
|
||||
return this.destinationProvider.getDestination();
|
||||
}
|
||||
Map<String, Object> uriVariables = new HashMap<String, Object>();
|
||||
for (Map.Entry<String, Expression> entry : this.uriVariableExpressions.entrySet()) {
|
||||
Object value = entry.getValue().getValue(this.evaluationContext, requestMessage, String.class);
|
||||
uriVariables.put(entry.getKey(), value);
|
||||
}
|
||||
return this.uriTemplate.expand(uriVariables);
|
||||
}
|
||||
|
||||
private WebServiceMessageCallback getRequestCallback(Message<?> requestMessage) {
|
||||
String soapAction = requestMessage.getHeaders().get(WebServiceHeaders.SOAP_ACTION, String.class);
|
||||
return (soapAction != null) ?
|
||||
@@ -147,4 +234,32 @@ public abstract class AbstractWebServiceOutboundGateway extends AbstractReplyPro
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
@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-2009 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.
|
||||
@@ -35,10 +35,7 @@ public class MarshallingWebServiceOutboundGateway extends AbstractWebServiceOutb
|
||||
|
||||
public MarshallingWebServiceOutboundGateway(DestinationProvider destinationProvider, Marshaller marshaller, Unmarshaller unmarshaller, WebServiceMessageFactory messageFactory) {
|
||||
super(destinationProvider, messageFactory);
|
||||
Assert.notNull(marshaller, "marshaller must not be null");
|
||||
Assert.notNull(unmarshaller, "unmarshaller must not be null");
|
||||
this.getWebServiceTemplate().setMarshaller(marshaller);
|
||||
this.getWebServiceTemplate().setUnmarshaller(unmarshaller);
|
||||
this.configureMarshallers(marshaller, unmarshaller);
|
||||
}
|
||||
|
||||
public MarshallingWebServiceOutboundGateway(DestinationProvider destinationProvider, Marshaller marshaller, Unmarshaller unmarshaller) {
|
||||
@@ -47,23 +44,60 @@ public class MarshallingWebServiceOutboundGateway extends AbstractWebServiceOutb
|
||||
|
||||
public MarshallingWebServiceOutboundGateway(DestinationProvider destinationProvider, Marshaller marshaller, WebServiceMessageFactory messageFactory) {
|
||||
super(destinationProvider, messageFactory);
|
||||
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 the " + this.getClass().getName() +
|
||||
"(DestinationProvider destinationProvider, Marshaller marshaller, Unmarshaller unmarshaller) constructor.");
|
||||
this.getWebServiceTemplate().setMarshaller(marshaller);
|
||||
this.getWebServiceTemplate().setUnmarshaller((Unmarshaller) marshaller);
|
||||
this.configureMarshallers(marshaller);
|
||||
}
|
||||
|
||||
public MarshallingWebServiceOutboundGateway(DestinationProvider destinationProvider, Marshaller marshaller) {
|
||||
this(destinationProvider, marshaller, (WebServiceMessageFactory) null);
|
||||
}
|
||||
|
||||
public MarshallingWebServiceOutboundGateway(String uri, Marshaller marshaller, Unmarshaller unmarshaller, WebServiceMessageFactory messageFactory) {
|
||||
super(uri, messageFactory);
|
||||
this.configureMarshallers(marshaller, unmarshaller);
|
||||
}
|
||||
|
||||
public MarshallingWebServiceOutboundGateway(String uri, Marshaller marshaller, Unmarshaller unmarshaller) {
|
||||
this(uri, marshaller, unmarshaller, null);
|
||||
}
|
||||
|
||||
public MarshallingWebServiceOutboundGateway(String uri, Marshaller marshaller, WebServiceMessageFactory messageFactory) {
|
||||
super(uri, messageFactory);
|
||||
this.configureMarshallers(marshaller);
|
||||
}
|
||||
|
||||
public MarshallingWebServiceOutboundGateway(String uri, Marshaller marshaller) {
|
||||
this(uri, marshaller, (WebServiceMessageFactory) null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the provided Marshaller and Unmarshaller on this gateway's WebServiceTemplate.
|
||||
* Neither may be null.
|
||||
*/
|
||||
private void configureMarshallers(Marshaller marshaller, Unmarshaller unmarshaller) {
|
||||
Assert.notNull(marshaller, "marshaller must not be null");
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object doHandle(Object requestPayload, WebServiceMessageCallback requestCallback) {
|
||||
return this.getWebServiceTemplate().marshalSendAndReceive(requestPayload, requestCallback);
|
||||
protected Object doHandle(String uri, Object requestPayload, WebServiceMessageCallback requestCallback) {
|
||||
return this.getWebServiceTemplate().marshalSendAndReceive(uri, requestPayload, requestCallback);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -58,23 +58,36 @@ public class SimpleWebServiceOutboundGateway extends AbstractWebServiceOutboundG
|
||||
this.sourceExtractor = (sourceExtractor != null) ? sourceExtractor : new DefaultSourceExtractor();
|
||||
}
|
||||
|
||||
public SimpleWebServiceOutboundGateway(String uri) {
|
||||
this(uri, null, null);
|
||||
}
|
||||
|
||||
public SimpleWebServiceOutboundGateway(String uri, SourceExtractor<?> sourceExtractor) {
|
||||
this(uri, sourceExtractor, (WebServiceMessageFactory) null);
|
||||
}
|
||||
|
||||
public SimpleWebServiceOutboundGateway(String uri, SourceExtractor<?> sourceExtractor, WebServiceMessageFactory messageFactory) {
|
||||
super(uri, messageFactory);
|
||||
this.sourceExtractor = (sourceExtractor != null) ? sourceExtractor : new DefaultSourceExtractor();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Object doHandle(Object requestPayload, WebServiceMessageCallback requestCallback) {
|
||||
protected Object doHandle(String uri, Object requestPayload, WebServiceMessageCallback requestCallback) {
|
||||
if (requestPayload instanceof Source) {
|
||||
return this.getWebServiceTemplate().sendSourceAndReceive(
|
||||
(Source) requestPayload, requestCallback, this.sourceExtractor);
|
||||
uri, (Source) requestPayload, requestCallback, this.sourceExtractor);
|
||||
}
|
||||
if (requestPayload instanceof String) {
|
||||
StringResult result = new StringResult();
|
||||
this.getWebServiceTemplate().sendSourceAndReceiveToResult(
|
||||
new StringSource((String) requestPayload), requestCallback, result);
|
||||
uri, new StringSource((String) requestPayload), requestCallback, result);
|
||||
return result.toString();
|
||||
}
|
||||
if (requestPayload instanceof Document) {
|
||||
DOMResult result = new DOMResult();
|
||||
this.getWebServiceTemplate().sendSourceAndReceiveToResult(
|
||||
new DOMSource((Document) requestPayload), requestCallback, result);
|
||||
uri, new DOMSource((Document) requestPayload), requestCallback, result);
|
||||
return result.getNode();
|
||||
}
|
||||
throw new MessagingException("Unsupported payload type '" + requestPayload.getClass() +
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2009 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.net.URI;
|
||||
|
||||
/**
|
||||
* @author Jonas Partner
|
||||
* @author Mark Fisher
|
||||
* @since 1.0.3
|
||||
*/
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.ws.client.support.destination.DestinationProvider;
|
||||
|
||||
|
||||
/**
|
||||
* A {@link DestinationProvider} implementation that returns a fixed URI.
|
||||
* This is used by the outbound gateway parser when no 'destination-provider'
|
||||
* reference has been configured.
|
||||
*
|
||||
* @author Jonas Partner
|
||||
* @author Mark Fisher
|
||||
* @since 1.0.3
|
||||
*/
|
||||
class FixedUriDestinationProvider implements DestinationProvider {
|
||||
|
||||
private final URI uri;
|
||||
|
||||
|
||||
public FixedUriDestinationProvider(String uri) {
|
||||
Assert.hasText(uri, "uri must not be null or empty");
|
||||
this.uri = URI.create(uri);
|
||||
}
|
||||
|
||||
|
||||
public URI getDestination() {
|
||||
return this.uri;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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,17 +16,21 @@
|
||||
|
||||
package org.springframework.integration.ws.config;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.config.ConstructorArgumentValues;
|
||||
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.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.config.xml.AbstractOutboundGatewayParser;
|
||||
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
|
||||
/**
|
||||
* Parser for the <outbound-gateway/> element in the 'ws' namespace.
|
||||
@@ -46,34 +50,41 @@ public class WebServiceOutboundGatewayParser extends AbstractOutboundGatewayPars
|
||||
return BASE_PACKAGE + "." + simpleClassName;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override
|
||||
protected BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(this.getGatewayClassName(element));
|
||||
this.buildDestinationProvider(builder, element, parserContext);
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(this.getGatewayClassName(element));
|
||||
String uri = element.getAttribute("uri");
|
||||
String destinationProvider = element.getAttribute("destination-provider");
|
||||
List<Element> uriVariableElements = DomUtils.getChildElementsByTagName(element, "uri-variable");
|
||||
if (!(StringUtils.hasText(destinationProvider) ^ StringUtils.hasText(uri))) {
|
||||
parserContext.getReaderContext().error(
|
||||
"Exactly one of 'uri' or 'destination-provider' is required.", element);
|
||||
}
|
||||
if (StringUtils.hasText(destinationProvider)) {
|
||||
if (!CollectionUtils.isEmpty(uriVariableElements)) {
|
||||
parserContext.getReaderContext().error("No 'uri-variable' sub-elements are allowed when "
|
||||
+ "a 'destination-provider' reference has been provided.", element);
|
||||
}
|
||||
builder.addConstructorArgReference(destinationProvider);
|
||||
}
|
||||
else {
|
||||
builder.addConstructorArgValue(uri);
|
||||
if (!CollectionUtils.isEmpty(uriVariableElements)) {
|
||||
Map<String, String> uriVariableExpressions = new HashMap<String, String>();
|
||||
for (Element uriVariableElement : uriVariableElements) {
|
||||
String name = uriVariableElement.getAttribute("name");
|
||||
String expression = uriVariableElement.getAttribute("expression");
|
||||
uriVariableExpressions.put(name, expression);
|
||||
}
|
||||
builder.addPropertyValue("uriVariableExpressions", uriVariableExpressions);
|
||||
}
|
||||
}
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "reply-channel");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "ignore-empty-responses");
|
||||
this.postProcessGateway(builder, element, parserContext);
|
||||
return builder;
|
||||
}
|
||||
|
||||
private void buildDestinationProvider(BeanDefinitionBuilder builder, Element element, ParserContext parserContext) {
|
||||
String uri = element.getAttribute("uri");
|
||||
String destinationProvider = element.getAttribute("destination-provider");
|
||||
if (!(StringUtils.hasText(destinationProvider) ^ StringUtils.hasText(uri))) {
|
||||
parserContext.getReaderContext().error("Exactly one of 'uri' or 'destination-provider' is required.", element);
|
||||
return;
|
||||
}
|
||||
if (StringUtils.hasText(destinationProvider)) {
|
||||
builder.addConstructorArgReference(destinationProvider);
|
||||
}
|
||||
else {
|
||||
ConstructorArgumentValues cavs = new ConstructorArgumentValues();
|
||||
cavs.addGenericArgumentValue(uri);
|
||||
builder.addConstructorArgValue(new RootBeanDefinition(
|
||||
BASE_PACKAGE +".config.FixedUriDestinationProvider", cavs, null));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postProcessGateway(BeanDefinitionBuilder builder, Element element, ParserContext parserContext) {
|
||||
String marshallerRef = element.getAttribute("marshaller");
|
||||
|
||||
@@ -26,9 +26,10 @@
|
||||
Defines a Web Service based outbound Messaging Gateway.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:all>
|
||||
<xsd:sequence>
|
||||
<xsd:element ref="integration:poller" minOccurs="0" maxOccurs="1"/>
|
||||
</xsd:all>
|
||||
<xsd:element name="uri-variable" type="uriVariableType" minOccurs="0" maxOccurs="unbounded" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="id" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
@@ -64,10 +65,13 @@
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="uri" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The Destination URI for this Web Service Gateway. If the URI should be determined at runtime
|
||||
(e.g. registry lookup), then configure a 'destination-provider' reference instead.
|
||||
</xsd:documentation>
|
||||
(e.g. registry lookup), then configure a 'destination-provider' reference instead. Aternatively,
|
||||
this URI may include {placeholders} whose values are determined by evaluating SpEL expressions
|
||||
provided via 'uri-variable' sub-elements. The root object for those evaluations is the actual
|
||||
request Message at runtime, i.e. you can access its payload or headers in the expression.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="destination-provider" type="xsd:string">
|
||||
@@ -203,6 +207,31 @@
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:complexType name="uriVariableType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Expression to be evaluated against the Message to replace a URI {placeholder} with the evaluation result.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:attribute name="name" use="required">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Name of the placeholder to be replaced.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="expression" use="required">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Expression to be evaluated to determine the replacement value.
|
||||
The Message is the root object of the expression, therefore
|
||||
the 'payload' and 'headers' are available directly. Any bean
|
||||
may be resolved if the bean name is preceded with '@'.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:element name="inbound-gateway">
|
||||
<xsd:complexType>
|
||||
<xsd:annotation>
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<?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
|
||||
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://localhost/test/{foo}/{bar}" interceptor="interceptor">
|
||||
<ws:uri-variable name="foo" expression="payload.substring(1,4)"/>
|
||||
<ws:uri-variable name="bar" expression="headers.bar"/>
|
||||
</ws:outbound-gateway>
|
||||
|
||||
<bean id="interceptor" class="org.springframework.integration.ws.config.UriVariableTests$TestClientInterceptor"/>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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 static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
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.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.support.interceptor.ClientInterceptor;
|
||||
import org.springframework.ws.context.MessageContext;
|
||||
import org.springframework.ws.transport.context.TransportContext;
|
||||
import org.springframework.ws.transport.context.TransportContextHolder;
|
||||
import org.springframework.ws.transport.http.HttpUrlConnection;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
* @since 2.1
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
public class UriVariableTests {
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext context;
|
||||
|
||||
@Test
|
||||
public void checkUriVariables() {
|
||||
MessageChannel input = context.getBean("input", MessageChannel.class);
|
||||
TestClientInterceptor interceptor = context.getBean("interceptor", TestClientInterceptor.class);
|
||||
Message<?> message = MessageBuilder.withPayload("<FOO/>").setHeader("bar", "BAR").build();
|
||||
try {
|
||||
input.send(message);
|
||||
}
|
||||
catch (MessageHandlingException e) {
|
||||
// expected
|
||||
assertEquals(WebServiceIOException.class, e.getCause().getClass());
|
||||
}
|
||||
assertEquals("http://localhost/test/FOO/BAR", interceptor.getLastUri().toString());
|
||||
}
|
||||
|
||||
|
||||
private static class TestClientInterceptor implements ClientInterceptor {
|
||||
|
||||
private URI lastUri;
|
||||
|
||||
private URI getLastUri() {
|
||||
return this.lastUri;
|
||||
}
|
||||
|
||||
public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
|
||||
TransportContext tc = TransportContextHolder.getTransportContext();
|
||||
if (tc != null && tc.getConnection() instanceof HttpUrlConnection) {
|
||||
try {
|
||||
this.lastUri = ((HttpUrlConnection) tc.getConnection()).getUri();
|
||||
}
|
||||
catch (URISyntaxException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("expected HttpUrlConnection as TransportContext");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean handleResponse(MessageContext messageContext) throws WebServiceClientException {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean handleFault(MessageContext messageContext) throws WebServiceClientException {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.integration.ws.config;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -337,20 +338,22 @@ public class WebServiceOutboundGatewayParserTests {
|
||||
assertEquals(messageFactory, templateAccessor.getPropertyValue("messageFactory"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test
|
||||
public void simpleGatewayWithDestinationProvider() {
|
||||
ApplicationContext context = new ClassPathXmlApplicationContext(
|
||||
"simpleWebServiceOutboundGatewayParserTests.xml", this.getClass());
|
||||
AbstractEndpoint endpoint = (AbstractEndpoint) context.getBean("gatewayWithDestinationProvider");
|
||||
assertEquals(EventDrivenConsumer.class, endpoint.getClass());
|
||||
Object gateway = new DirectFieldAccessor(endpoint).getPropertyValue("handler");
|
||||
StubDestinationProvider stubProvider = (StubDestinationProvider) context.getBean("destinationProvider");
|
||||
assertEquals(SimpleWebServiceOutboundGateway.class, gateway.getClass());
|
||||
DirectFieldAccessor accessor = new DirectFieldAccessor(gateway);
|
||||
Object destinationProviderObject = new DirectFieldAccessor(
|
||||
accessor.getPropertyValue("webServiceTemplate")).getPropertyValue("destinationProvider");
|
||||
StubDestinationProvider stubProvider = (StubDestinationProvider)context.getBean("destinationProvider");
|
||||
assertEquals("Wrong DestinationProvider", stubProvider, destinationProviderObject );
|
||||
}
|
||||
assertEquals("Wrong DestinationProvider", stubProvider, accessor.getPropertyValue("destinationProvider"));
|
||||
assertNull(accessor.getPropertyValue("uriTemplate"));
|
||||
Object destinationProviderObject = new DirectFieldAccessor(
|
||||
accessor.getPropertyValue("webServiceTemplate")).getPropertyValue("destinationProvider");
|
||||
assertEquals("Wrong DestinationProvider", stubProvider,destinationProviderObject);
|
||||
}
|
||||
|
||||
@Test(expected = BeanDefinitionParsingException.class)
|
||||
public void invalidGatewayWithBothUriAndDestinationProvider() {
|
||||
|
||||
Reference in New Issue
Block a user