INT-4208: Add WebFlux-Based HttpMessageHandler
JIRA: https://jira.spring.io/browse/INT-4208 Since `AsyncRestTemplate` is deprecated in Spring 5.0, it doesn't make sense to promote that feature via our new `AsyncHttpRequestExecutingMessageHandler` component * Rework (and rename) `AsyncHttpRequestExecutingMessageHandler` to `ReactiveHttpRequestExecutingMessageHandler` and make it based on the WebFlux `WebClient` * Fix Java DSL (`ReactiveHttpMessageHandlerSpec`) and all tests according a new logic in the `ReactiveHttpRequestExecutingMessageHandler` * Fix XML namespace support to use new `ReactiveHttpRequestExecutingMessageHandler` and don't expose unused options like `converters` and `request-factory` * Fix `What's New` and `http.adoc` * To remain with `async` mode for the `ReactiveHttpRequestExecutingMessageHandler` behavior support fix `AbstractMessageProducingHandler` to adapt reply `Mono` to the `SettableListenableFuture` * Introduce new `reactive` behavior for the `AbstractMessageProducingHandler` when `outputChannel` is `ReactiveSubscribableChannel` and perform `.subscribeTo(Publisher)` for `Publisher` reply * Upgrade to Spring AMQP `2.0 M3` * Downgrade to Spring Security `4.2.2` Address PR comments Add async error handling to the one-way case Minor polishing and checkstyle fix
This commit is contained in:
committed by
Gary Russell
parent
d954e6a66f
commit
19c5402079
@@ -130,12 +130,12 @@ subprojects { subproject ->
|
||||
servletApiVersion = '3.1.0'
|
||||
slf4jVersion = "1.7.21"
|
||||
smackVersion = '4.1.7'
|
||||
springAmqpVersion = project.hasProperty('springAmqpVersion') ? project.springAmqpVersion : '2.0.0.BUILD-SNAPSHOT'
|
||||
springAmqpVersion = project.hasProperty('springAmqpVersion') ? project.springAmqpVersion : '2.0.0.M3'
|
||||
springDataJpaVersion = '2.0.0.M2'
|
||||
springDataMongoVersion = '2.0.0.M2'
|
||||
springDataRedisVersion = '2.0.0.M2'
|
||||
springGemfireVersion = '2.0.0.M2'
|
||||
springSecurityVersion = '5.0.0.BUILD-SNAPSHOT'
|
||||
springSecurityVersion = '4.2.2.RELEASE'
|
||||
springSocialTwitterVersion = '2.0.0.M1'
|
||||
springRetryVersion = '1.2.0.RELEASE'
|
||||
springVersion = project.hasProperty('springVersion') ? project.springVersion : '5.0.0.M5'
|
||||
@@ -389,8 +389,10 @@ project('spring-integration-http') {
|
||||
dependencies {
|
||||
compile project(":spring-integration-core")
|
||||
compile "org.springframework:spring-webmvc:$springVersion"
|
||||
compile "org.springframework:spring-webflux:$springVersion"
|
||||
compile ("javax.servlet:javax.servlet-api:$servletApiVersion", provided)
|
||||
compile ("com.rometools:rome:$romeToolsVersion", optional)
|
||||
compile ("io.projectreactor.ipc:reactor-netty:$reactorNettyVersion" , optional)
|
||||
|
||||
testCompile project(":spring-integration-security")
|
||||
testCompile "org.springframework.security:spring-security-config:$springSecurityVersion"
|
||||
|
||||
@@ -21,7 +21,10 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.reactivestreams.Publisher;
|
||||
|
||||
import org.springframework.integration.IntegrationMessageHeaderAccessor;
|
||||
import org.springframework.integration.channel.ReactiveSubscribableChannel;
|
||||
import org.springframework.integration.core.MessageProducer;
|
||||
import org.springframework.integration.core.MessagingTemplate;
|
||||
import org.springframework.integration.routingslip.RoutingSlipRouteStrategy;
|
||||
@@ -37,6 +40,10 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.ListenableFutureCallback;
|
||||
import org.springframework.util.concurrent.SettableListenableFuture;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* The base {@link AbstractMessageHandler} implementation for the {@link MessageProducer}.
|
||||
@@ -44,6 +51,7 @@ import org.springframework.util.concurrent.ListenableFutureCallback;
|
||||
* @author David Liu
|
||||
* @author Artem Bilan
|
||||
* @author Gary Russell
|
||||
*
|
||||
* since 4.1
|
||||
*/
|
||||
public abstract class AbstractMessageProducingHandler extends AbstractMessageHandler
|
||||
@@ -181,36 +189,56 @@ public abstract class AbstractMessageProducingHandler extends AbstractMessageHan
|
||||
}
|
||||
}
|
||||
|
||||
if (this.async && reply instanceof ListenableFuture<?>) {
|
||||
ListenableFuture<?> future = (ListenableFuture<?>) reply;
|
||||
final Object theReplyChannel = replyChannel;
|
||||
future.addCallback(new ListenableFutureCallback<Object>() {
|
||||
if (this.async && (reply instanceof ListenableFuture<?> || reply instanceof Publisher<?>)) {
|
||||
if (reply instanceof ListenableFuture<?> || !(getOutputChannel() instanceof ReactiveSubscribableChannel)) {
|
||||
ListenableFuture<?> future;
|
||||
if (reply instanceof ListenableFuture<?>) {
|
||||
future = (ListenableFuture<?>) reply;
|
||||
}
|
||||
else {
|
||||
SettableListenableFuture<Object> settableListenableFuture = new SettableListenableFuture<>();
|
||||
|
||||
@Override
|
||||
public void onSuccess(Object result) {
|
||||
Message<?> replyMessage = null;
|
||||
try {
|
||||
replyMessage = createOutputMessage(result, requestHeaders);
|
||||
sendOutput(replyMessage, theReplyChannel, false);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Exception exceptionToLogAndSend = e;
|
||||
if (!(e instanceof MessagingException)) {
|
||||
exceptionToLogAndSend = new MessageHandlingException(requestMessage, e);
|
||||
if (replyMessage != null) {
|
||||
exceptionToLogAndSend = new MessagingException(replyMessage, exceptionToLogAndSend);
|
||||
}
|
||||
Mono.from((Publisher<?>) reply)
|
||||
.subscribe(settableListenableFuture::set, settableListenableFuture::setException);
|
||||
|
||||
future = settableListenableFuture;
|
||||
}
|
||||
|
||||
Object theReplyChannel = replyChannel;
|
||||
future.addCallback(new ListenableFutureCallback<Object>() {
|
||||
|
||||
@Override
|
||||
public void onSuccess(Object result) {
|
||||
Message<?> replyMessage = null;
|
||||
try {
|
||||
replyMessage = createOutputMessage(result, requestHeaders);
|
||||
sendOutput(replyMessage, theReplyChannel, false);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Exception exceptionToLogAndSend = e;
|
||||
if (!(e instanceof MessagingException)) {
|
||||
exceptionToLogAndSend = new MessageHandlingException(requestMessage, e);
|
||||
if (replyMessage != null) {
|
||||
exceptionToLogAndSend = new MessagingException(replyMessage, exceptionToLogAndSend);
|
||||
}
|
||||
}
|
||||
logger.error("Failed to send async reply: " + result.toString(), exceptionToLogAndSend);
|
||||
onFailure(exceptionToLogAndSend);
|
||||
}
|
||||
logger.error("Failed to send async reply: " + result.toString(), exceptionToLogAndSend);
|
||||
onFailure(exceptionToLogAndSend);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable ex) {
|
||||
sendErrorMessage(requestMessage, ex);
|
||||
}
|
||||
});
|
||||
@Override
|
||||
public void onFailure(Throwable ex) {
|
||||
sendErrorMessage(requestMessage, ex);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
else {
|
||||
((ReactiveSubscribableChannel) getOutputChannel())
|
||||
.subscribeTo(Flux.from((Publisher<?>) reply)
|
||||
.map(result -> createOutputMessage(result, requestHeaders)));
|
||||
}
|
||||
}
|
||||
else {
|
||||
sendOutput(createOutputMessage(reply, requestHeaders), replyChannel, false);
|
||||
|
||||
@@ -41,34 +41,21 @@ import org.springframework.util.xml.DomUtils;
|
||||
abstract class HttpAdapterParsingUtils {
|
||||
|
||||
static final String[] SYNC_REST_TEMPLATE_REFERENCE_ATTRIBUTES = {
|
||||
"request-factory", "error-handler", "message-converters"
|
||||
};
|
||||
|
||||
static final String[] ASYNC_REST_TEMPLATE_REFERENCE_ATTRIBUTES = {
|
||||
"async-request-factory", "error-handler", "message-converters"
|
||||
"request-factory", "error-handler", "message-converters"
|
||||
};
|
||||
|
||||
static void verifyNoRestTemplateAttributes(Element element, ParserContext parserContext) {
|
||||
for (String attributeName : SYNC_REST_TEMPLATE_REFERENCE_ATTRIBUTES) {
|
||||
if (element.hasAttribute(attributeName)) {
|
||||
parserContext.getReaderContext().error("When providing a 'rest-template' reference, the '"
|
||||
+ attributeName + "' attribute is not allowed.",
|
||||
parserContext.extractSource(element));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void verifyNoAsyncRestTemplateAttributes(Element element, ParserContext parserContext) {
|
||||
for (String attributeName : ASYNC_REST_TEMPLATE_REFERENCE_ATTRIBUTES) {
|
||||
if (element.hasAttribute(attributeName)) {
|
||||
parserContext.getReaderContext().error("When providing an 'async-rest-template' reference, the '"
|
||||
+ attributeName + "' attribute is not allowed.",
|
||||
parserContext.extractSource(element));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void configureUriVariableExpressions(BeanDefinitionBuilder builder, ParserContext parserContext, Element element) {
|
||||
static void configureUriVariableExpressions(BeanDefinitionBuilder builder, ParserContext parserContext,
|
||||
Element element) {
|
||||
String uriVariablesExpression = element.getAttribute("uri-variables-expression");
|
||||
|
||||
List<Element> uriVariableElements = DomUtils.getChildElementsByTagName(element, "uri-variable");
|
||||
@@ -79,8 +66,9 @@ abstract class HttpAdapterParsingUtils {
|
||||
parserContext.getReaderContext().error("'uri-variables-expression' attribute " +
|
||||
"and 'uri-variable' sub-elements are mutually exclusive.", element);
|
||||
}
|
||||
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(ExpressionFactoryBean.class)
|
||||
.addConstructorArgValue(uriVariablesExpression);
|
||||
BeanDefinitionBuilder beanDefinitionBuilder =
|
||||
BeanDefinitionBuilder.genericBeanDefinition(ExpressionFactoryBean.class)
|
||||
.addConstructorArgValue(uriVariablesExpression);
|
||||
builder.addPropertyValue("uriVariablesExpression", beanDefinitionBuilder.getBeanDefinition());
|
||||
}
|
||||
|
||||
@@ -89,21 +77,24 @@ abstract class HttpAdapterParsingUtils {
|
||||
for (Element uriVariableElement : uriVariableElements) {
|
||||
String name = uriVariableElement.getAttribute("name");
|
||||
String expression = uriVariableElement.getAttribute("expression");
|
||||
BeanDefinitionBuilder factoryBeanBuilder = BeanDefinitionBuilder.genericBeanDefinition(ExpressionFactoryBean.class);
|
||||
BeanDefinitionBuilder factoryBeanBuilder =
|
||||
BeanDefinitionBuilder.genericBeanDefinition(ExpressionFactoryBean.class);
|
||||
factoryBeanBuilder.addConstructorArgValue(expression);
|
||||
uriVariableExpressions.put(name, factoryBeanBuilder.getBeanDefinition());
|
||||
uriVariableExpressions.put(name, factoryBeanBuilder.getBeanDefinition());
|
||||
}
|
||||
builder.addPropertyValue("uriVariableExpressions", uriVariableExpressions);
|
||||
}
|
||||
}
|
||||
|
||||
static void configureUrlConstructorArg(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
static void configureUrlConstructorArg(Element element, ParserContext parserContext,
|
||||
BeanDefinitionBuilder builder) {
|
||||
String urlAttribute = element.getAttribute("url");
|
||||
String urlExpressionAttribute = element.getAttribute("url-expression");
|
||||
boolean hasUrlAttribute = StringUtils.hasText(urlAttribute);
|
||||
boolean hasUrlExpressionAttribute = StringUtils.hasText(urlExpressionAttribute);
|
||||
if (!(hasUrlAttribute ^ hasUrlExpressionAttribute)) {
|
||||
parserContext.getReaderContext().error("Adapter must have exactly one of 'url' or 'url-expression'", element);
|
||||
if (hasUrlAttribute == hasUrlExpressionAttribute) {
|
||||
parserContext.getReaderContext()
|
||||
.error("Adapter must have exactly one of 'url' or 'url-expression'", element);
|
||||
}
|
||||
RootBeanDefinition expressionDef;
|
||||
if (hasUrlAttribute) {
|
||||
@@ -126,8 +117,9 @@ abstract class HttpAdapterParsingUtils {
|
||||
boolean hasHttpMethodExpression = StringUtils.hasText(httpMethodExpression);
|
||||
|
||||
if (hasHttpMethod && hasHttpMethodExpression) {
|
||||
parserContext.getReaderContext().error("The 'http-method' and 'http-method-expression' are mutually exclusive. " +
|
||||
"You can only have one or the other", element);
|
||||
parserContext.getReaderContext()
|
||||
.error("The 'http-method' and 'http-method-expression' are mutually exclusive. " +
|
||||
"You can only have one or the other", element);
|
||||
}
|
||||
|
||||
RootBeanDefinition expressionDef = null;
|
||||
@@ -144,7 +136,8 @@ abstract class HttpAdapterParsingUtils {
|
||||
}
|
||||
}
|
||||
|
||||
static void setExpectedResponseOrExpression(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
static void setExpectedResponseOrExpression(Element element, ParserContext parserContext,
|
||||
BeanDefinitionBuilder builder) {
|
||||
String expectedResponseType = element.getAttribute("expected-response-type");
|
||||
String expectedResponseTypeExpression = element.getAttribute("expected-response-type-expression");
|
||||
|
||||
@@ -152,8 +145,9 @@ abstract class HttpAdapterParsingUtils {
|
||||
boolean hasExpectedResponseTypeExpression = StringUtils.hasText(expectedResponseTypeExpression);
|
||||
|
||||
if (hasExpectedResponseType && hasExpectedResponseTypeExpression) {
|
||||
parserContext.getReaderContext().error("The 'expected-response-type' and 'expected-response-type-expression' are mutually exclusive. " +
|
||||
"You can only have one or the other", element);
|
||||
parserContext.getReaderContext()
|
||||
.error("The 'expected-response-type' and 'expected-response-type-expression' are mutually exclusive. " +
|
||||
"You can only have one or the other", element);
|
||||
}
|
||||
|
||||
RootBeanDefinition expressionDef = null;
|
||||
|
||||
@@ -34,8 +34,8 @@ public class HttpNamespaceHandler extends AbstractIntegrationNamespaceHandler {
|
||||
registerBeanDefinitionParser("inbound-gateway", new HttpInboundEndpointParser(true));
|
||||
registerBeanDefinitionParser("outbound-channel-adapter", new HttpOutboundChannelAdapterParser());
|
||||
registerBeanDefinitionParser("outbound-gateway", new HttpOutboundGatewayParser());
|
||||
registerBeanDefinitionParser("outbound-async-channel-adapter", new HttpOutboundChannelAdapterParser());
|
||||
registerBeanDefinitionParser("outbound-async-gateway", new HttpOutboundGatewayParser());
|
||||
registerBeanDefinitionParser("outbound-reactive-channel-adapter", new HttpOutboundChannelAdapterParser());
|
||||
registerBeanDefinitionParser("outbound-reactive-gateway", new HttpOutboundGatewayParser());
|
||||
registerBeanDefinitionParser("graph-controller", new IntegrationGraphControllerParser());
|
||||
}
|
||||
|
||||
|
||||
@@ -23,8 +23,8 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.config.xml.AbstractOutboundChannelAdapterParser;
|
||||
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
|
||||
import org.springframework.integration.http.outbound.AsyncHttpRequestExecutingMessageHandler;
|
||||
import org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler;
|
||||
import org.springframework.integration.http.outbound.ReactiveHttpRequestExecutingMessageHandler;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -35,6 +35,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Gary Russell
|
||||
* @author Artem Bilan
|
||||
* @author Shiliang Li
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public class HttpOutboundChannelAdapterParser extends AbstractOutboundChannelAdapterParser {
|
||||
@@ -42,9 +43,9 @@ public class HttpOutboundChannelAdapterParser extends AbstractOutboundChannelAda
|
||||
@Override
|
||||
protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) {
|
||||
BeanDefinitionBuilder builder;
|
||||
boolean async = element.getLocalName().contains("async");
|
||||
if (async) {
|
||||
builder = BeanDefinitionBuilder.genericBeanDefinition(AsyncHttpRequestExecutingMessageHandler.class);
|
||||
boolean reactive = element.getLocalName().contains("reactive");
|
||||
if (reactive) {
|
||||
builder = BeanDefinitionBuilder.genericBeanDefinition(ReactiveHttpRequestExecutingMessageHandler.class);
|
||||
}
|
||||
else {
|
||||
builder = BeanDefinitionBuilder.genericBeanDefinition(HttpRequestExecutingMessageHandler.class);
|
||||
@@ -55,17 +56,11 @@ public class HttpOutboundChannelAdapterParser extends AbstractOutboundChannelAda
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "encode-uri");
|
||||
HttpAdapterParsingUtils.setHttpMethodOrExpression(element, parserContext, builder);
|
||||
|
||||
if (async) {
|
||||
String asyncTemplateRef = element.getAttribute("async-rest-template");
|
||||
if (reactive) {
|
||||
String webClientRef = element.getAttribute("web-client");
|
||||
|
||||
if (StringUtils.hasText(asyncTemplateRef)) {
|
||||
HttpAdapterParsingUtils.verifyNoAsyncRestTemplateAttributes(element, parserContext);
|
||||
builder.addConstructorArgReference(asyncTemplateRef);
|
||||
}
|
||||
else {
|
||||
for (String referenceAttributeName : HttpAdapterParsingUtils.ASYNC_REST_TEMPLATE_REFERENCE_ATTRIBUTES) {
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, referenceAttributeName);
|
||||
}
|
||||
if (StringUtils.hasText(webClientRef)) {
|
||||
builder.addConstructorArgReference(webClientRef);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -95,7 +90,8 @@ public class HttpOutboundChannelAdapterParser extends AbstractOutboundChannelAda
|
||||
else if (StringUtils.hasText(mappedRequestHeaders)) {
|
||||
BeanDefinitionBuilder headerMapperBuilder = BeanDefinitionBuilder.genericBeanDefinition(
|
||||
"org.springframework.integration.http.support.DefaultHttpHeaderMapper");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(headerMapperBuilder, element, "mapped-request-headers", "outboundHeaderNames");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(headerMapperBuilder, element,
|
||||
"mapped-request-headers", "outboundHeaderNames");
|
||||
builder.addPropertyValue("headerMapper", headerMapperBuilder.getBeanDefinition());
|
||||
}
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "charset");
|
||||
|
||||
@@ -22,8 +22,8 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.config.xml.AbstractConsumerEndpointParser;
|
||||
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
|
||||
import org.springframework.integration.http.outbound.AsyncHttpRequestExecutingMessageHandler;
|
||||
import org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler;
|
||||
import org.springframework.integration.http.outbound.ReactiveHttpRequestExecutingMessageHandler;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -45,9 +45,9 @@ public class HttpOutboundGatewayParser extends AbstractConsumerEndpointParser {
|
||||
@Override
|
||||
protected BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext) {
|
||||
BeanDefinitionBuilder builder;
|
||||
boolean async = element.getLocalName().contains("async");
|
||||
if (async) {
|
||||
builder = BeanDefinitionBuilder.genericBeanDefinition(AsyncHttpRequestExecutingMessageHandler.class);
|
||||
boolean reactive = element.getLocalName().contains("reactive");
|
||||
if (reactive) {
|
||||
builder = BeanDefinitionBuilder.genericBeanDefinition(ReactiveHttpRequestExecutingMessageHandler.class);
|
||||
}
|
||||
else {
|
||||
builder = BeanDefinitionBuilder.genericBeanDefinition(HttpRequestExecutingMessageHandler.class);
|
||||
@@ -57,16 +57,10 @@ public class HttpOutboundGatewayParser extends AbstractConsumerEndpointParser {
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "encode-uri");
|
||||
HttpAdapterParsingUtils.setHttpMethodOrExpression(element, parserContext, builder);
|
||||
|
||||
if (async) {
|
||||
String asyncTemplateRef = element.getAttribute("async-rest-template");
|
||||
if (StringUtils.hasText(asyncTemplateRef)) {
|
||||
HttpAdapterParsingUtils.verifyNoAsyncRestTemplateAttributes(element, parserContext);
|
||||
builder.addConstructorArgReference(asyncTemplateRef);
|
||||
}
|
||||
else {
|
||||
for (String referenceAttributeName : HttpAdapterParsingUtils.ASYNC_REST_TEMPLATE_REFERENCE_ATTRIBUTES) {
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, referenceAttributeName);
|
||||
}
|
||||
if (reactive) {
|
||||
String webClientRef = element.getAttribute("web-client");
|
||||
if (StringUtils.hasText(webClientRef)) {
|
||||
builder.addConstructorArgReference(webClientRef);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -88,8 +82,10 @@ public class HttpOutboundGatewayParser extends AbstractConsumerEndpointParser {
|
||||
String mappedResponseHeaders = element.getAttribute("mapped-response-headers");
|
||||
if (StringUtils.hasText(headerMapper)) {
|
||||
if (StringUtils.hasText(mappedRequestHeaders) || StringUtils.hasText(mappedResponseHeaders)) {
|
||||
parserContext.getReaderContext().error("Neither 'mapped-request-headers' or 'mapped-response-headers' " +
|
||||
"attributes are allowed when a 'header-mapper' has been specified.", parserContext.extractSource(element));
|
||||
parserContext.getReaderContext()
|
||||
.error("Neither 'mapped-request-headers' or 'mapped-response-headers' " +
|
||||
"attributes are allowed when a 'header-mapper' has been specified.",
|
||||
parserContext.extractSource(element));
|
||||
return null;
|
||||
}
|
||||
builder.addPropertyReference("headerMapper", headerMapper);
|
||||
@@ -98,12 +94,15 @@ public class HttpOutboundGatewayParser extends AbstractConsumerEndpointParser {
|
||||
BeanDefinitionBuilder headerMapperBuilder = BeanDefinitionBuilder.genericBeanDefinition(
|
||||
"org.springframework.integration.http.support.DefaultHttpHeaderMapper");
|
||||
headerMapperBuilder.setFactoryMethod("outboundMapper");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(headerMapperBuilder, element, "mapped-request-headers", "outboundHeaderNames");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(headerMapperBuilder, element, "mapped-response-headers", "inboundHeaderNames");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(headerMapperBuilder, element,
|
||||
"mapped-request-headers", "outboundHeaderNames");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(headerMapperBuilder, element,
|
||||
"mapped-response-headers", "inboundHeaderNames");
|
||||
builder.addPropertyValue("headerMapper", headerMapperBuilder.getBeanDefinition());
|
||||
}
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "charset");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "extract-request-payload", "extractPayload");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "extract-request-payload",
|
||||
"extractPayload");
|
||||
|
||||
HttpAdapterParsingUtils.setExpectedResponseOrExpression(element, parserContext, builder);
|
||||
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright 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.http.dsl;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.common.LiteralExpression;
|
||||
import org.springframework.http.client.AsyncClientHttpRequestFactory;
|
||||
import org.springframework.integration.expression.ValueExpression;
|
||||
import org.springframework.integration.http.outbound.AsyncHttpRequestExecutingMessageHandler;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.client.AsyncRestTemplate;
|
||||
|
||||
/**
|
||||
* The {@link BaseHttpMessageHandlerSpec} implementation for the {@link AsyncHttpRequestExecutingMessageHandler}.
|
||||
* @author Shiliang Li
|
||||
* @since 5.0
|
||||
* @see AsyncHttpRequestExecutingMessageHandler
|
||||
*/
|
||||
public class AsyncHttpMessageHandlerSpec
|
||||
extends BaseHttpMessageHandlerSpec<AsyncHttpMessageHandlerSpec, AsyncHttpRequestExecutingMessageHandler> {
|
||||
|
||||
private final AsyncRestTemplate asyncRestTemplate;
|
||||
|
||||
AsyncHttpMessageHandlerSpec(URI uri, AsyncRestTemplate asyncRestTemplate) {
|
||||
this(new ValueExpression<>(uri), asyncRestTemplate);
|
||||
}
|
||||
|
||||
AsyncHttpMessageHandlerSpec(String uri, AsyncRestTemplate asyncRestTemplate) {
|
||||
this(new LiteralExpression(uri), asyncRestTemplate);
|
||||
}
|
||||
|
||||
AsyncHttpMessageHandlerSpec(Expression uriExpression, AsyncRestTemplate asyncRestTemplate) {
|
||||
super(new AsyncHttpRequestExecutingMessageHandler(uriExpression, asyncRestTemplate));
|
||||
this.asyncRestTemplate = asyncRestTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link AsyncClientHttpRequestFactory} for the underlying {@link AsyncRestTemplate}.
|
||||
* @param asyncRequestFactory The request factory.
|
||||
* @return the spec
|
||||
*/
|
||||
public AsyncHttpMessageHandlerSpec asyncRequestFactory(AsyncClientHttpRequestFactory asyncRequestFactory) {
|
||||
Assert.isNull(this.asyncRestTemplate,
|
||||
"the 'requestFactory' must be specified on the provided 'restTemplate': " + this.asyncRestTemplate);
|
||||
this.target.setAsyncRequestFactory(asyncRequestFactory);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isRestTemplateSet() {
|
||||
return this.asyncRestTemplate != null;
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.integration.http.dsl;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
@@ -27,7 +26,6 @@ import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.integration.dsl.ComponentsRegistration;
|
||||
import org.springframework.integration.dsl.MessageHandlerSpec;
|
||||
import org.springframework.integration.expression.FunctionExpression;
|
||||
@@ -37,8 +35,6 @@ import org.springframework.integration.http.support.DefaultHttpHeaderMapper;
|
||||
import org.springframework.integration.mapping.HeaderMapper;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.client.ResponseErrorHandler;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* The base {@link MessageHandlerSpec} for {@link AbstractHttpRequestExecutingMessageHandler}s.
|
||||
@@ -319,29 +315,5 @@ public abstract class BaseHttpMessageHandlerSpec<S extends BaseHttpMessageHandle
|
||||
return Collections.singletonList(this.headerMapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link ResponseErrorHandler} for the underlying {@link RestTemplate}.
|
||||
* @param errorHandler The error handler.
|
||||
* @return the spec
|
||||
*/
|
||||
public S errorHandler(ResponseErrorHandler errorHandler) {
|
||||
Assert.isTrue(this.isRestTemplateSet(),
|
||||
"the 'errorHandler' must be specified on the provided 'restTemplate'");
|
||||
this.target.setErrorHandler(errorHandler);
|
||||
return _this();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a list of {@link HttpMessageConverter}s to be used by the underlying {@link RestTemplate}.
|
||||
* Converters configured via this method will override the default converters.
|
||||
* @param messageConverters The message converters.
|
||||
* @return the spec
|
||||
*/
|
||||
public S messageConverters(HttpMessageConverter<?>... messageConverters) {
|
||||
Assert.isTrue(!isRestTemplateSet(), "the 'messageConverters' must be specified on the provided restTemplate");
|
||||
this.target.setMessageConverters(Arrays.asList(messageConverters));
|
||||
return _this();
|
||||
}
|
||||
|
||||
protected abstract boolean isRestTemplateSet();
|
||||
protected abstract boolean isClientSet();
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@ import org.springframework.integration.http.inbound.HttpRequestHandlingMessaging
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.client.AsyncRestTemplate;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
/**
|
||||
* The HTTP components Factory.
|
||||
@@ -128,90 +128,95 @@ public final class Http {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@link AsyncHttpMessageHandlerSpec} builder for one-way adapter based on provided {@link URI}.
|
||||
* Create an {@link ReactiveHttpMessageHandlerSpec} builder for one-way adapter based on provided {@link URI}.
|
||||
* @param uri the {@link URI} to send requests.
|
||||
* @return the AsyncHttpMessageHandlerSpec instance
|
||||
* @return the ReactiveHttpMessageHandlerSpec instance
|
||||
*/
|
||||
public static AsyncHttpMessageHandlerSpec outboundAsyncChannelAdapter(URI uri) {
|
||||
return outboundAsyncChannelAdapter(uri, null);
|
||||
public static ReactiveHttpMessageHandlerSpec outboundReactiveChannelAdapter(URI uri) {
|
||||
return outboundReactiveChannelAdapter(uri, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@link AsyncHttpMessageHandlerSpec} builder for one-way adapter based on provided {@code uri}.
|
||||
* Create an {@link ReactiveHttpMessageHandlerSpec} builder for one-way adapter based on provided {@code uri}.
|
||||
* @param uri the {@code uri} to send requests.
|
||||
* @return the AsyncHttpMessageHandlerSpec instance
|
||||
* @return the ReactiveHttpMessageHandlerSpec instance
|
||||
*/
|
||||
public static AsyncHttpMessageHandlerSpec outboundAsyncChannelAdapter(String uri) {
|
||||
return outboundAsyncChannelAdapter(uri, null);
|
||||
public static ReactiveHttpMessageHandlerSpec outboundReactiveChannelAdapter(String uri) {
|
||||
return outboundReactiveChannelAdapter(uri, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@link AsyncHttpMessageHandlerSpec} builder for one-way adapter based on provided {@code Function}
|
||||
* Create an {@link ReactiveHttpMessageHandlerSpec} builder for one-way adapter based on provided {@code Function}
|
||||
* to evaluate target {@code uri} against request message.
|
||||
* @param uriFunction the {@code Function} to evaluate {@code uri} at runtime.
|
||||
* @param <P> the expected payload type.
|
||||
* @return the AsyncHttpMessageHandlerSpec instance
|
||||
* @return the ReactiveHttpMessageHandlerSpec instance
|
||||
*/
|
||||
public static <P> AsyncHttpMessageHandlerSpec outboundAsyncChannelAdapter(Function<Message<P>, ?> uriFunction) {
|
||||
return outboundAsyncChannelAdapter(new FunctionExpression<>(uriFunction));
|
||||
public static <P> ReactiveHttpMessageHandlerSpec outboundReactiveChannelAdapter(Function<Message<P>, ?> uriFunction) {
|
||||
return outboundReactiveChannelAdapter(new FunctionExpression<>(uriFunction));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@link AsyncHttpMessageHandlerSpec} builder for one-way adapter based on provided SpEL {@link Expression}
|
||||
* to evaluate target {@code uri} against request message.
|
||||
* @param uriExpression the SpEL {@link Expression} to evaluate {@code uri} at runtime.
|
||||
* @return the AsyncHttpMessageHandlerSpec instance
|
||||
*/
|
||||
public static AsyncHttpMessageHandlerSpec outboundAsyncChannelAdapter(Expression uriExpression) {
|
||||
return outboundAsyncChannelAdapter(uriExpression, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@link AsyncHttpMessageHandlerSpec} builder for one-way adapter
|
||||
* based on provided {@link URI} and {@link AsyncRestTemplate}.
|
||||
* @param uri the {@link URI} to send requests.
|
||||
* @param asyncRestTemplate {@link AsyncRestTemplate} to use.
|
||||
* @return the AsyncHttpMessageHandlerSpec instance
|
||||
*/
|
||||
public static AsyncHttpMessageHandlerSpec outboundAsyncChannelAdapter(URI uri, AsyncRestTemplate asyncRestTemplate) {
|
||||
return new AsyncHttpMessageHandlerSpec(uri, asyncRestTemplate).expectReply(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@link AsyncHttpMessageHandlerSpec} builder for one-way adapter
|
||||
* based on provided {@code uri} and {@link AsyncRestTemplate}.
|
||||
* @param uri the {@code uri} to send requests.
|
||||
* @param asyncRestTemplate {@link AsyncRestTemplate} to use.
|
||||
* @return the AsyncHttpMessageHandlerSpec instance
|
||||
*/
|
||||
public static AsyncHttpMessageHandlerSpec outboundAsyncChannelAdapter(String uri, AsyncRestTemplate asyncRestTemplate) {
|
||||
return new AsyncHttpMessageHandlerSpec(uri, asyncRestTemplate).expectReply(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@link AsyncHttpMessageHandlerSpec} builder for one-way adapter
|
||||
* based on provided {@code Function} to evaluate target {@code uri} against request message
|
||||
* and {@link AsyncRestTemplate} for HTTP exchanges.
|
||||
* @param uriFunction the {@code Function} to evaluate {@code uri} at runtime.
|
||||
* @param asyncRestTemplate {@link AsyncRestTemplate} to use.
|
||||
* @param <P> the expected payload type.
|
||||
* @return the AsyncHttpMessageHandlerSpec instance
|
||||
*/
|
||||
public static <P> AsyncHttpMessageHandlerSpec outboundAsyncChannelAdapter(Function<Message<P>, ?> uriFunction,
|
||||
AsyncRestTemplate asyncRestTemplate) {
|
||||
return outboundAsyncChannelAdapter(new FunctionExpression<>(uriFunction), asyncRestTemplate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@link AsyncHttpMessageHandlerSpec} builder for one-way adapter
|
||||
* Create an {@link ReactiveHttpMessageHandlerSpec} builder for one-way adapter
|
||||
* based on provided SpEL {@link Expression} to evaluate target {@code uri}
|
||||
* against request message and {@link AsyncRestTemplate} for HTTP exchanges.
|
||||
* against request message.
|
||||
* @param uriExpression the SpEL {@link Expression} to evaluate {@code uri} at runtime.
|
||||
* @param asyncRestTemplate {@link AsyncRestTemplate} to use.
|
||||
* @return the AsyncHttpMessageHandlerSpec instance
|
||||
* @return the ReactiveHttpMessageHandlerSpec instance
|
||||
*/
|
||||
public static AsyncHttpMessageHandlerSpec outboundAsyncChannelAdapter(Expression uriExpression, AsyncRestTemplate asyncRestTemplate) {
|
||||
return new AsyncHttpMessageHandlerSpec(uriExpression, asyncRestTemplate).expectReply(false);
|
||||
public static ReactiveHttpMessageHandlerSpec outboundReactiveChannelAdapter(Expression uriExpression) {
|
||||
return outboundReactiveChannelAdapter(uriExpression, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@link ReactiveHttpMessageHandlerSpec} builder for one-way adapter
|
||||
* based on provided {@link URI} and {@link WebClient}.
|
||||
* @param uri the {@link URI} to send requests.
|
||||
* @param webClient {@link WebClient} to use.
|
||||
* @return the ReactiveHttpMessageHandlerSpec instance
|
||||
*/
|
||||
public static ReactiveHttpMessageHandlerSpec outboundReactiveChannelAdapter(URI uri, WebClient webClient) {
|
||||
return new ReactiveHttpMessageHandlerSpec(uri, webClient)
|
||||
.expectReply(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@link ReactiveHttpMessageHandlerSpec} builder for one-way adapter
|
||||
* based on provided {@code uri} and {@link WebClient}.
|
||||
* @param uri the {@code uri} to send requests.
|
||||
* @param webClient {@link WebClient} to use.
|
||||
* @return the ReactiveHttpMessageHandlerSpec instance
|
||||
*/
|
||||
public static ReactiveHttpMessageHandlerSpec outboundReactiveChannelAdapter(String uri, WebClient webClient) {
|
||||
return new ReactiveHttpMessageHandlerSpec(uri, webClient)
|
||||
.expectReply(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@link ReactiveHttpMessageHandlerSpec} builder for one-way adapter
|
||||
* based on provided {@code Function} to evaluate target {@code uri} against request message
|
||||
* and {@link WebClient} for HTTP exchanges.
|
||||
* @param uriFunction the {@code Function} to evaluate {@code uri} at runtime.
|
||||
* @param webClient {@link WebClient} to use.
|
||||
* @param <P> the expected payload type.
|
||||
* @return the ReactiveHttpMessageHandlerSpec instance
|
||||
*/
|
||||
public static <P> ReactiveHttpMessageHandlerSpec outboundReactiveChannelAdapter(Function<Message<P>, ?> uriFunction,
|
||||
WebClient webClient) {
|
||||
return outboundReactiveChannelAdapter(new FunctionExpression<>(uriFunction), webClient);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@link ReactiveHttpMessageHandlerSpec} builder for one-way adapter
|
||||
* based on provided SpEL {@link Expression} to evaluate target {@code uri}
|
||||
* against request message and {@link WebClient} for HTTP exchanges.
|
||||
* @param uriExpression the SpEL {@link Expression} to evaluate {@code uri} at runtime.
|
||||
* @param webClient {@link WebClient} to use.
|
||||
* @return the ReactiveHttpMessageHandlerSpec instance
|
||||
*/
|
||||
public static ReactiveHttpMessageHandlerSpec outboundReactiveChannelAdapter(Expression uriExpression,
|
||||
WebClient webClient) {
|
||||
return new ReactiveHttpMessageHandlerSpec(uriExpression, webClient)
|
||||
.expectReply(false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -302,90 +307,93 @@ public final class Http {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@link AsyncHttpMessageHandlerSpec} builder for request-reply gateway based on provided {@link URI}.
|
||||
* Create an {@link ReactiveHttpMessageHandlerSpec} builder for request-reply gateway
|
||||
* based on provided {@link URI}.
|
||||
* @param uri the {@link URI} to send requests.
|
||||
* @return the AsyncHttpMessageHandlerSpec instance
|
||||
* @return the ReactiveHttpMessageHandlerSpec instance
|
||||
*/
|
||||
public static AsyncHttpMessageHandlerSpec outboundAsyncGateway(URI uri) {
|
||||
return outboundAsyncGateway(uri, null);
|
||||
public static ReactiveHttpMessageHandlerSpec outboundReactiveGateway(URI uri) {
|
||||
return outboundReactiveGateway(uri, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@link AsyncHttpMessageHandlerSpec} builder for request-reply gateway based on provided {@code uri}.
|
||||
* Create an {@link ReactiveHttpMessageHandlerSpec} builder for request-reply gateway
|
||||
* based on provided {@code uri}.
|
||||
* @param uri the {@code uri} to send requests.
|
||||
* @return the AsyncHttpMessageHandlerSpec instance
|
||||
* @return the ReactiveHttpMessageHandlerSpec instance
|
||||
*/
|
||||
public static AsyncHttpMessageHandlerSpec outboundAsyncGateway(String uri) {
|
||||
return outboundAsyncGateway(uri, null);
|
||||
public static ReactiveHttpMessageHandlerSpec outboundReactiveGateway(String uri) {
|
||||
return outboundReactiveGateway(uri, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@link AsyncHttpMessageHandlerSpec} builder for request-reply gateway
|
||||
* Create an {@link ReactiveHttpMessageHandlerSpec} builder for request-reply gateway
|
||||
* based on provided {@code Function} to evaluate target {@code uri} against request message.
|
||||
* @param uriFunction the {@code Function} to evaluate {@code uri} at runtime.
|
||||
* @param <P> the expected payload type.
|
||||
* @return the AsyncHttpMessageHandlerSpec instance
|
||||
* @return the ReactiveHttpMessageHandlerSpec instance
|
||||
*/
|
||||
public static <P> AsyncHttpMessageHandlerSpec outboundAsyncGateway(Function<Message<P>, ?> uriFunction) {
|
||||
return outboundAsyncGateway(new FunctionExpression<>(uriFunction));
|
||||
public static <P> ReactiveHttpMessageHandlerSpec outboundReactiveGateway(Function<Message<P>, ?> uriFunction) {
|
||||
return outboundReactiveGateway(new FunctionExpression<>(uriFunction));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@link AsyncHttpMessageHandlerSpec} builder for request-reply gateway
|
||||
* Create an {@link ReactiveHttpMessageHandlerSpec} builder for request-reply gateway
|
||||
* based on provided SpEL {@link Expression} to evaluate target {@code uri} against request message.
|
||||
* @param uriExpression the SpEL {@link Expression} to evaluate {@code uri} at runtime.
|
||||
* @return the AsyncHttpMessageHandlerSpec instance
|
||||
* @return the ReactiveHttpMessageHandlerSpec instance
|
||||
*/
|
||||
public static AsyncHttpMessageHandlerSpec outboundAsyncGateway(Expression uriExpression) {
|
||||
return outboundAsyncGateway(uriExpression, null);
|
||||
public static ReactiveHttpMessageHandlerSpec outboundReactiveGateway(Expression uriExpression) {
|
||||
return outboundReactiveGateway(uriExpression, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@link AsyncHttpMessageHandlerSpec} builder for request-reply gateway
|
||||
* based on provided {@link URI} and {@link RestTemplate}.
|
||||
* Create an {@link ReactiveHttpMessageHandlerSpec} builder for request-reply gateway
|
||||
* based on provided {@link URI} and {@link WebClient}.
|
||||
* @param uri the {@link URI} to send requests.
|
||||
* @param asyncRestTemplate {@link AsyncRestTemplate} to use.
|
||||
* @return the AsyncHttpMessageHandlerSpec instance
|
||||
* @param webClient {@link WebClient} to use.
|
||||
* @return the ReactiveHttpMessageHandlerSpec instance
|
||||
*/
|
||||
public static AsyncHttpMessageHandlerSpec outboundAsyncGateway(URI uri, AsyncRestTemplate asyncRestTemplate) {
|
||||
return new AsyncHttpMessageHandlerSpec(uri, asyncRestTemplate);
|
||||
public static ReactiveHttpMessageHandlerSpec outboundReactiveGateway(URI uri, WebClient webClient) {
|
||||
return new ReactiveHttpMessageHandlerSpec(uri, webClient);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@link AsyncHttpMessageHandlerSpec} builder for request-reply gateway
|
||||
* based on provided {@code uri} and {@link RestTemplate}.
|
||||
* Create an {@link ReactiveHttpMessageHandlerSpec} builder for request-reply gateway
|
||||
* based on provided {@code uri} and {@link WebClient}.
|
||||
* @param uri the {@code uri} to send requests.
|
||||
* @param asyncRestTemplate {@link AsyncRestTemplate} to use.
|
||||
* @return the AsyncHttpMessageHandlerSpec instance
|
||||
* @param webClient {@link WebClient} to use.
|
||||
* @return the ReactiveHttpMessageHandlerSpec instance
|
||||
*/
|
||||
public static AsyncHttpMessageHandlerSpec outboundAsyncGateway(String uri, AsyncRestTemplate asyncRestTemplate) {
|
||||
return new AsyncHttpMessageHandlerSpec(uri, asyncRestTemplate);
|
||||
public static ReactiveHttpMessageHandlerSpec outboundReactiveGateway(String uri, WebClient webClient) {
|
||||
return new ReactiveHttpMessageHandlerSpec(uri, webClient);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@link AsyncHttpMessageHandlerSpec} builder for request-reply gateway
|
||||
* Create an {@link ReactiveHttpMessageHandlerSpec} builder for request-reply gateway
|
||||
* based on provided {@code Function} to evaluate target {@code uri} against request message
|
||||
* and {@link RestTemplate} for HTTP exchanges.
|
||||
* and {@link WebClient} for HTTP exchanges.
|
||||
* @param uriFunction the {@code Function} to evaluate {@code uri} at runtime.
|
||||
* @param asyncRestTemplate {@link AsyncRestTemplate} to use.
|
||||
* @param webClient {@link WebClient} to use.
|
||||
* @param <P> the expected payload type.
|
||||
* @return the AsyncHttpMessageHandlerSpec instance
|
||||
* @return the ReactiveHttpMessageHandlerSpec instance
|
||||
*/
|
||||
public static <P> AsyncHttpMessageHandlerSpec outboundAsyncGateway(Function<Message<P>, ?> uriFunction,
|
||||
AsyncRestTemplate asyncRestTemplate) {
|
||||
return outboundAsyncGateway(new FunctionExpression<>(uriFunction), asyncRestTemplate);
|
||||
public static <P> ReactiveHttpMessageHandlerSpec outboundReactiveGateway(Function<Message<P>, ?> uriFunction,
|
||||
WebClient webClient) {
|
||||
return outboundReactiveGateway(new FunctionExpression<>(uriFunction), webClient);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@link AsyncHttpMessageHandlerSpec} builder for request-reply gateway
|
||||
* Create an {@link ReactiveHttpMessageHandlerSpec} builder for request-reply gateway
|
||||
* based on provided SpEL {@link Expression} to evaluate target {@code uri}
|
||||
* against request message and {@link AsyncRestTemplate} for HTTP exchanges.
|
||||
* against request message and {@link WebClient} for HTTP exchanges.
|
||||
* @param uriExpression the SpEL {@link Expression} to evaluate {@code uri} at runtime.
|
||||
* @param asyncRestTemplate {@link AsyncRestTemplate} to use.
|
||||
* @return the AsyncHttpMessageHandlerSpec instance
|
||||
* @param webClient {@link WebClient} to use.
|
||||
* @return the ReactiveHttpMessageHandlerSpec instance
|
||||
*/
|
||||
public static AsyncHttpMessageHandlerSpec outboundAsyncGateway(Expression uriExpression, AsyncRestTemplate asyncRestTemplate) {
|
||||
return new AsyncHttpMessageHandlerSpec(uriExpression, asyncRestTemplate);
|
||||
public static ReactiveHttpMessageHandlerSpec outboundReactiveGateway(Expression uriExpression,
|
||||
WebClient webClient) {
|
||||
return new ReactiveHttpMessageHandlerSpec(uriExpression, webClient);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,13 +17,16 @@
|
||||
package org.springframework.integration.http.dsl;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.common.LiteralExpression;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.integration.expression.ValueExpression;
|
||||
import org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.client.ResponseErrorHandler;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
@@ -66,8 +69,33 @@ public class HttpMessageHandlerSpec
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link ResponseErrorHandler} for the underlying {@link RestTemplate}.
|
||||
* @param errorHandler The error handler.
|
||||
* @return the spec
|
||||
*/
|
||||
public HttpMessageHandlerSpec errorHandler(ResponseErrorHandler errorHandler) {
|
||||
Assert.isTrue(this.isClientSet(),
|
||||
"the 'errorHandler' must be specified on the provided 'restTemplate'");
|
||||
this.target.setErrorHandler(errorHandler);
|
||||
return _this();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a list of {@link HttpMessageConverter}s to be used by the underlying {@link RestTemplate}.
|
||||
* Converters configured via this method will override the default converters.
|
||||
* @param messageConverters The message converters.
|
||||
* @return the spec
|
||||
*/
|
||||
public HttpMessageHandlerSpec messageConverters(HttpMessageConverter<?>... messageConverters) {
|
||||
Assert.isTrue(!isClientSet(), "the 'messageConverters' must be specified on the provided restTemplate");
|
||||
this.target.setMessageConverters(Arrays.asList(messageConverters));
|
||||
return _this();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isRestTemplateSet() {
|
||||
protected boolean isClientSet() {
|
||||
return this.restTemplate != null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 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.http.dsl;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.common.LiteralExpression;
|
||||
import org.springframework.integration.expression.ValueExpression;
|
||||
import org.springframework.integration.http.outbound.ReactiveHttpRequestExecutingMessageHandler;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
/**
|
||||
* The {@link BaseHttpMessageHandlerSpec} implementation for the {@link ReactiveHttpRequestExecutingMessageHandler}.
|
||||
*
|
||||
* @author Shiliang Li
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 5.0
|
||||
*
|
||||
* @see ReactiveHttpRequestExecutingMessageHandler
|
||||
*/
|
||||
public class ReactiveHttpMessageHandlerSpec
|
||||
extends BaseHttpMessageHandlerSpec<ReactiveHttpMessageHandlerSpec, ReactiveHttpRequestExecutingMessageHandler> {
|
||||
|
||||
private final WebClient webClient;
|
||||
|
||||
ReactiveHttpMessageHandlerSpec(URI uri, WebClient webClient) {
|
||||
this(new ValueExpression<>(uri), webClient);
|
||||
}
|
||||
|
||||
ReactiveHttpMessageHandlerSpec(String uri, WebClient webClient) {
|
||||
this(new LiteralExpression(uri), webClient);
|
||||
}
|
||||
|
||||
ReactiveHttpMessageHandlerSpec(Expression uriExpression, WebClient webClient) {
|
||||
super(new ReactiveHttpRequestExecutingMessageHandler(uriExpression, webClient));
|
||||
this.webClient = webClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isClientSet() {
|
||||
return this.webClient != null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,7 +36,6 @@ import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.integration.expression.ExpressionEvalMap;
|
||||
import org.springframework.integration.expression.ExpressionUtils;
|
||||
import org.springframework.integration.expression.ValueExpression;
|
||||
@@ -44,6 +43,7 @@ import org.springframework.integration.handler.AbstractReplyProducingMessageHand
|
||||
import org.springframework.integration.http.support.DefaultHttpHeaderMapper;
|
||||
import org.springframework.integration.mapping.HeaderMapper;
|
||||
import org.springframework.integration.support.AbstractIntegrationMessageBuilder;
|
||||
import org.springframework.integration.support.MessageBuilderFactory;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageHandlingException;
|
||||
import org.springframework.messaging.MessagingException;
|
||||
@@ -53,7 +53,6 @@ import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.client.ResponseErrorHandler;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.util.UriComponents;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
@@ -163,14 +162,13 @@ public abstract class AbstractHttpRequestExecutingMessageHandler extends Abstrac
|
||||
* @return whether a reply Message is expected.
|
||||
* @see AbstractHttpRequestExecutingMessageHandler#setExpectReply(boolean)
|
||||
*/
|
||||
public boolean getExpectReply() {
|
||||
public boolean isExpectReply() {
|
||||
return this.expectReply;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether a reply Message is expected. If not, this handler will simply return null for a
|
||||
* successful response or throw an Exception for a non-successful response. The default is true.
|
||||
*
|
||||
* @param expectReply true if a reply is expected.
|
||||
*/
|
||||
public void setExpectReply(boolean expectReply) {
|
||||
@@ -204,21 +202,6 @@ public abstract class AbstractHttpRequestExecutingMessageHandler extends Abstrac
|
||||
this.expectedResponseTypeExpression = expectedResponseTypeExpression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link ResponseErrorHandler} for the underlying implementation.
|
||||
*
|
||||
* @param errorHandler The error handler.
|
||||
*/
|
||||
public abstract void setErrorHandler(ResponseErrorHandler errorHandler);
|
||||
|
||||
/**
|
||||
* Set a list of {@link HttpMessageConverter}s to be used by the underlying implementation.
|
||||
* Converters configured via this method will override the default converters.
|
||||
*
|
||||
* @param messageConverters The message converters.
|
||||
*/
|
||||
public abstract void setMessageConverters(List<HttpMessageConverter<?>> messageConverters);
|
||||
|
||||
/**
|
||||
* Set the {@link HeaderMapper} to use when mapping between HTTP headers and MessageHeaders.
|
||||
* @param headerMapper The header mapper.
|
||||
@@ -228,8 +211,6 @@ public abstract class AbstractHttpRequestExecutingMessageHandler extends Abstrac
|
||||
this.headerMapper = headerMapper;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set the Map of URI variable expressions to evaluate against the outbound message
|
||||
* when replacing the variable placeholders in a URI template.
|
||||
@@ -280,16 +261,17 @@ public abstract class AbstractHttpRequestExecutingMessageHandler extends Abstrac
|
||||
try {
|
||||
HttpMethod httpMethod = this.determineHttpMethod(requestMessage);
|
||||
|
||||
if (!this.shouldIncludeRequestBody(httpMethod) && this.extractPayloadExplicitlySet) {
|
||||
if (!shouldIncludeRequestBody(httpMethod) && this.extractPayloadExplicitlySet) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("The 'extractPayload' attribute has no relevance for the current request since the HTTP Method is '" +
|
||||
httpMethod + "', and no request body will be sent for that method.");
|
||||
logger.warn("The 'extractPayload' attribute has no relevance for the current request " +
|
||||
"since the HTTP Method is '" + httpMethod +
|
||||
"', and no request body will be sent for that method.");
|
||||
}
|
||||
}
|
||||
|
||||
Object expectedResponseType = this.determineExpectedResponseType(requestMessage);
|
||||
Object expectedResponseType = determineExpectedResponseType(requestMessage);
|
||||
|
||||
HttpEntity<?> httpRequest = this.generateHttpRequest(requestMessage, httpMethod);
|
||||
HttpEntity<?> httpRequest = generateHttpRequest(requestMessage, httpMethod);
|
||||
Map<String, ?> uriVariables = this.determineUriVariables(requestMessage);
|
||||
UriComponentsBuilder uriComponentsBuilder = uri instanceof String
|
||||
? UriComponentsBuilder.fromUriString((String) uri)
|
||||
@@ -297,7 +279,7 @@ public abstract class AbstractHttpRequestExecutingMessageHandler extends Abstrac
|
||||
UriComponents uriComponents = uriComponentsBuilder.buildAndExpand(uriVariables);
|
||||
realUri = this.encodeUri ? uriComponents.toUri() : new URI(uriComponents.toUriString());
|
||||
|
||||
return this.exchange(realUri, httpMethod, httpRequest, expectedResponseType);
|
||||
return exchange(realUri, httpMethod, httpRequest, expectedResponseType, requestMessage);
|
||||
}
|
||||
catch (MessagingException e) {
|
||||
throw e;
|
||||
@@ -308,7 +290,8 @@ public abstract class AbstractHttpRequestExecutingMessageHandler extends Abstrac
|
||||
}
|
||||
}
|
||||
|
||||
abstract protected Object exchange(URI realUri, HttpMethod httpMethod, HttpEntity<?> httpRequest, Object expectedResponseType);
|
||||
protected abstract Object exchange(URI realUri, HttpMethod httpMethod, HttpEntity<?> httpRequest,
|
||||
Object expectedResponseType, Message<?> requestMessage);
|
||||
|
||||
protected Object getReply(ResponseEntity<?> httpResponse) {
|
||||
if (this.expectReply) {
|
||||
@@ -317,17 +300,21 @@ public abstract class AbstractHttpRequestExecutingMessageHandler extends Abstrac
|
||||
if (this.transferCookies) {
|
||||
this.doConvertSetCookie(headers);
|
||||
}
|
||||
|
||||
AbstractIntegrationMessageBuilder<?> replyBuilder = null;
|
||||
MessageBuilderFactory messageBuilderFactory = getMessageBuilderFactory();
|
||||
if (httpResponse.hasBody()) {
|
||||
Object responseBody = httpResponse.getBody();
|
||||
replyBuilder = (responseBody instanceof Message<?>) ?
|
||||
this.getMessageBuilderFactory().fromMessage((Message<?>) responseBody) : this.getMessageBuilderFactory().withPayload(responseBody);
|
||||
replyBuilder = (responseBody instanceof Message<?>)
|
||||
? messageBuilderFactory.fromMessage((Message<?>) responseBody)
|
||||
: messageBuilderFactory.withPayload(responseBody);
|
||||
|
||||
}
|
||||
else {
|
||||
replyBuilder = this.getMessageBuilderFactory().withPayload(httpResponse);
|
||||
replyBuilder = messageBuilderFactory.withPayload(httpResponse);
|
||||
}
|
||||
replyBuilder.setHeader(org.springframework.integration.http.HttpHeaders.STATUS_CODE, httpResponse.getStatusCode());
|
||||
replyBuilder.setHeader(org.springframework.integration.http.HttpHeaders.STATUS_CODE,
|
||||
httpResponse.getStatusCode());
|
||||
return replyBuilder.copyHeaders(headers);
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -1,162 +0,0 @@
|
||||
/*
|
||||
* Copyright 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.http.outbound;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.common.LiteralExpression;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.client.AsyncClientHttpRequestFactory;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.integration.expression.ValueExpression;
|
||||
import org.springframework.messaging.MessageHandler;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.SettableListenableFuture;
|
||||
import org.springframework.web.client.AsyncRestTemplate;
|
||||
import org.springframework.web.client.ResponseErrorHandler;
|
||||
|
||||
/**
|
||||
* A {@link MessageHandler} implementation that executes HTTP requests by delegating
|
||||
* to an {@link AsyncRestTemplate} instance.
|
||||
* @see HttpRequestExecutingMessageHandler
|
||||
* @author Shiliang Li
|
||||
* @since 5.0
|
||||
*/
|
||||
public class AsyncHttpRequestExecutingMessageHandler extends AbstractHttpRequestExecutingMessageHandler {
|
||||
|
||||
private final AsyncRestTemplate asyncRestTemplate;
|
||||
|
||||
/**
|
||||
* Create a handler that will send requests to the provided URI.
|
||||
*
|
||||
* @param uri The URI.
|
||||
*/
|
||||
public AsyncHttpRequestExecutingMessageHandler(URI uri) {
|
||||
this(new ValueExpression<>(uri));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a handler that will send requests to the provided URI.
|
||||
*
|
||||
* @param uri The URI.
|
||||
*/
|
||||
public AsyncHttpRequestExecutingMessageHandler(String uri) {
|
||||
this(uri, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a handler that will send requests to the provided URI Expression.
|
||||
*
|
||||
* @param uriExpression The URI expression.
|
||||
*/
|
||||
public AsyncHttpRequestExecutingMessageHandler(Expression uriExpression) {
|
||||
this(uriExpression, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a handler that will send requests to the provided URI using a provided AsyncRestTemplate
|
||||
* @param uri The URI.
|
||||
* @param asyncRestTemplate The rest template.
|
||||
*/
|
||||
public AsyncHttpRequestExecutingMessageHandler(String uri, AsyncRestTemplate asyncRestTemplate) {
|
||||
this(new LiteralExpression(uri), asyncRestTemplate);
|
||||
/*
|
||||
* We'd prefer to do this assertion first, but the compiler doesn't allow it. However,
|
||||
* it's safe because the literal expression simply wraps the String variable, even
|
||||
* when null.
|
||||
*/
|
||||
Assert.hasText(uri, "URI is required");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a handler that will send requests to the provided URI using a provided AsyncRestTemplate
|
||||
* @param uriExpression A SpEL Expression that can be resolved against the message object and
|
||||
* {@link BeanFactory}.
|
||||
* @param asyncRestTemplate The rest template.
|
||||
*/
|
||||
public AsyncHttpRequestExecutingMessageHandler(Expression uriExpression, AsyncRestTemplate asyncRestTemplate) {
|
||||
super(uriExpression);
|
||||
this.asyncRestTemplate = (asyncRestTemplate == null ? new AsyncRestTemplate() : asyncRestTemplate);
|
||||
this.setAsync(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getComponentType() {
|
||||
return (this.getExpectReply() ? "http:outbound-async-gateway" : "http:outbound-async-channel-adapter");
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link ResponseErrorHandler} for the underlying {@link AsyncRestTemplate}.
|
||||
*
|
||||
* @param errorHandler The error handler.
|
||||
*
|
||||
* @see AsyncRestTemplate#setErrorHandler(ResponseErrorHandler)
|
||||
*/
|
||||
@Override
|
||||
public void setErrorHandler(ResponseErrorHandler errorHandler) {
|
||||
this.asyncRestTemplate.setErrorHandler(errorHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a list of {@link HttpMessageConverter}s to be used by the underlying {@link AsyncRestTemplate}.
|
||||
* Converters configured via this method will override the default converters.
|
||||
*
|
||||
* @param messageConverters The message converters.
|
||||
*
|
||||
* @see AsyncRestTemplate#setMessageConverters(java.util.List)
|
||||
*/
|
||||
@Override
|
||||
public void setMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
|
||||
this.asyncRestTemplate.setMessageConverters(messageConverters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link AsyncClientHttpRequestFactory} for the underlying {@link AsyncRestTemplate}.
|
||||
*
|
||||
* @param asyncRequestFactory The request factory.
|
||||
*
|
||||
* @see AsyncRestTemplate#setAsyncRequestFactory(AsyncClientHttpRequestFactory)
|
||||
*/
|
||||
public void setAsyncRequestFactory(AsyncClientHttpRequestFactory asyncRequestFactory) {
|
||||
this.asyncRestTemplate.setAsyncRequestFactory(asyncRequestFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object exchange(URI uri, HttpMethod httpMethod, HttpEntity<?> httpRequest, Object expectedResponseType) {
|
||||
SettableListenableFuture<Object> replyMessageFuture = new SettableListenableFuture<>();
|
||||
ListenableFuture<? extends ResponseEntity<?>> responseFuture;
|
||||
if (expectedResponseType instanceof ParameterizedTypeReference<?>) {
|
||||
responseFuture = this.asyncRestTemplate.exchange(uri, httpMethod, httpRequest, (ParameterizedTypeReference<?>) expectedResponseType);
|
||||
}
|
||||
else {
|
||||
responseFuture = this.asyncRestTemplate.exchange(uri, httpMethod, httpRequest, (Class<?>) expectedResponseType);
|
||||
}
|
||||
|
||||
responseFuture.addCallback(
|
||||
result -> replyMessageFuture.set(getReply(result)),
|
||||
replyMessageFuture::setException);
|
||||
|
||||
return replyMessageFuture;
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.integration.expression.ValueExpression;
|
||||
import org.springframework.integration.mapping.HeaderMapper;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageHandler;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.client.ResponseErrorHandler;
|
||||
@@ -53,6 +54,7 @@ import org.springframework.web.client.RestTemplate;
|
||||
* @author Artem Bilan
|
||||
* @author Wallace Wadge
|
||||
* @author Shiliang Li
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
public class HttpRequestExecutingMessageHandler extends AbstractHttpRequestExecutingMessageHandler {
|
||||
@@ -113,17 +115,14 @@ public class HttpRequestExecutingMessageHandler extends AbstractHttpRequestExecu
|
||||
|
||||
@Override
|
||||
public String getComponentType() {
|
||||
return (this.getExpectReply() ? "http:outbound-gateway" : "http:outbound-channel-adapter");
|
||||
return (this.isExpectReply() ? "http:outbound-gateway" : "http:outbound-channel-adapter");
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link ResponseErrorHandler} for the underlying {@link RestTemplate}.
|
||||
*
|
||||
* @param errorHandler The error handler.
|
||||
*
|
||||
* @see RestTemplate#setErrorHandler(ResponseErrorHandler)
|
||||
*/
|
||||
@Override
|
||||
public void setErrorHandler(ResponseErrorHandler errorHandler) {
|
||||
this.restTemplate.setErrorHandler(errorHandler);
|
||||
}
|
||||
@@ -131,12 +130,9 @@ public class HttpRequestExecutingMessageHandler extends AbstractHttpRequestExecu
|
||||
/**
|
||||
* Set a list of {@link HttpMessageConverter}s to be used by the underlying {@link RestTemplate}.
|
||||
* Converters configured via this method will override the default converters.
|
||||
*
|
||||
* @param messageConverters The message converters.
|
||||
*
|
||||
* @see RestTemplate#setMessageConverters(java.util.List)
|
||||
*/
|
||||
@Override
|
||||
public void setMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
|
||||
this.restTemplate.setMessageConverters(messageConverters);
|
||||
}
|
||||
@@ -153,10 +149,12 @@ public class HttpRequestExecutingMessageHandler extends AbstractHttpRequestExecu
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object exchange(URI uri, HttpMethod httpMethod, HttpEntity<?> httpRequest, Object expectedResponseType) {
|
||||
protected Object exchange(URI uri, HttpMethod httpMethod, HttpEntity<?> httpRequest, Object expectedResponseType,
|
||||
Message<?> requestMessage) {
|
||||
ResponseEntity<?> httpResponse;
|
||||
if (expectedResponseType instanceof ParameterizedTypeReference<?>) {
|
||||
httpResponse = this.restTemplate.exchange(uri, httpMethod, httpRequest, (ParameterizedTypeReference<?>) expectedResponseType);
|
||||
httpResponse = this.restTemplate.exchange(uri, httpMethod, httpRequest,
|
||||
(ParameterizedTypeReference<?>) expectedResponseType);
|
||||
}
|
||||
else {
|
||||
httpResponse = this.restTemplate.exchange(uri, httpMethod, httpRequest, (Class<?>) expectedResponseType);
|
||||
|
||||
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright 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.http.outbound;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.common.LiteralExpression;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.integration.expression.ValueExpression;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageHandler;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.reactive.function.BodyExtractors;
|
||||
import org.springframework.web.reactive.function.BodyInserters;
|
||||
import org.springframework.web.reactive.function.client.ClientResponse;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import org.springframework.web.reactive.function.client.WebClientException;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* A {@link MessageHandler} implementation that executes HTTP requests by delegating
|
||||
* to a Reactive {@link WebClient} instance.
|
||||
*
|
||||
* @author Shiliang Li
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 5.0
|
||||
*
|
||||
* @see HttpRequestExecutingMessageHandler
|
||||
*/
|
||||
public class ReactiveHttpRequestExecutingMessageHandler extends AbstractHttpRequestExecutingMessageHandler {
|
||||
|
||||
private final WebClient webClient;
|
||||
|
||||
/**
|
||||
* Create a handler that will send requests to the provided URI.
|
||||
* @param uri The URI.
|
||||
*/
|
||||
public ReactiveHttpRequestExecutingMessageHandler(URI uri) {
|
||||
this(new ValueExpression<>(uri));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a handler that will send requests to the provided URI.
|
||||
* @param uri The URI.
|
||||
*/
|
||||
public ReactiveHttpRequestExecutingMessageHandler(String uri) {
|
||||
this(uri, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a handler that will send requests to the provided URI Expression.
|
||||
* @param uriExpression The URI expression.
|
||||
*/
|
||||
public ReactiveHttpRequestExecutingMessageHandler(Expression uriExpression) {
|
||||
this(uriExpression, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a handler that will send requests to the provided URI using a provided WebClient.
|
||||
* @param uri The URI.
|
||||
* @param webClient The WebClient to use.
|
||||
*/
|
||||
public ReactiveHttpRequestExecutingMessageHandler(String uri, WebClient webClient) {
|
||||
this(new LiteralExpression(uri), webClient);
|
||||
/*
|
||||
* We'd prefer to do this assertion first, but the compiler doesn't allow it. However,
|
||||
* it's safe because the literal expression simply wraps the String variable, even
|
||||
* when null.
|
||||
*/
|
||||
Assert.hasText(uri, "URI is required");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a handler that will send requests to the provided URI using a provided WebClient.
|
||||
* @param uriExpression A SpEL Expression that can be resolved against the message object and
|
||||
* {@link BeanFactory}.
|
||||
* @param webClient The WebClient to use.
|
||||
*/
|
||||
public ReactiveHttpRequestExecutingMessageHandler(Expression uriExpression, WebClient webClient) {
|
||||
super(uriExpression);
|
||||
this.webClient = (webClient == null ? WebClient.create() : webClient);
|
||||
this.setAsync(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getComponentType() {
|
||||
return (isExpectReply() ? "http:outbound-reactive-gateway" : "http:outbound-reactive-channel-adapter");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object exchange(URI uri, HttpMethod httpMethod, HttpEntity<?> httpRequest, Object expectedResponseType,
|
||||
Message<?> requestMessage) {
|
||||
WebClient.UriSpec uriSpec;
|
||||
|
||||
// TODO use WebClient.method(HttpMethod) in the future version
|
||||
|
||||
switch (httpMethod) {
|
||||
case GET:
|
||||
uriSpec = this.webClient.get();
|
||||
break;
|
||||
case HEAD:
|
||||
uriSpec = this.webClient.head();
|
||||
break;
|
||||
case POST:
|
||||
uriSpec = this.webClient.post();
|
||||
break;
|
||||
case PUT:
|
||||
uriSpec = this.webClient.put();
|
||||
break;
|
||||
case PATCH:
|
||||
uriSpec = this.webClient.patch();
|
||||
break;
|
||||
case DELETE:
|
||||
uriSpec = this.webClient.delete();
|
||||
break;
|
||||
case OPTIONS:
|
||||
uriSpec = this.webClient.options();
|
||||
break;
|
||||
case TRACE:
|
||||
throw new UnsupportedOperationException("WebClient doesn't support the TRACE HTTP method");
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unsupported HTTP method");
|
||||
}
|
||||
|
||||
WebClient.HeaderSpec spec = uriSpec.uri(uri)
|
||||
.headers(httpRequest.getHeaders());
|
||||
|
||||
Mono<ClientResponse> responseMono;
|
||||
if (httpRequest.hasBody()) {
|
||||
responseMono = spec.exchange(BodyInserters.fromObject(httpRequest.getBody()));
|
||||
}
|
||||
else {
|
||||
responseMono = spec.exchange();
|
||||
}
|
||||
|
||||
if (isExpectReply()) {
|
||||
|
||||
ResolvableType responseType;
|
||||
|
||||
if (expectedResponseType instanceof ParameterizedTypeReference<?>) {
|
||||
responseType = ResolvableType.forType(((ParameterizedTypeReference<?>) expectedResponseType).getType());
|
||||
}
|
||||
else if (expectedResponseType != null) {
|
||||
responseType = ResolvableType.forClass((Class<?>) expectedResponseType);
|
||||
}
|
||||
else {
|
||||
responseType = null;
|
||||
}
|
||||
|
||||
return responseMono
|
||||
.map(response ->
|
||||
new ResponseEntity<>(responseType != null
|
||||
? response.body(BodyExtractors.toMono(responseType)).block()
|
||||
: null,
|
||||
response.headers().asHttpHeaders(),
|
||||
response.statusCode()))
|
||||
.map(this::getReply);
|
||||
}
|
||||
else {
|
||||
responseMono
|
||||
.doOnNext(response -> {
|
||||
HttpStatus httpStatus = response.statusCode();
|
||||
if (httpStatus.is4xxClientError() || httpStatus.is5xxServerError()) {
|
||||
throw new WebClientException(
|
||||
"ClientResponse has erroneous status code: " + httpStatus.value() +
|
||||
" " + httpStatus.getReasonPhrase());
|
||||
}
|
||||
})
|
||||
.subscribe(v -> { }, ex -> sendErrorMessage(requestMessage, ex));
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -401,11 +401,11 @@
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="outbound-async-channel-adapter">
|
||||
<xsd:element name="outbound-reactive-channel-adapter">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Configures a Consumer Endpoint for the
|
||||
'org.springframework.integration.http.outbound.AsyncHttpRequestExecutingMessageHandler'
|
||||
'org.springframework.integration.http.outbound.ReactiveHttpRequestExecutingMessageHandler'
|
||||
with 'expectReply = false' that sends HTTP requests based on incoming messages.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
@@ -424,7 +424,19 @@
|
||||
</xsd:choice>
|
||||
<xsd:attributeGroup ref="integration:channelAdapterAttributes"/>
|
||||
<xsd:attributeGroup ref="httpOutboundCommonAttributes"/>
|
||||
<xsd:attributeGroup ref="asyncHttpOutboundCommonAttributes"/>
|
||||
<xsd:attribute name="web-client" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.web.reactive.function.client.WebClient" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
<xsd:documentation>
|
||||
A reference to an org.springframework.web.reactive.function.client.WebClient bean
|
||||
which is used to send to send the HTTP Requests reactive manner.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="extract-payload" type="xsd:string" default="true">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
@@ -532,11 +544,11 @@
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="outbound-async-gateway">
|
||||
<xsd:element name="outbound-reactive-gateway">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Configures a Consumer Endpoint for the
|
||||
'org.springframework.integration.http.outbound.AsyncHttpRequestExecutingMessageHandler'
|
||||
'org.springframework.integration.http.outbound.ReactiveHttpRequestExecutingMessageHandler'
|
||||
that sends HTTP requests based on incoming messages and expects HTTP responses.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
@@ -551,8 +563,10 @@
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="transactional" type="integration:transactionalType" minOccurs="0" maxOccurs="1" />
|
||||
<xsd:element name="request-handler-advice-chain" type="integration:handlerAdviceChainType" minOccurs="0" maxOccurs="1" />
|
||||
<xsd:element name="transactional" type="integration:transactionalType" minOccurs="0"
|
||||
maxOccurs="1" />
|
||||
<xsd:element name="request-handler-advice-chain" type="integration:handlerAdviceChainType"
|
||||
minOccurs="0" maxOccurs="1" />
|
||||
<xsd:element ref="integration:poller" minOccurs="0" maxOccurs="1"/>
|
||||
</xsd:choice>
|
||||
<xsd:attribute name="request-channel" type="xsd:string">
|
||||
@@ -620,7 +634,19 @@
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attributeGroup ref="httpOutboundCommonAttributes"/>
|
||||
<xsd:attributeGroup ref="asyncHttpOutboundCommonAttributes"/>
|
||||
<xsd:attribute name="web-client" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.web.reactive.function.client.WebClient" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
<xsd:documentation>
|
||||
A reference to an org.springframework.web.reactive.function.client.WebClient bean
|
||||
which is used to send to send the HTTP Requests reactive manner.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
@@ -859,33 +885,6 @@
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:attributeGroup name="asyncHttpOutboundCommonAttributes">
|
||||
<xsd:attribute name="async-rest-template" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.web.client.AsyncRestTemplate" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
<xsd:documentation>
|
||||
The reference to org.springframework.web.client.AsyncRestTemplate bean to send the HTTP Request.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="async-request-factory" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Reference to a AsyncClientHttpRequestFactory to be used by the underlying RestTemplate.
|
||||
]]></xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.http.client.AsyncClientHttpRequestFactory" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:attributeGroup>
|
||||
|
||||
<xsd:attributeGroup name="syncHttpOutboundCommonAttributes">
|
||||
<xsd:attribute name="rest-template" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
@@ -911,6 +910,27 @@
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="error-handler" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Reference to a ResponseErrorHandler to be used by the underlying RestTemplate.
|
||||
</xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.web.client.ResponseErrorHandler" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="message-converters" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Provide a reference to a list of HttpMessageConverter instances. If specified,
|
||||
these converters will replace all of the default converters that would normally
|
||||
be present on the underlying RestTemplate.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:attributeGroup>
|
||||
|
||||
<xsd:attributeGroup name="httpOutboundCommonAttributes">
|
||||
@@ -992,14 +1012,6 @@
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="message-converters" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Provide a reference to a list of HttpMessageConverter instances. If specified, these converters will replace
|
||||
all of the default converters that would normally be present on the underlying RestTemplate.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="header-mapper" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
@@ -1024,18 +1036,6 @@
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="error-handler" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Reference to a ResponseErrorHandler to be used by the underlying RestTemplate.
|
||||
]]></xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.web.client.ResponseErrorHandler" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="order" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans:beans
|
||||
xmlns="http://www.springframework.org/schema/integration/http"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:si="http://www.springframework.org/schema/integration"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/integration/http http://www.springframework.org/schema/integration/http/spring-integration-http.xsd
|
||||
xmlns="http://www.springframework.org/schema/integration/http"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:si="http://www.springframework.org/schema/integration"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/integration/http http://www.springframework.org/schema/integration/http/spring-integration-http.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
|
||||
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
|
||||
@@ -14,29 +14,32 @@
|
||||
|
||||
<outbound-channel-adapter id="minimalConfig" url="http://localhost/test1" channel="requests"/>
|
||||
|
||||
<outbound-channel-adapter id="restTemplateConfig" url="http://localhost/test1" channel="requests" rest-template="customRestTemplate"/>
|
||||
<outbound-channel-adapter id="restTemplateConfig" url="http://localhost/test1" channel="requests"
|
||||
rest-template="customRestTemplate"/>
|
||||
|
||||
<outbound-async-channel-adapter id="asyncMinimalConfig" url="http://localhost/test1" channel="requests" />
|
||||
<outbound-reactive-channel-adapter id="reactiveMinimalConfig" url="http://localhost/test1" channel="requests"/>
|
||||
|
||||
<outbound-async-channel-adapter id="asyncRestTemplateConfig" url="http://localhost/test1" channel="requests" async-rest-template="asyncRestTemplate" />
|
||||
<outbound-reactive-channel-adapter id="reactiveWebClientConfig" url="http://localhost/test1" channel="requests"
|
||||
web-client="webClient"/>
|
||||
|
||||
<beans:bean id="customRestTemplate" class="org.springframework.web.client.RestTemplate"/>
|
||||
|
||||
<beans:bean id="asyncRestTemplate" class="org.springframework.web.client.AsyncRestTemplate"/>
|
||||
<beans:bean id="webClient" class="org.springframework.web.reactive.function.client.WebClient"
|
||||
factory-method="create"/>
|
||||
|
||||
<outbound-channel-adapter id="fullConfig"
|
||||
url="http://localhost/test2/{foo}"
|
||||
http-method="GET"
|
||||
channel="requests"
|
||||
charset="UTF-8"
|
||||
message-converters="converterList"
|
||||
extract-payload="false"
|
||||
expected-response-type="java.lang.Boolean"
|
||||
mapped-request-headers="requestHeader1, requestHeader2"
|
||||
request-factory="testRequestFactory"
|
||||
error-handler="testErrorHandler"
|
||||
order="77"
|
||||
auto-startup="false">
|
||||
url="http://localhost/test2/{foo}"
|
||||
http-method="GET"
|
||||
channel="requests"
|
||||
charset="UTF-8"
|
||||
message-converters="converterList"
|
||||
extract-payload="false"
|
||||
expected-response-type="java.lang.Boolean"
|
||||
mapped-request-headers="requestHeader1, requestHeader2"
|
||||
request-factory="testRequestFactory"
|
||||
error-handler="testErrorHandler"
|
||||
order="77"
|
||||
auto-startup="false">
|
||||
<uri-variable name="foo" expression="headers.bar"/>
|
||||
|
||||
</outbound-channel-adapter>
|
||||
@@ -47,21 +50,22 @@
|
||||
</util:map>
|
||||
|
||||
<outbound-channel-adapter id="withUrlAndTemplate"
|
||||
url="http://localhost/test1" channel="requests"
|
||||
uri-variables-expression="@uriVariables"
|
||||
rest-template="customRestTemplate"/>
|
||||
url="http://localhost/test1" channel="requests"
|
||||
uri-variables-expression="@uriVariables"
|
||||
rest-template="customRestTemplate"/>
|
||||
|
||||
<outbound-channel-adapter id="withUrlExpression" url-expression="'http://localhost/test1'" channel="requests"/>
|
||||
|
||||
<outbound-channel-adapter id="withAdvice" url-expression="'http://localhost/test1'" channel="requests">
|
||||
<request-handler-advice-chain>
|
||||
<beans:bean class="org.springframework.integration.http.config.HttpOutboundChannelAdapterParserTests$FooAdvice" />
|
||||
<beans:bean
|
||||
class="org.springframework.integration.http.config.HttpOutboundChannelAdapterParserTests$FooAdvice"/>
|
||||
</request-handler-advice-chain>
|
||||
</outbound-channel-adapter>
|
||||
|
||||
<outbound-channel-adapter id="withUrlExpressionAndTemplate"
|
||||
url-expression="'http://localhost/test1'" channel="requests"
|
||||
rest-template="customRestTemplate"/>
|
||||
url-expression="'http://localhost/test1'" channel="requests"
|
||||
rest-template="customRestTemplate"/>
|
||||
|
||||
<si:channel id="queueChannel">
|
||||
<si:queue capacity="10"/>
|
||||
@@ -102,7 +106,8 @@
|
||||
|
||||
<beans:bean id="testAsyncRequestFactory" class="org.springframework.http.client.SimpleClientHttpRequestFactory"/>
|
||||
|
||||
<beans:bean id="testErrorHandler" class="org.springframework.integration.http.config.HttpOutboundChannelAdapterParserTests$StubErrorHandler"/>
|
||||
<beans:bean id="testErrorHandler"
|
||||
class="org.springframework.integration.http.config.HttpOutboundChannelAdapterParserTests$StubErrorHandler"/>
|
||||
|
||||
<util:list id="converterList">
|
||||
<beans:bean class="org.springframework.integration.http.config.StubHttpMessageConverter"/>
|
||||
|
||||
@@ -41,14 +41,12 @@ import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.standard.SpelExpression;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.client.AsyncClientHttpRequestFactory;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
import org.springframework.integration.endpoint.AbstractEndpoint;
|
||||
import org.springframework.integration.endpoint.PollingConsumer;
|
||||
import org.springframework.integration.handler.advice.AbstractRequestHandlerAdvice;
|
||||
import org.springframework.integration.http.outbound.AsyncHttpRequestExecutingMessageHandler;
|
||||
import org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.messaging.Message;
|
||||
@@ -58,9 +56,9 @@ import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.web.client.AsyncRestTemplate;
|
||||
import org.springframework.web.client.ResponseErrorHandler;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
@@ -75,40 +73,51 @@ import org.springframework.web.client.RestTemplate;
|
||||
@DirtiesContext
|
||||
public class HttpOutboundChannelAdapterParserTests {
|
||||
|
||||
@Autowired @Qualifier("minimalConfig")
|
||||
@Autowired
|
||||
@Qualifier("minimalConfig")
|
||||
private AbstractEndpoint minimalConfig;
|
||||
|
||||
@Autowired @Qualifier("fullConfig")
|
||||
@Autowired
|
||||
@Qualifier("fullConfig")
|
||||
private AbstractEndpoint fullConfig;
|
||||
|
||||
@Autowired @Qualifier("restTemplateConfig")
|
||||
@Autowired
|
||||
@Qualifier("restTemplateConfig")
|
||||
private AbstractEndpoint restTemplateConfig;
|
||||
|
||||
@Autowired @Qualifier("asyncMinimalConfig")
|
||||
private AbstractEndpoint asyncMinimalConfig;
|
||||
@Autowired
|
||||
@Qualifier("reactiveMinimalConfig")
|
||||
private AbstractEndpoint reactiveMinimalConfig;
|
||||
|
||||
@Autowired @Qualifier("asyncRestTemplateConfig")
|
||||
private AbstractEndpoint asyncRestTemplateConfig;
|
||||
@Autowired
|
||||
@Qualifier("reactiveWebClientConfig")
|
||||
private AbstractEndpoint reactiveWebClientConfig;
|
||||
|
||||
@Autowired @Qualifier("customRestTemplate")
|
||||
@Autowired
|
||||
@Qualifier("customRestTemplate")
|
||||
private RestTemplate customRestTemplate;
|
||||
|
||||
@Autowired @Qualifier("asyncRestTemplate")
|
||||
private AsyncRestTemplate asyncRestTemplate;
|
||||
@Autowired
|
||||
private WebClient webClient;
|
||||
|
||||
@Autowired @Qualifier("withUrlAndTemplate")
|
||||
@Autowired
|
||||
@Qualifier("withUrlAndTemplate")
|
||||
private AbstractEndpoint withUrlAndTemplate;
|
||||
|
||||
@Autowired @Qualifier("withUrlExpression")
|
||||
@Autowired
|
||||
@Qualifier("withUrlExpression")
|
||||
private AbstractEndpoint withUrlExpression;
|
||||
|
||||
@Autowired @Qualifier("withAdvice")
|
||||
@Autowired
|
||||
@Qualifier("withAdvice")
|
||||
private AbstractEndpoint withAdvice;
|
||||
|
||||
@Autowired @Qualifier("withUrlExpressionAndTemplate")
|
||||
@Autowired
|
||||
@Qualifier("withUrlExpressionAndTemplate")
|
||||
private AbstractEndpoint withUrlExpressionAndTemplate;
|
||||
|
||||
@Autowired @Qualifier("withPoller1")
|
||||
@Autowired
|
||||
@Qualifier("withPoller1")
|
||||
private AbstractEndpoint withPoller1;
|
||||
|
||||
@Autowired
|
||||
@@ -120,7 +129,7 @@ public class HttpOutboundChannelAdapterParserTests {
|
||||
public void minimalConfig() {
|
||||
DirectFieldAccessor endpointAccessor = new DirectFieldAccessor(this.minimalConfig);
|
||||
RestTemplate restTemplate =
|
||||
TestUtils.getPropertyValue(this.minimalConfig, "handler.restTemplate", RestTemplate.class);
|
||||
TestUtils.getPropertyValue(this.minimalConfig, "handler.restTemplate", RestTemplate.class);
|
||||
assertNotSame(customRestTemplate, restTemplate);
|
||||
HttpRequestExecutingMessageHandler handler = (HttpRequestExecutingMessageHandler) endpointAccessor.getPropertyValue("handler");
|
||||
DirectFieldAccessor handlerAccessor = new DirectFieldAccessor(handler);
|
||||
@@ -179,23 +188,20 @@ public class HttpOutboundChannelAdapterParserTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asyncMinimalConfig() {
|
||||
DirectFieldAccessor endpointAccessor = new DirectFieldAccessor(this.asyncMinimalConfig);
|
||||
AsyncRestTemplate asyncRestTemplate =
|
||||
TestUtils.getPropertyValue(this.asyncMinimalConfig, "handler.asyncRestTemplate", AsyncRestTemplate.class);
|
||||
assertNotSame(this.asyncRestTemplate, asyncRestTemplate);
|
||||
AsyncHttpRequestExecutingMessageHandler handler = (AsyncHttpRequestExecutingMessageHandler) endpointAccessor.getPropertyValue("handler");
|
||||
public void reactiveMinimalConfig() {
|
||||
DirectFieldAccessor endpointAccessor = new DirectFieldAccessor(this.reactiveMinimalConfig);
|
||||
WebClient webClient =
|
||||
TestUtils.getPropertyValue(this.reactiveMinimalConfig, "handler.webClient", WebClient.class);
|
||||
assertNotSame(this.webClient, webClient);
|
||||
Object handler = endpointAccessor.getPropertyValue("handler");
|
||||
DirectFieldAccessor handlerAccessor = new DirectFieldAccessor(handler);
|
||||
assertEquals(false, handlerAccessor.getPropertyValue("expectReply"));
|
||||
assertEquals(this.applicationContext.getBean("requests"), endpointAccessor.getPropertyValue("inputChannel"));
|
||||
assertNull(handlerAccessor.getPropertyValue("outputChannel"));
|
||||
DirectFieldAccessor templateAccessor = new DirectFieldAccessor(handlerAccessor.getPropertyValue("asyncRestTemplate"));
|
||||
AsyncClientHttpRequestFactory asyncRequestFactory = (AsyncClientHttpRequestFactory)
|
||||
templateAccessor.getPropertyValue("asyncRequestFactory");
|
||||
assertTrue(asyncRequestFactory instanceof SimpleClientHttpRequestFactory);
|
||||
Expression uriExpression = (Expression) handlerAccessor.getPropertyValue("uriExpression");
|
||||
assertEquals("http://localhost/test1", uriExpression.getValue());
|
||||
assertEquals(HttpMethod.POST.name(), TestUtils.getPropertyValue(handler, "httpMethodExpression", Expression.class).getExpressionString());
|
||||
assertEquals(HttpMethod.POST.name(),
|
||||
TestUtils.getPropertyValue(handler, "httpMethodExpression", Expression.class).getExpressionString());
|
||||
assertEquals(Charset.forName("UTF-8"), handlerAccessor.getPropertyValue("charset"));
|
||||
assertEquals(true, handlerAccessor.getPropertyValue("extractPayload"));
|
||||
}
|
||||
@@ -203,16 +209,13 @@ public class HttpOutboundChannelAdapterParserTests {
|
||||
@Test
|
||||
public void restTemplateConfig() {
|
||||
RestTemplate restTemplate =
|
||||
TestUtils.getPropertyValue(this.restTemplateConfig, "handler.restTemplate", RestTemplate.class);
|
||||
TestUtils.getPropertyValue(this.restTemplateConfig, "handler.restTemplate", RestTemplate.class);
|
||||
assertEquals(customRestTemplate, restTemplate);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asyncRestTemplateConfig() {
|
||||
AsyncRestTemplate asyncRestTemplate = TestUtils.getPropertyValue(
|
||||
this.asyncRestTemplateConfig,
|
||||
"handler.asyncRestTemplate", AsyncRestTemplate.class);
|
||||
assertSame(this.asyncRestTemplate, asyncRestTemplate);
|
||||
public void reactiveWebClientConfig() {
|
||||
assertSame(this.webClient, TestUtils.getPropertyValue(this.reactiveWebClientConfig, "handler.webClient"));
|
||||
}
|
||||
|
||||
@Test(expected = BeanDefinitionParsingException.class)
|
||||
@@ -225,7 +228,7 @@ public class HttpOutboundChannelAdapterParserTests {
|
||||
public void withUrlAndTemplate() {
|
||||
DirectFieldAccessor endpointAccessor = new DirectFieldAccessor(this.withUrlAndTemplate);
|
||||
RestTemplate restTemplate =
|
||||
TestUtils.getPropertyValue(this.withUrlAndTemplate, "handler.restTemplate", RestTemplate.class);
|
||||
TestUtils.getPropertyValue(this.withUrlAndTemplate, "handler.restTemplate", RestTemplate.class);
|
||||
assertSame(customRestTemplate, restTemplate);
|
||||
HttpRequestExecutingMessageHandler handler = (HttpRequestExecutingMessageHandler) endpointAccessor.getPropertyValue("handler");
|
||||
DirectFieldAccessor handlerAccessor = new DirectFieldAccessor(handler);
|
||||
@@ -255,7 +258,7 @@ public class HttpOutboundChannelAdapterParserTests {
|
||||
public void withUrlExpression() {
|
||||
DirectFieldAccessor endpointAccessor = new DirectFieldAccessor(this.withUrlExpression);
|
||||
RestTemplate restTemplate =
|
||||
TestUtils.getPropertyValue(this.withUrlExpression, "handler.restTemplate", RestTemplate.class);
|
||||
TestUtils.getPropertyValue(this.withUrlExpression, "handler.restTemplate", RestTemplate.class);
|
||||
assertNotSame(customRestTemplate, restTemplate);
|
||||
HttpRequestExecutingMessageHandler handler = (HttpRequestExecutingMessageHandler) endpointAccessor.getPropertyValue("handler");
|
||||
DirectFieldAccessor handlerAccessor = new DirectFieldAccessor(handler);
|
||||
@@ -285,7 +288,7 @@ public class HttpOutboundChannelAdapterParserTests {
|
||||
public void withUrlExpressionAndTemplate() {
|
||||
DirectFieldAccessor endpointAccessor = new DirectFieldAccessor(this.withUrlExpressionAndTemplate);
|
||||
RestTemplate restTemplate =
|
||||
TestUtils.getPropertyValue(this.withUrlExpressionAndTemplate, "handler.restTemplate", RestTemplate.class);
|
||||
TestUtils.getPropertyValue(this.withUrlExpressionAndTemplate, "handler.restTemplate", RestTemplate.class);
|
||||
assertSame(customRestTemplate, restTemplate);
|
||||
HttpRequestExecutingMessageHandler handler = (HttpRequestExecutingMessageHandler) endpointAccessor.getPropertyValue("handler");
|
||||
DirectFieldAccessor handlerAccessor = new DirectFieldAccessor(handler);
|
||||
@@ -325,6 +328,7 @@ public class HttpOutboundChannelAdapterParserTests {
|
||||
@Override
|
||||
public void handleError(ClientHttpResponse response) throws IOException {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class FooAdvice extends AbstractRequestHandlerAdvice {
|
||||
@@ -336,4 +340,5 @@ public class HttpOutboundChannelAdapterParserTests {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans:beans xmlns="http://www.springframework.org/schema/integration/http"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:si="http://www.springframework.org/schema/integration"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:si="http://www.springframework.org/schema/integration"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
@@ -14,7 +14,8 @@
|
||||
|
||||
<si:channel id="requests"/>
|
||||
|
||||
<beans:bean id="asyncRestTemplate" class="org.springframework.web.client.AsyncRestTemplate"/>
|
||||
<beans:bean id="webClient" class="org.springframework.web.reactive.function.client.WebClient"
|
||||
factory-method="create"/>
|
||||
|
||||
<outbound-gateway id="minimalConfig" url="http://localhost/test1" request-channel="requests"/>
|
||||
|
||||
@@ -23,46 +24,44 @@
|
||||
</si:channel>
|
||||
|
||||
<outbound-gateway id="fullConfig"
|
||||
url="http://localhost/test2"
|
||||
http-method="PUT"
|
||||
request-channel="requests"
|
||||
request-factory="testRequestFactory"
|
||||
reply-timeout="1234"
|
||||
message-converters="converterList"
|
||||
extract-request-payload="false"
|
||||
expected-response-type="java.lang.String"
|
||||
mapped-request-headers="requestHeader1, requestHeader2"
|
||||
mapped-response-headers="responseHeader"
|
||||
error-handler="testErrorHandler"
|
||||
reply-channel="replies"
|
||||
charset="UTF-8"
|
||||
order="77"
|
||||
auto-startup="false"
|
||||
transfer-cookies="true">
|
||||
url="http://localhost/test2"
|
||||
http-method="PUT"
|
||||
request-channel="requests"
|
||||
request-factory="testRequestFactory"
|
||||
reply-timeout="1234"
|
||||
message-converters="converterList"
|
||||
extract-request-payload="false"
|
||||
expected-response-type="java.lang.String"
|
||||
mapped-request-headers="requestHeader1, requestHeader2"
|
||||
mapped-response-headers="responseHeader"
|
||||
error-handler="testErrorHandler"
|
||||
reply-channel="replies"
|
||||
charset="UTF-8"
|
||||
order="77"
|
||||
auto-startup="false"
|
||||
transfer-cookies="true">
|
||||
<uri-variable name="foo" expression="headers.bar"/>
|
||||
</outbound-gateway>
|
||||
|
||||
<outbound-async-gateway id="asyncMinimalConfig" url="http://localhost/test1" request-channel="requests" async-rest-template="asyncRestTemplate"/>
|
||||
<outbound-reactive-gateway id="reactiveMinimalConfig" url="http://localhost/test1" request-channel="requests"
|
||||
web-client="webClient"/>
|
||||
|
||||
<outbound-async-gateway id="asyncFullConfig"
|
||||
url="http://localhost/test2"
|
||||
http-method="PUT"
|
||||
request-channel="requests"
|
||||
async-request-factory="testRequestFactory"
|
||||
reply-timeout="1234"
|
||||
message-converters="converterList"
|
||||
extract-request-payload="false"
|
||||
expected-response-type="java.lang.String"
|
||||
mapped-request-headers="requestHeader1, requestHeader2"
|
||||
mapped-response-headers="responseHeader"
|
||||
error-handler="testErrorHandler"
|
||||
reply-channel="replies"
|
||||
charset="UTF-8"
|
||||
order="77"
|
||||
auto-startup="false"
|
||||
transfer-cookies="true">
|
||||
<outbound-reactive-gateway id="reactiveFullConfig"
|
||||
url="http://localhost/test2"
|
||||
http-method="PUT"
|
||||
request-channel="requests"
|
||||
reply-timeout="1234"
|
||||
extract-request-payload="false"
|
||||
expected-response-type="java.lang.String"
|
||||
mapped-request-headers="requestHeader1, requestHeader2"
|
||||
mapped-response-headers="responseHeader"
|
||||
reply-channel="replies"
|
||||
charset="UTF-8"
|
||||
order="77"
|
||||
auto-startup="false"
|
||||
transfer-cookies="true">
|
||||
<uri-variable name="foo" expression="headers.bar"/>
|
||||
</outbound-async-gateway>
|
||||
</outbound-reactive-gateway>
|
||||
|
||||
<util:map id="uriVariables">
|
||||
<beans:entry key="foo1" value="bar1"/>
|
||||
@@ -74,7 +73,7 @@
|
||||
|
||||
<outbound-gateway id="withAdvice" url-expression="'http://localhost/test1'" request-channel="requests">
|
||||
<request-handler-advice-chain>
|
||||
<beans:bean class="org.springframework.integration.http.config.HttpOutboundGatewayParserTests$FooAdvice" />
|
||||
<beans:bean class="org.springframework.integration.http.config.HttpOutboundGatewayParserTests$FooAdvice"/>
|
||||
</request-handler-advice-chain>
|
||||
</outbound-gateway>
|
||||
|
||||
@@ -116,7 +115,8 @@
|
||||
|
||||
<beans:bean id="testRequestFactory" class="org.springframework.http.client.SimpleClientHttpRequestFactory"/>
|
||||
|
||||
<beans:bean id="testErrorHandler" class="org.springframework.integration.http.config.HttpOutboundGatewayParserTests$StubErrorHandler"/>
|
||||
<beans:bean id="testErrorHandler"
|
||||
class="org.springframework.integration.http.config.HttpOutboundGatewayParserTests$StubErrorHandler"/>
|
||||
|
||||
<util:list id="converterList">
|
||||
<beans:bean class="org.springframework.integration.http.config.StubHttpMessageConverter"/>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* 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.
|
||||
@@ -19,6 +19,7 @@ package org.springframework.integration.http.config;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
@@ -41,14 +42,12 @@ import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.standard.SpelExpression;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.client.AsyncClientHttpRequestFactory;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
import org.springframework.integration.endpoint.AbstractEndpoint;
|
||||
import org.springframework.integration.endpoint.PollingConsumer;
|
||||
import org.springframework.integration.handler.advice.AbstractRequestHandlerAdvice;
|
||||
import org.springframework.integration.http.outbound.AsyncHttpRequestExecutingMessageHandler;
|
||||
import org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.messaging.Message;
|
||||
@@ -58,8 +57,8 @@ import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.web.client.AsyncRestTemplate;
|
||||
import org.springframework.web.client.ResponseErrorHandler;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
@@ -72,29 +71,36 @@ import org.springframework.web.client.ResponseErrorHandler;
|
||||
@DirtiesContext
|
||||
public class HttpOutboundGatewayParserTests {
|
||||
|
||||
@Autowired @Qualifier("minimalConfig")
|
||||
@Autowired
|
||||
@Qualifier("minimalConfig")
|
||||
private AbstractEndpoint minimalConfigEndpoint;
|
||||
|
||||
@Autowired @Qualifier("fullConfig")
|
||||
@Autowired
|
||||
@Qualifier("fullConfig")
|
||||
private AbstractEndpoint fullConfigEndpoint;
|
||||
|
||||
@Autowired @Qualifier("asyncMinimalConfig")
|
||||
private AbstractEndpoint asyncMinimalConfigEndpoint;
|
||||
@Autowired
|
||||
@Qualifier("reactiveMinimalConfig")
|
||||
private AbstractEndpoint reactiveMinimalConfigEndpoint;
|
||||
|
||||
@Autowired @Qualifier("asyncFullConfig")
|
||||
private AbstractEndpoint asyncFullConfigEndpoint;
|
||||
@Autowired
|
||||
@Qualifier("reactiveFullConfig")
|
||||
private AbstractEndpoint reactiveFullConfigEndpoint;
|
||||
|
||||
@Autowired @Qualifier("withUrlExpression")
|
||||
@Autowired
|
||||
@Qualifier("withUrlExpression")
|
||||
private AbstractEndpoint withUrlExpressionEndpoint;
|
||||
|
||||
@Autowired @Qualifier("withAdvice")
|
||||
@Autowired
|
||||
@Qualifier("withAdvice")
|
||||
private AbstractEndpoint withAdvice;
|
||||
|
||||
@Autowired @Qualifier("withPoller1")
|
||||
@Autowired
|
||||
@Qualifier("withPoller1")
|
||||
private AbstractEndpoint withPoller1;
|
||||
|
||||
@Autowired @Qualifier("asyncRestTemplate")
|
||||
private AsyncRestTemplate asyncRestTemplate;
|
||||
@Autowired
|
||||
private WebClient webClient;
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext applicationContext;
|
||||
@@ -173,22 +179,19 @@ public class HttpOutboundGatewayParserTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asyncMinimalConfig() {
|
||||
AsyncHttpRequestExecutingMessageHandler handler = (AsyncHttpRequestExecutingMessageHandler) new DirectFieldAccessor(
|
||||
this.asyncMinimalConfigEndpoint).getPropertyValue("handler");
|
||||
MessageChannel requestChannel = (MessageChannel) new DirectFieldAccessor(
|
||||
this.minimalConfigEndpoint).getPropertyValue("inputChannel");
|
||||
public void reactiveMinimalConfig() {
|
||||
Object handler = new DirectFieldAccessor(this.reactiveMinimalConfigEndpoint).getPropertyValue("handler");
|
||||
Object requestChannel = new DirectFieldAccessor(this.reactiveMinimalConfigEndpoint)
|
||||
.getPropertyValue("inputChannel");
|
||||
assertEquals(this.applicationContext.getBean("requests"), requestChannel);
|
||||
DirectFieldAccessor handlerAccessor = new DirectFieldAccessor(handler);
|
||||
Object replyChannel = handlerAccessor.getPropertyValue("outputChannel");
|
||||
assertNull(replyChannel);
|
||||
DirectFieldAccessor templateAccessor = new DirectFieldAccessor(handlerAccessor.getPropertyValue("asyncRestTemplate"));
|
||||
AsyncClientHttpRequestFactory requestFactory = (AsyncClientHttpRequestFactory)
|
||||
templateAccessor.getPropertyValue("asyncRequestFactory");
|
||||
assertTrue(requestFactory instanceof SimpleClientHttpRequestFactory);
|
||||
assertSame(this.webClient, handlerAccessor.getPropertyValue("webClient"));
|
||||
Expression uriExpression = (Expression) handlerAccessor.getPropertyValue("uriExpression");
|
||||
assertEquals("http://localhost/test1", uriExpression.getValue());
|
||||
assertEquals(HttpMethod.POST.name(), TestUtils.getPropertyValue(handler, "httpMethodExpression", Expression.class).getExpressionString());
|
||||
assertEquals(HttpMethod.POST.name(),
|
||||
TestUtils.getPropertyValue(handler, "httpMethodExpression", Expression.class).getExpressionString());
|
||||
assertEquals(Charset.forName("UTF-8"), handlerAccessor.getPropertyValue("charset"));
|
||||
assertEquals(true, handlerAccessor.getPropertyValue("extractPayload"));
|
||||
assertEquals(false, handlerAccessor.getPropertyValue("transferCookies"));
|
||||
@@ -196,11 +199,11 @@ public class HttpOutboundGatewayParserTests {
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void asyncFullConfig() {
|
||||
DirectFieldAccessor endpointAccessor = new DirectFieldAccessor(this.asyncFullConfigEndpoint);
|
||||
AsyncHttpRequestExecutingMessageHandler handler = (AsyncHttpRequestExecutingMessageHandler) endpointAccessor.getPropertyValue("handler");
|
||||
public void reactiveFullConfig() {
|
||||
DirectFieldAccessor endpointAccessor = new DirectFieldAccessor(this.reactiveFullConfigEndpoint);
|
||||
Object handler = endpointAccessor.getPropertyValue("handler");
|
||||
MessageChannel requestChannel = (MessageChannel) new DirectFieldAccessor(
|
||||
this.asyncFullConfigEndpoint).getPropertyValue("inputChannel");
|
||||
this.reactiveFullConfigEndpoint).getPropertyValue("inputChannel");
|
||||
assertEquals(this.applicationContext.getBean("requests"), requestChannel);
|
||||
DirectFieldAccessor handlerAccessor = new DirectFieldAccessor(handler);
|
||||
assertEquals(77, handlerAccessor.getPropertyValue("order"));
|
||||
@@ -208,24 +211,15 @@ public class HttpOutboundGatewayParserTests {
|
||||
Object replyChannel = handlerAccessor.getPropertyValue("outputChannel");
|
||||
assertNotNull(replyChannel);
|
||||
assertEquals(this.applicationContext.getBean("replies"), replyChannel);
|
||||
DirectFieldAccessor asyncTemplateAccessor = new DirectFieldAccessor(handlerAccessor.getPropertyValue("asyncRestTemplate"));
|
||||
DirectFieldAccessor syncTemplateAccessor = new DirectFieldAccessor(asyncTemplateAccessor.getPropertyValue("syncTemplate"));
|
||||
AsyncClientHttpRequestFactory requestFactory = (AsyncClientHttpRequestFactory)
|
||||
asyncTemplateAccessor.getPropertyValue("asyncRequestFactory");
|
||||
assertTrue(requestFactory instanceof SimpleClientHttpRequestFactory);
|
||||
Object converterListBean = this.applicationContext.getBean("converterList");
|
||||
assertEquals(converterListBean, syncTemplateAccessor.getPropertyValue("messageConverters"));
|
||||
|
||||
assertEquals(String.class.getName(), TestUtils.getPropertyValue(handler, "expectedResponseTypeExpression", Expression.class).getValue());
|
||||
assertEquals(String.class.getName(),
|
||||
TestUtils.getPropertyValue(handler, "expectedResponseTypeExpression", Expression.class).getValue());
|
||||
Expression uriExpression = (Expression) handlerAccessor.getPropertyValue("uriExpression");
|
||||
assertEquals("http://localhost/test2", uriExpression.getValue());
|
||||
assertEquals(HttpMethod.PUT.name(), TestUtils.getPropertyValue(handler, "httpMethodExpression", Expression.class).getExpressionString());
|
||||
assertEquals(HttpMethod.PUT.name(),
|
||||
TestUtils.getPropertyValue(handler, "httpMethodExpression", Expression.class).getExpressionString());
|
||||
assertEquals(Charset.forName("UTF-8"), handlerAccessor.getPropertyValue("charset"));
|
||||
assertEquals(false, handlerAccessor.getPropertyValue("extractPayload"));
|
||||
Object requestFactoryBean = this.applicationContext.getBean("testRequestFactory");
|
||||
assertEquals(requestFactoryBean, requestFactory);
|
||||
Object errorHandlerBean = this.applicationContext.getBean("testErrorHandler");
|
||||
assertEquals(errorHandlerBean, syncTemplateAccessor.getPropertyValue("errorHandler"));
|
||||
Object sendTimeout = new DirectFieldAccessor(
|
||||
handlerAccessor.getPropertyValue("messagingTemplate")).getPropertyValue("sendTimeout");
|
||||
assertEquals(new Long("1234"), sendTimeout);
|
||||
@@ -302,7 +296,6 @@ public class HttpOutboundGatewayParserTests {
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static class StubErrorHandler implements ResponseErrorHandler {
|
||||
|
||||
@Override
|
||||
@@ -324,4 +317,5 @@ public class HttpOutboundGatewayParserTests {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,16 +18,12 @@ package org.springframework.integration.http.dsl;
|
||||
|
||||
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
|
||||
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
|
||||
import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
|
||||
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
|
||||
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -37,13 +33,15 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.client.reactive.ClientHttpConnector;
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
import org.springframework.integration.config.EnableIntegration;
|
||||
import org.springframework.integration.dsl.IntegrationFlow;
|
||||
import org.springframework.integration.dsl.IntegrationFlows;
|
||||
import org.springframework.integration.http.outbound.AsyncHttpRequestExecutingMessageHandler;
|
||||
import org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler;
|
||||
import org.springframework.integration.http.outbound.ReactiveHttpRequestExecutingMessageHandler;
|
||||
import org.springframework.integration.security.channel.ChannelSecurityInterceptor;
|
||||
import org.springframework.integration.security.channel.SecuredChannel;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
@@ -58,16 +56,18 @@ import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.client.MockMvcClientHttpRequestFactory;
|
||||
import org.springframework.test.web.client.MockRestServiceServer;
|
||||
import org.springframework.test.web.reactive.server.HttpHandlerConnector;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.AsyncRestTemplate;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* @author Artem Bilan
|
||||
* @author Shiliang Li
|
||||
@@ -86,7 +86,7 @@ public class HttpDslTests {
|
||||
private HttpRequestExecutingMessageHandler serviceInternalGatewayHandler;
|
||||
|
||||
@Autowired
|
||||
private AsyncHttpRequestExecutingMessageHandler serviceInternalAsyncGatewayHandler;
|
||||
private ReactiveHttpRequestExecutingMessageHandler serviceInternalReactiveGatewayHandler;
|
||||
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@@ -115,16 +115,21 @@ public class HttpDslTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHttpAsyncProxyFlow() throws Exception {
|
||||
AsyncRestTemplate asyncRestTemplate = new AsyncRestTemplate();
|
||||
String destinationUri = "http://www.springsource.org/spring-integration";
|
||||
MockRestServiceServer
|
||||
.createServer(asyncRestTemplate)
|
||||
.expect(requestTo(Matchers.startsWith(destinationUri)))
|
||||
.andExpect(method(HttpMethod.POST))
|
||||
.andRespond(withSuccess("FOO", MediaType.TEXT_PLAIN));
|
||||
new DirectFieldAccessor(this.serviceInternalAsyncGatewayHandler)
|
||||
.setPropertyValue("asyncRestTemplate", asyncRestTemplate);
|
||||
public void testHttpReactiveProxyFlow() throws Exception {
|
||||
ClientHttpConnector httpConnector = new HttpHandlerConnector((request, response) -> {
|
||||
response.setStatusCode(HttpStatus.OK);
|
||||
response.getHeaders().setContentType(MediaType.TEXT_PLAIN);
|
||||
|
||||
return response.writeWith(Mono.just(response.bufferFactory().wrap("FOO".getBytes())))
|
||||
.then(response::setComplete);
|
||||
});
|
||||
|
||||
WebClient webClient = WebClient.builder()
|
||||
.clientConnector(httpConnector)
|
||||
.build();
|
||||
|
||||
new DirectFieldAccessor(this.serviceInternalReactiveGatewayHandler)
|
||||
.setPropertyValue("webClient", webClient);
|
||||
|
||||
this.mockMvc.perform(
|
||||
get("/service2")
|
||||
@@ -191,17 +196,18 @@ public class HttpDslTests {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public IntegrationFlow httpAsyncProxyFlow() {
|
||||
public IntegrationFlow httpReactiveProxyFlow() {
|
||||
return IntegrationFlows
|
||||
.from(Http.inboundGateway("/service2")
|
||||
.requestMapping(r -> r.params("name")))
|
||||
.handle(Http.<MultiValueMap<String, String>>outboundAsyncGateway(m ->
|
||||
.handle(Http.<MultiValueMap<String, String>>outboundReactiveGateway(m ->
|
||||
UriComponentsBuilder.fromUriString("http://www.springsource.org/spring-integration")
|
||||
.queryParams(m.getPayload())
|
||||
.build()
|
||||
.toUri())
|
||||
.httpMethod(HttpMethod.GET)
|
||||
.expectedResponseType(String.class),
|
||||
e -> e.id("serviceInternalAsyncGateway"))
|
||||
e -> e.id("serviceInternalReactiveGateway"))
|
||||
.get();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright 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.http.outbound;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
|
||||
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
|
||||
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.dsl.channel.MessageChannels;
|
||||
import org.springframework.integration.http.HttpHeaders;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.test.web.client.MockRestServiceServer;
|
||||
import org.springframework.web.client.AsyncRestTemplate;
|
||||
|
||||
/**
|
||||
* @author Shiliang Li
|
||||
* @since 5.0
|
||||
*/
|
||||
public class AsyncHttpRequestExecutingMessageHandlerTests {
|
||||
|
||||
@Test
|
||||
public void testAsyncReturn() {
|
||||
AsyncRestTemplate asyncRestTemplate = new AsyncRestTemplate();
|
||||
String destinationUri = "http://www.springsource.org/spring-integration";
|
||||
MockRestServiceServer
|
||||
.createServer(asyncRestTemplate)
|
||||
.expect(requestTo(destinationUri))
|
||||
.andExpect(method(HttpMethod.POST))
|
||||
.andRespond(withSuccess());
|
||||
|
||||
AsyncHttpRequestExecutingMessageHandler asyncHandler = new AsyncHttpRequestExecutingMessageHandler(
|
||||
destinationUri,
|
||||
asyncRestTemplate);
|
||||
QueueChannel ackChannel = MessageChannels.queue().get();
|
||||
asyncHandler.setOutputChannel(ackChannel);
|
||||
asyncHandler.handleMessage(MessageBuilder.withPayload("hello, world").build());
|
||||
Message<?> ack = ackChannel.receive(1000);
|
||||
assertNotNull(ack);
|
||||
assertNotNull(ack.getHeaders());
|
||||
assertEquals(ack.getHeaders().get(HttpHeaders.STATUS_CODE), HttpStatus.OK);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright 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.http.outbound;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.client.reactive.ClientHttpConnector;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.channel.ReactiveChannel;
|
||||
import org.springframework.integration.http.HttpHeaders;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.support.ErrorMessage;
|
||||
import org.springframework.test.web.reactive.server.HttpHandlerConnector;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* @author Shiliang Li
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 5.0
|
||||
*/
|
||||
public class ReactiveHttpRequestExecutingMessageHandlerTests {
|
||||
|
||||
@Test
|
||||
public void testReactiveReturn() throws Throwable {
|
||||
ClientHttpConnector httpConnector = new HttpHandlerConnector((request, response) -> {
|
||||
response.setStatusCode(HttpStatus.OK);
|
||||
return Mono.empty()
|
||||
.then(response::setComplete);
|
||||
});
|
||||
|
||||
WebClient webClient = WebClient.builder()
|
||||
.clientConnector(httpConnector)
|
||||
.build();
|
||||
|
||||
String destinationUri = "http://www.springsource.org/spring-integration";
|
||||
ReactiveHttpRequestExecutingMessageHandler reactiveHandler =
|
||||
new ReactiveHttpRequestExecutingMessageHandler(destinationUri, webClient);
|
||||
|
||||
ReactiveChannel ackChannel = new ReactiveChannel();
|
||||
reactiveHandler.setOutputChannel(ackChannel);
|
||||
reactiveHandler.handleMessage(MessageBuilder.withPayload("hello, world").build());
|
||||
|
||||
Message<?> ack = Mono.from(ackChannel).block(Duration.ofSeconds(10));
|
||||
|
||||
assertNotNull(ack);
|
||||
assertNotNull(ack.getHeaders());
|
||||
assertEquals(ack.getHeaders().get(HttpHeaders.STATUS_CODE), HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReactiveErrorOneWay() throws Throwable {
|
||||
ClientHttpConnector httpConnector = new HttpHandlerConnector((request, response) -> {
|
||||
response.setStatusCode(HttpStatus.UNAUTHORIZED);
|
||||
return Mono.empty()
|
||||
.then(response::setComplete);
|
||||
});
|
||||
|
||||
WebClient webClient = WebClient.builder()
|
||||
.clientConnector(httpConnector)
|
||||
.build();
|
||||
|
||||
String destinationUri = "http://www.springsource.org/spring-integration";
|
||||
ReactiveHttpRequestExecutingMessageHandler reactiveHandler =
|
||||
new ReactiveHttpRequestExecutingMessageHandler(destinationUri, webClient);
|
||||
reactiveHandler.setExpectReply(false);
|
||||
|
||||
QueueChannel errorChannel = new QueueChannel();
|
||||
reactiveHandler.handleMessage(MessageBuilder.withPayload("hello, world")
|
||||
.setErrorChannel(errorChannel)
|
||||
.build());
|
||||
|
||||
Message<?> errorMessage = errorChannel.receive(10000);
|
||||
|
||||
assertNotNull(errorMessage);
|
||||
assertThat(errorMessage, instanceOf(ErrorMessage.class));
|
||||
Throwable throwable = (Throwable) errorMessage.getPayload();
|
||||
assertThat(throwable.getMessage(), containsString("401 Unauthorized"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReactiveConnectErrorOneWay() throws Throwable {
|
||||
ClientHttpConnector httpConnector = new HttpHandlerConnector((request, response) -> {
|
||||
throw new RuntimeException("Intentional connection error");
|
||||
});
|
||||
|
||||
WebClient webClient = WebClient.builder()
|
||||
.clientConnector(httpConnector)
|
||||
.build();
|
||||
|
||||
String destinationUri = "http://www.springsource.org/spring-integration";
|
||||
ReactiveHttpRequestExecutingMessageHandler reactiveHandler =
|
||||
new ReactiveHttpRequestExecutingMessageHandler(destinationUri, webClient);
|
||||
reactiveHandler.setExpectReply(false);
|
||||
|
||||
QueueChannel errorChannel = new QueueChannel();
|
||||
reactiveHandler.handleMessage(MessageBuilder.withPayload("hello, world")
|
||||
.setErrorChannel(errorChannel)
|
||||
.build());
|
||||
|
||||
Message<?> errorMessage = errorChannel.receive(10000);
|
||||
|
||||
assertNotNull(errorMessage);
|
||||
assertThat(errorMessage, instanceOf(ErrorMessage.class));
|
||||
Throwable throwable = (Throwable) errorMessage.getPayload();
|
||||
assertThat(throwable.getMessage(), containsString("Intentional connection error"));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
=== Introduction
|
||||
|
||||
The HTTP support allows for the execution of HTTP requests and the processing of inbound HTTP requests.
|
||||
the HTTP support consists of the following gateway implementations: `HttpInboundEndpoint`, `HttpRequestExecutingMessageHandler` and `AsyncHttpRequestExecutingMessageHandler`
|
||||
the HTTP support consists of the following gateway implementations: `HttpInboundEndpoint`, `HttpRequestExecutingMessageHandler` and `ReactiveHttpRequestExecutingMessageHandler`
|
||||
|
||||
[[http-inbound]]
|
||||
=== Http Inbound Components
|
||||
@@ -191,36 +191,42 @@ The `expected-response-type` must be compatible with the (configured or default)
|
||||
Of course, this can be an abstract class, or even an interface (such as `java.io.Serializable` when using java serialization and `Content-Type: application/x-java-serialized-object`).
|
||||
=====
|
||||
|
||||
==== AsyncHttpRequestExecutingMessageHandler
|
||||
==== ReactiveHttpRequestExecutingMessageHandler
|
||||
|
||||
The `AsyncHttpRequestExecutingMessageHandler` implementation is very similar to `HttpRequestExecutingMessageHandler` instead of delegating to a `AsyncRestTemplate`.
|
||||
The `ReactiveHttpRequestExecutingMessageHandler` implementation is very similar to `HttpRequestExecutingMessageHandler` instead of delegating to a `WebClient` from Spring Framework WebFlux module.
|
||||
To configure it, write a bean like this:
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
<bean id="httpAsyncOutbound"
|
||||
class="org.springframework.integration.http.outbound.AsyncHttpRequestExecutingMessageHandler">
|
||||
<bean id="httpReactiveOutbound"
|
||||
class="org.springframework.integration.http.outbound.ReactiveHttpRequestExecutingMessageHandler">
|
||||
<constructor-arg value="http://localhost:8080/example" />
|
||||
<property name="outputChannel" ref="responseChannel" />
|
||||
</bean>
|
||||
----
|
||||
|
||||
You can configure the `AsyncClientHttpRequestFactory` instance to use:
|
||||
You can configure a `WebClient` instance to use:
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
<bean id="httpOutbound"
|
||||
class="org.springframework.integration.http.outbound.AsyncHttpRequestExecutingMessageHandler">
|
||||
<beans:bean id="webClient" class="org.springframework.web.reactive.function.client.WebClient"
|
||||
factory-method="create"/>
|
||||
|
||||
<bean id="httpReactiveOutbound"
|
||||
class="org.springframework.integration.http.outbound.ReactiveHttpRequestExecutingMessageHandler">
|
||||
<constructor-arg value="http://localhost:8080/example" />
|
||||
<constructor-arg re="webClient" />
|
||||
<property name="outputChannel" ref="responseChannel" />
|
||||
<property name="asyncRequestFactory" ref="customRequestFactory" />
|
||||
</bean>
|
||||
----
|
||||
|
||||
By default the HTTP request will be generated using an instance of `SimpleClientHttpRequestFactory`.
|
||||
Use of the Apache Commons HTTP Async Client is also supported through the provided `HttpComponentsAsyncClientHttpRequestFactory` which can be injected as shown above.
|
||||
The `WebClient` `exchange()` operation returns a `Mono<ClientResponse>` which is mapped to the `AbstractIntegrationMessageBuilder` reactive support (using `Mono.map()`) as the output from the `ReactiveHttpRequestExecutingMessageHandler`.
|
||||
Together with the `ReactiveChannel` as an `outputChannel`, the `Mono<ClientResponse>` evaluation is deferred until a downstream subscription is made.
|
||||
Otherwise, it is treated as an `async` mode and the `Mono` response is adapted to an `SettableListenableFuture` for an asynchronous reply from the `ReactiveHttpRequestExecutingMessageHandler`.
|
||||
|
||||
For other settings like cookie, converters, etc, please see <<HttpRequestExecutingMessageHandler>> above.
|
||||
See http://docs.spring.io/spring/docs/5.0.0.M5/spring-framework-reference/html/web-reactive.html#web-reactive-client[WebFlux documentation] and https://projectreactor.io/[Project Reactor] for more information.
|
||||
|
||||
For other settings like cookie, uri variables, etc, please see <<HttpRequestExecutingMessageHandler>> above.
|
||||
|
||||
[[http-namespace]]
|
||||
=== HTTP Namespace Support
|
||||
@@ -544,29 +550,27 @@ The configuration looks very similar to the gateway:
|
||||
auto-startup="false"/>
|
||||
----
|
||||
|
||||
If you want to execute the http request in an asynchronous way, you can use the `outbound-async-gateway` or `outbound-async-channel-adapter`.
|
||||
If you want to execute the http request in a reactive, non-blocking way, you can use the `outbound-reactive-gateway` or `outbound-reactive-channel-adapter`.
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
<int-http:outbound-async-gateway id="asyncExample1"
|
||||
<int-http:outbound-reactive-gateway id="reactiveExample1"
|
||||
request-channel="requests"
|
||||
url="http://localhost/test"
|
||||
http-method-expression="headers.httpMethod"
|
||||
extract-request-payload="false"
|
||||
expected-response-type-expression="payload"
|
||||
charset="UTF-8"
|
||||
async-request-factory="requestFactory"
|
||||
reply-timeout="1234"
|
||||
reply-channel="replies"/>
|
||||
|
||||
<int-http:outbound-async-channel-adapter id="asyncExample2"
|
||||
<int-http:outbound-reactive-channel-adapter id="reactiveExample2"
|
||||
url="http://localhost/example"
|
||||
http-method="GET"
|
||||
channel="requests"
|
||||
charset="UTF-8"
|
||||
extract-payload="false"
|
||||
expected-response-type="java.lang.String"
|
||||
async-request-factory="someRequestFactory"
|
||||
order="3"
|
||||
auto-startup="false"/>
|
||||
|
||||
|
||||
@@ -27,10 +27,10 @@ See <<testing>> for more information.
|
||||
The new `MongoDbOutboundGateway` allows you to make queries to the database on demand by sending a message to its request channel.
|
||||
See <<mongodb-outbound-gateway>> for more information.
|
||||
|
||||
==== HTTP Async Outbound Gateway and Channel Adapter
|
||||
==== HTTP Reactive Outbound Gateway and Channel Adapter
|
||||
|
||||
The new `AsyncHttpRequestExecutingMessageHandler` adds support for `AsyncRestTemplate` for outbound channel adapter and gateway.
|
||||
See <<AsyncHttpRequestExecutingMessageHandler>> for more information.
|
||||
The new `ReactiveHttpRequestExecutingMessageHandler` adds support for WebFlux `WebClient` for outbound channel adapter and gateway.
|
||||
See <<ReactiveHttpRequestExecutingMessageHandler>> for more information.
|
||||
|
||||
==== Content Type Conversion
|
||||
|
||||
|
||||
Reference in New Issue
Block a user