INT-2822: 'requires-reply' for Outbound Gateways
* Add `requires-reply` attribute for all adapters outbound gateways as `true` by default * WS-outbound-gateway is still without it, because it has its own specific attribute `ignore-empty-responses` * Make `requires-reply` as `false` by default for `jdbc:stored-proc-outbound-gateway` inasmuch as `jdbc:stored-proc-outbound-adapter` doesn't have ability to configure `returning-resultset` * add parser tests for `requires-reply` JIRA: https://jira.springsource.org/browse/INT-2822 INT-2822 'requires-reply' for ws:outbound-gateway Default false. INT-2822: Polishing after rebase INT-2822: deprecate 'ignore-empty-responses' * Add 'requires-reply' section into What's New INT-2822: remove 'ignore-empty-responses' from RM INT-2822: Polishing after rebase INT-2822: Rebased and polished INT-2822: Rebased and polished Add WARN within deprecated `AbstractWebServiceOutboundGateway#setIgnoreEmptyResponses` Revert 'ignore-empty-responses'; Doc Polishing
This commit is contained in:
committed by
Gary Russell
parent
b8980d4064
commit
70886b2543
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
@@ -29,6 +29,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Mark Fisher
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Gunnar Hillert
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
@@ -53,6 +54,7 @@ public class AmqpOutboundGatewayParser extends AbstractConsumerEndpointParser {
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "routing-key");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "routing-key-expression");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "reply-timeout", "sendTimeout");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "requires-reply");
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "reply-channel", "outputChannel");
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "return-channel");
|
||||
|
||||
|
||||
@@ -199,6 +199,15 @@
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="requires-reply" type="xsd:string" use="optional" default="true">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Specify whether this outbound gateway must return a non-null value. This value is
|
||||
'true' by default, and a ReplyRequiredException will be thrown when
|
||||
the underlying service returns a null value.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
routing-key="si.test.binding"
|
||||
amqp-template="amqpTemplate"
|
||||
order="5"
|
||||
requires-reply="false"
|
||||
mapped-request-headers="foo*"
|
||||
mapped-reply-headers="bar*"/>
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.integration.amqp.config;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
@@ -62,7 +63,7 @@ public class AmqpOutboundGatewayParserTests {
|
||||
Object edc = context.getBean("rabbitGateway");
|
||||
AmqpOutboundEndpoint gateway = TestUtils.getPropertyValue(edc, "handler", AmqpOutboundEndpoint.class);
|
||||
assertEquals(5, gateway.getOrder());
|
||||
assertTrue(context.containsBean("rabbitGateway"));
|
||||
assertTrue(TestUtils.getPropertyValue(gateway, "requiresReply", Boolean.class));
|
||||
assertEquals(context.getBean("fromRabbit"), TestUtils.getPropertyValue(gateway, "outputChannel"));
|
||||
assertEquals("amqp:outbound-gateway", gateway.getComponentType());
|
||||
MessageChannel returnChannel = context.getBean("returnChannel", MessageChannel.class);
|
||||
@@ -81,6 +82,8 @@ public class AmqpOutboundGatewayParserTests {
|
||||
|
||||
AmqpOutboundEndpoint endpoint = TestUtils.getPropertyValue(eventDrivernConsumer, "handler", AmqpOutboundEndpoint.class);
|
||||
|
||||
assertFalse(TestUtils.getPropertyValue(endpoint, "requiresReply", Boolean.class));
|
||||
|
||||
Field amqpTemplateField = ReflectionUtils.findField(AmqpOutboundEndpoint.class, "amqpTemplate");
|
||||
amqpTemplateField.setAccessible(true);
|
||||
RabbitTemplate amqpTemplate = TestUtils.getPropertyValue(endpoint, "amqpTemplate", RabbitTemplate.class);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,6 +26,7 @@ import org.springframework.util.StringUtils;
|
||||
* Base class for url-based outbound gateway parsers.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Artem Bilan
|
||||
*/
|
||||
public abstract class AbstractOutboundGatewayParser extends AbstractConsumerEndpointParser {
|
||||
|
||||
@@ -45,6 +46,7 @@ public abstract class AbstractOutboundGatewayParser extends AbstractConsumerEndp
|
||||
if (StringUtils.hasText(replyChannel)) {
|
||||
builder.addPropertyReference("replyChannel", replyChannel);
|
||||
}
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "requires-reply");
|
||||
this.postProcessGateway(builder, element, parserContext);
|
||||
return builder;
|
||||
}
|
||||
|
||||
@@ -1075,7 +1075,6 @@
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
|
||||
<xsd:complexType name="serviceActivatorType">
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="expressionOrInnerEndpointDefinitionAware">
|
||||
@@ -1083,10 +1082,8 @@
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Specify whether the service method must return a non-null value. This value will be
|
||||
FALSE by
|
||||
default, but if set to TRUE, a MessageHandlingException will be thrown when
|
||||
the underlying service method (or
|
||||
expression) returns a NULL value.
|
||||
'false' by default, but if set to 'true', a ReplyRequiredException will be thrown when
|
||||
the underlying service method (or expression) returns a null value.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
@@ -3153,9 +3150,9 @@ is provided, the return value is expected to match a channel name exactly.
|
||||
<xsd:attribute name="requires-reply" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Specify whether the splitter method must return a non-null value. This value will be
|
||||
FALSE by default, but if set to TRUE, a MessageHandlingException will be thrown when
|
||||
the underlying service method (or expression) returns a NULL value.
|
||||
Specify whether the service method must return a non-null value. This value will be
|
||||
'false' by default, but if set to 'true', a ReplyRequiredException will be thrown when
|
||||
the underlying service method (or expression) returns a null value.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Gary Russell
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Gunnar Hillert
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
@@ -54,8 +55,7 @@ public abstract class AbstractRemoteFileOutboundGatewayParser extends AbstractCo
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "local-directory");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "auto-create-local-directory");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "order");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "rename-expression");
|
||||
return builder;
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "rename-expression"); IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "requires-reply"); return builder;
|
||||
}
|
||||
|
||||
protected void configureFilter(BeanDefinitionBuilder builder, Element element, ParserContext parserContext) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -44,6 +44,7 @@ public class FileOutboundGatewayParser extends AbstractConsumerEndpointParser {
|
||||
protected BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext) {
|
||||
BeanDefinitionBuilder handlerBuilder = FileWritingMessageHandlerBeanDefinitionBuilder.configure(element, true, parserContext);
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(handlerBuilder, element, "reply-timeout", "sendTimeout");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(handlerBuilder, element, "requires-reply");
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(handlerBuilder, element, "reply-channel", "outputChannel");
|
||||
return handlerBuilder;
|
||||
}
|
||||
|
||||
@@ -394,6 +394,15 @@ Only files matching this regular expression will be picked up by this adapter.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="requires-reply" type="xsd:string" use="optional" default="true">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Specify whether this outbound gateway must return a non-null value. This value is
|
||||
'true' by default, and a ReplyRequiredException will be thrown when
|
||||
the underlying service returns a null value.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
<int-file:outbound-gateway id="gatewayWithDirectoryExpression"
|
||||
request-channel="someChannel" directory-expression="'build/foo'"
|
||||
auto-startup="false" order="777" filename-generator-expression="'foo.txt'">
|
||||
auto-startup="false" order="777" filename-generator-expression="'foo.txt'" requires-reply="false">
|
||||
<int-file:request-handler-advice-chain>
|
||||
<beans:bean class="org.springframework.integration.file.config.FileOutboundGatewayParserTests$FooAdvice" />
|
||||
</int-file:request-handler-advice-chain>
|
||||
@@ -28,7 +28,7 @@
|
||||
<int-file:outbound-gateway id="gatewayWithReplaceMode"
|
||||
request-channel="gatewayWithReplaceModeChannel"
|
||||
filename-generator-expression="'fileToAppend.txt'" mode="REPLACE"
|
||||
directory="test" />
|
||||
directory="test" requires-reply="false"/>
|
||||
|
||||
<int-file:outbound-gateway id="gatewayWithAppendMode"
|
||||
request-channel="gatewayWithAppendModeChannel"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.integration.file.config;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
@@ -27,10 +28,12 @@ import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.MessageChannel;
|
||||
import org.springframework.integration.MessageHandlingException;
|
||||
import org.springframework.integration.core.MessageHandler;
|
||||
import org.springframework.integration.core.MessagingTemplate;
|
||||
import org.springframework.integration.endpoint.EventDrivenConsumer;
|
||||
import org.springframework.integration.file.DefaultFileNameGenerator;
|
||||
@@ -45,6 +48,7 @@ import org.springframework.util.FileCopyUtils;
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
* @author Gunnar Hillert
|
||||
* @author Artem Bilan
|
||||
*/
|
||||
@ContextConfiguration
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@@ -68,6 +72,10 @@ public class FileOutboundGatewayParserTests {
|
||||
@Autowired
|
||||
MessageChannel gatewayWithReplaceModeChannel;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("gatewayWithReplaceMode.handler")
|
||||
MessageHandler gatewayWithReplaceModeHandler;
|
||||
|
||||
@Autowired
|
||||
MessageChannel gatewayWithFailModeLowercaseChannel;
|
||||
|
||||
@@ -82,6 +90,7 @@ public class FileOutboundGatewayParserTests {
|
||||
assertEquals(Boolean.FALSE, gatewayAccessor.getPropertyValue("autoStartup"));
|
||||
DirectFieldAccessor handlerAccessor = new DirectFieldAccessor(handler);
|
||||
assertEquals(777, handlerAccessor.getPropertyValue("order"));
|
||||
assertEquals(Boolean.TRUE, handlerAccessor.getPropertyValue("requiresReply"));
|
||||
DefaultFileNameGenerator fileNameGenerator = (DefaultFileNameGenerator) handlerAccessor.getPropertyValue("fileNameGenerator");
|
||||
assertNotNull(fileNameGenerator);
|
||||
String expression = (String) TestUtils.getPropertyValue(fileNameGenerator, "expression");
|
||||
@@ -264,6 +273,8 @@ public class FileOutboundGatewayParserTests {
|
||||
@Test
|
||||
public void gatewayWithReplaceMode() throws Exception{
|
||||
|
||||
assertFalse(TestUtils.getPropertyValue(this.gatewayWithReplaceModeHandler, "requiresReply", Boolean.class));
|
||||
|
||||
final MessagingTemplate messagingTemplate = new MessagingTemplate(this.gatewayWithReplaceModeChannel);
|
||||
|
||||
String expectedFileContent = "String content:";
|
||||
|
||||
@@ -435,6 +435,15 @@
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="requires-reply" type="xsd:string" use="optional" default="true">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Specify whether this outbound gateway must return a non-null value. This value is
|
||||
'true' by default, and a ReplyRequiredException will be thrown when
|
||||
the underlying service returns a null value.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
command-options="-P"
|
||||
expression="payload"
|
||||
order="2"
|
||||
requires-reply="false"
|
||||
>
|
||||
<int-ftp:request-handler-advice-chain>
|
||||
<bean class="org.springframework.integration.ftp.config.FtpOutboundGatewayParserTests$FooAdvice" />
|
||||
|
||||
@@ -84,6 +84,7 @@ public class FtpOutboundGatewayParserTests {
|
||||
|
||||
Long sendTimeout = TestUtils.getPropertyValue(gateway, "messagingTemplate.sendTimeout", Long.class);
|
||||
assertEquals(Long.valueOf(777), sendTimeout);
|
||||
assertTrue(TestUtils.getPropertyValue(gateway, "requiresReply", Boolean.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -101,6 +102,7 @@ public class FtpOutboundGatewayParserTests {
|
||||
Set<String> options = TestUtils.getPropertyValue(gateway, "options", Set.class);
|
||||
assertTrue(options.contains(Option.PRESERVE_TIMESTAMP));
|
||||
gateway.handleMessage(new GenericMessage<String>("foo"));
|
||||
assertFalse(TestUtils.getPropertyValue(gateway, "requiresReply", Boolean.class));
|
||||
assertEquals(1, adviceCalled);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
@@ -24,6 +24,7 @@ import org.w3c.dom.Element;
|
||||
/**
|
||||
* @author Dave Syer
|
||||
* @author Gunnar Hillert
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 2.0
|
||||
*
|
||||
@@ -48,8 +49,7 @@ public class JdbcOutboundGatewayParser extends AbstractConsumerEndpointParser {
|
||||
String updateQuery = IntegrationNamespaceUtils.getTextFromAttributeOrNestedElement(element, "update",
|
||||
parserContext);
|
||||
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(JdbcOutboundGateway.class);
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(JdbcOutboundGateway.class);
|
||||
if (refToDataSourceSet) {
|
||||
builder.addConstructorArgReference(dataSourceRef);
|
||||
}
|
||||
@@ -68,6 +68,7 @@ public class JdbcOutboundGatewayParser extends AbstractConsumerEndpointParser {
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "max-rows-per-poll");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "keys-generated");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "reply-timeout", "sendTimeout");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "requires-reply");
|
||||
|
||||
String replyChannel = element.getAttribute("reply-channel");
|
||||
if (StringUtils.hasText(replyChannel)) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
@@ -27,6 +27,7 @@ import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* @author Gunnar Hillert
|
||||
* @author Artem Bilan
|
||||
* @since 2.1
|
||||
*
|
||||
*/
|
||||
@@ -62,6 +63,7 @@ public class StoredProcOutboundGatewayParser extends AbstractConsumerEndpointPar
|
||||
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "expect-single-result");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "reply-timeout", "sendTimeout");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "requires-reply");
|
||||
|
||||
String replyChannel = element.getAttribute("reply-channel");
|
||||
if (StringUtils.hasText(replyChannel)) {
|
||||
|
||||
@@ -502,6 +502,15 @@
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="requires-reply" type="xsd:string" use="optional" default="true">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Specify whether this outbound gateway must return a non-null value. This value is
|
||||
'true' by default, and a ReplyRequiredException will be thrown when
|
||||
the underlying service returns a null value.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
@@ -967,6 +976,15 @@
|
||||
<xsd:union memberTypes="xsd:boolean xsd:string" />
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="requires-reply" type="xsd:string" use="optional" default="false">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Specify whether this outbound gateway must return a non-null value. This value is
|
||||
'false' by default, if it set to 'true', a ReplyRequiredException will be thrown when
|
||||
the underlying service returns a null value.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
|
||||
@@ -14,14 +14,17 @@ package org.springframework.integration.jdbc.config;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@@ -29,6 +32,7 @@ import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.MessageChannel;
|
||||
import org.springframework.integration.core.MessageHandler;
|
||||
import org.springframework.integration.core.MessagingTemplate;
|
||||
import org.springframework.integration.core.PollableChannel;
|
||||
import org.springframework.integration.endpoint.PollingConsumer;
|
||||
@@ -75,6 +79,7 @@ public class JdbcOutboundGatewayParserTests {
|
||||
assertEquals("bar", payload.get("name"));
|
||||
JdbcOutboundGateway gateway = context.getBean("jdbcGateway.handler", JdbcOutboundGateway.class);
|
||||
assertEquals(23, TestUtils.getPropertyValue(gateway, "order"));
|
||||
Assert.assertTrue(TestUtils.getPropertyValue(gateway, "requiresReply", Boolean.class));
|
||||
Object gw = context.getBean("jdbcGateway");
|
||||
assertEquals(1, adviceCalled);
|
||||
}
|
||||
@@ -204,11 +209,15 @@ public class JdbcOutboundGatewayParserTests {
|
||||
@Test //INT-1029
|
||||
public void testOutboundGatewayInsideChain() {
|
||||
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("handlingMapPayloadJdbcOutboundGatewayTest.xml", getClass());
|
||||
//INT-2755
|
||||
assertNotNull(context.getBean("org.springframework.integration.handler.MessageHandlerChain#0$child.jdbc-outbound-gateway-within-chain.handler",
|
||||
JdbcOutboundGateway.class));
|
||||
|
||||
JdbcOutboundGateway jdbcMessageHandler =
|
||||
context.getBean("org.springframework.integration.handler.MessageHandlerChain#0$child.jdbc-outbound-gateway-within-chain.handler",
|
||||
JdbcOutboundGateway.class);
|
||||
|
||||
MessageChannel channel = context.getBean("jdbcOutboundGatewayInsideChain", MessageChannel.class);
|
||||
|
||||
assertFalse(TestUtils.getPropertyValue(jdbcMessageHandler, "requiresReply", Boolean.class));
|
||||
|
||||
channel.send(MessageBuilder.withPayload(Collections.singletonMap("foo", "bar")).build());
|
||||
|
||||
PollableChannel outbound = context.getBean("replyChannel", PollableChannel.class);
|
||||
|
||||
@@ -47,6 +47,7 @@ import org.springframework.jdbc.core.SqlParameter;
|
||||
/**
|
||||
* @author Gunnar Hillert
|
||||
* @author Gary Russell
|
||||
* @author Artem Bilan
|
||||
* @since 2.1
|
||||
*
|
||||
*/
|
||||
@@ -65,6 +66,7 @@ public class StoredProcOutboundGatewayParserTests {
|
||||
DirectFieldAccessor accessor = new DirectFieldAccessor(this.outboundGateway);
|
||||
Object source = accessor.getPropertyValue("handler");
|
||||
accessor = new DirectFieldAccessor(source);
|
||||
assertEquals(Boolean.TRUE, accessor.getPropertyValue("requiresReply"));
|
||||
source = accessor.getPropertyValue("executor");
|
||||
accessor = new DirectFieldAccessor(source);
|
||||
Expression storedProcedureName = (Expression) accessor.getPropertyValue("storedProcedureNameExpression");
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<si:chain input-channel="jdbcOutboundGatewayInsideChain" output-channel="replyChannel">
|
||||
<outbound-gateway id="jdbc-outbound-gateway-within-chain" query="select * from foos where id=:headers[id]"
|
||||
update="insert into foos (id, status, name) values (:headers[id], 0, :payload[foo])"
|
||||
data-source="dataSource"/>
|
||||
data-source="dataSource" requires-reply="false"/>
|
||||
|
||||
</si:chain>
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
data-source="datasource" auto-startup="true" id="storedProcedureOutboundGateway"
|
||||
ignore-column-meta-data="false" is-function="false"
|
||||
skip-undeclared-results="false" order="2" reply-channel="replyChannel"
|
||||
reply-timeout="555" return-value-required="true">
|
||||
reply-timeout="555" return-value-required="true" requires-reply="true">
|
||||
|
||||
<int-jdbc:sql-parameter-definition name="username" direction="IN" type="VARCHAR" />
|
||||
<int-jdbc:sql-parameter-definition name="password" direction="OUT" />
|
||||
|
||||
@@ -33,6 +33,7 @@ import org.w3c.dom.Element;
|
||||
* @author Mark Fisher
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Gary Russell
|
||||
* @author Artem Bilan
|
||||
*/
|
||||
public class JmsOutboundGatewayParser extends AbstractConsumerEndpointParser {
|
||||
|
||||
@@ -65,6 +66,7 @@ public class JmsOutboundGatewayParser extends AbstractConsumerEndpointParser {
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "time-to-live");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "priority");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "explicit-qos-enabled");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "requires-reply");
|
||||
|
||||
String deliveryPersistent = element.getAttribute("delivery-persistent");
|
||||
if (StringUtils.hasText(deliveryPersistent)) {
|
||||
@@ -119,7 +121,7 @@ public class JmsOutboundGatewayParser extends AbstractConsumerEndpointParser {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(JmsOutboundGateway.ReplyContainerProperties.class);
|
||||
Integer acknowledgeMode = JmsAdapterParserUtils.parseAcknowledgeMode(element, parserContext);
|
||||
if (acknowledgeMode != null) {
|
||||
if (acknowledgeMode.intValue() == JmsAdapterParserUtils.SESSION_TRANSACTED) {
|
||||
if (JmsAdapterParserUtils.SESSION_TRANSACTED == acknowledgeMode) {
|
||||
builder.addPropertyValue("sessionTransacted", Boolean.TRUE);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -1065,6 +1065,15 @@
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="requires-reply" type="xsd:string" use="optional" default="true">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Specify whether this outbound gateway must return a non-null value. This value is
|
||||
'true' by default, and a ReplyRequiredException will be thrown when
|
||||
the underlying service returns a null value.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
@@ -1469,4 +1478,4 @@
|
||||
|
||||
</xsd:attributeGroup>
|
||||
|
||||
</xsd:schema>
|
||||
</xsd:schema>
|
||||
|
||||
@@ -128,6 +128,7 @@ public class JmsOutboundGatewayParserTests {
|
||||
new DirectFieldAccessor(endpoint).getPropertyValue("handler"));
|
||||
Object order = accessor.getPropertyValue("order");
|
||||
assertEquals(99, order);
|
||||
assertEquals(Boolean.TRUE, accessor.getPropertyValue("requiresReply"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd">
|
||||
|
||||
<si:channel id="requestChannel"/>
|
||||
|
||||
|
||||
<jms:outbound-gateway id="jmsGateway"
|
||||
request-destination-name="requestQueue"
|
||||
request-channel="requestChannel"
|
||||
@@ -47,7 +47,8 @@
|
||||
request-destination-name="requestQueue"
|
||||
request-channel="requestChannel"
|
||||
delivery-persistent="true"
|
||||
auto-startup="false">
|
||||
auto-startup="false"
|
||||
requires-reply="false">
|
||||
<jms:request-handler-advice-chain>
|
||||
<bean class="org.springframework.integration.jms.config.JmsOutboundGatewayParserTests$FooAdvice" />
|
||||
</jms:request-handler-advice-chain>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<jms:outbound-gateway id="jmsGateway"
|
||||
request-destination="requestQueue"
|
||||
request-channel="requestChannel"
|
||||
order="99"/>
|
||||
order="99" requires-reply="true"/>
|
||||
|
||||
<bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory">
|
||||
<constructor-arg>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,6 +18,7 @@ package org.springframework.integration.jmx.config;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.integration.jmx.OperationInvokingMessageHandler;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.config.xml.AbstractConsumerEndpointParser;
|
||||
@@ -25,10 +26,11 @@ import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
|
||||
|
||||
/**
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Artem Bilan
|
||||
* @since 2.0
|
||||
*/
|
||||
public class OperationInvokingOutboundGatewayParser extends AbstractConsumerEndpointParser {
|
||||
|
||||
|
||||
@Override
|
||||
protected String getInputChannelAttributeName() {
|
||||
return "request-channel";
|
||||
@@ -36,12 +38,12 @@ public class OperationInvokingOutboundGatewayParser extends AbstractConsumerEndp
|
||||
|
||||
@Override
|
||||
protected BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(
|
||||
"org.springframework.integration.jmx.OperationInvokingMessageHandler");
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(OperationInvokingMessageHandler.class);
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "server");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "object-name");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "operation-name");
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "reply-channel", "outputChannel");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "requires-reply");
|
||||
return builder;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,15 @@
|
||||
</xsd:all>
|
||||
<xsd:attribute name="request-channel" type="xsd:string" />
|
||||
<xsd:attribute name="reply-channel" type="xsd:string" use="optional" />
|
||||
<xsd:attribute name="requires-reply" type="xsd:string" use="optional" default="true">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Specify whether this outbound gateway must return a non-null value. This value is
|
||||
'true' by default, and ReplyRequiredException will be thrown when
|
||||
the underlying service returns a null value.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
@@ -29,18 +29,19 @@
|
||||
object-name="org.springframework.integration.jmx.config:type=TestBean,name=testBeanGateway"
|
||||
operation-name="testWithReturn">
|
||||
<jmx:request-handler-advice-chain>
|
||||
<bean class="org.springframework.integration.jmx.config.OperationInvokingOutboundGatewayTests$FooADvice" />
|
||||
<bean class="org.springframework.integration.jmx.config.OperationInvokingOutboundGatewayTests.FooAdvice" />
|
||||
</jmx:request-handler-advice-chain>
|
||||
</jmx:operation-invoking-outbound-gateway>
|
||||
|
||||
<si:chain input-channel="jmxOutboundGatewayInsideChain" output-channel="withReplyChannelOutput">
|
||||
<jmx:operation-invoking-outbound-gateway operation-name="testWithReturn"
|
||||
<si:chain id="operationInvokingWithinChain" input-channel="jmxOutboundGatewayInsideChain" output-channel="withReplyChannelOutput">
|
||||
<jmx:operation-invoking-outbound-gateway operation-name="testWithReturn" requires-reply="true"
|
||||
object-name="org.springframework.integration.jmx.config:type=TestBean,name=testBeanGateway"/>
|
||||
</si:chain>
|
||||
|
||||
<jmx:operation-invoking-outbound-gateway request-channel="withNoReplyChannel"
|
||||
object-name="org.springframework.integration.jmx.config:type=TestBean,name=testBeanGateway"
|
||||
operation-name="test"/>
|
||||
operation-name="test"
|
||||
requires-reply="false"/>
|
||||
|
||||
<bean id="testBeanGateway" class="org.springframework.integration.jmx.config.TestBean"/>
|
||||
</beans>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.integration.jmx.config;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -27,10 +28,13 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.MessageChannel;
|
||||
import org.springframework.integration.core.MessageHandler;
|
||||
import org.springframework.integration.core.PollableChannel;
|
||||
import org.springframework.integration.handler.advice.AbstractRequestHandlerAdvice;
|
||||
import org.springframework.integration.jmx.OperationInvokingMessageHandler;
|
||||
import org.springframework.integration.message.GenericMessage;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
@@ -61,6 +65,12 @@ public class OperationInvokingOutboundGatewayTests {
|
||||
@Autowired
|
||||
private TestBean testBean;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("operationInvokingWithinChain.handler")
|
||||
private MessageHandler operationInvokingWithinChain;
|
||||
|
||||
|
||||
|
||||
private static volatile int adviceCalled;
|
||||
|
||||
@After
|
||||
@@ -89,8 +99,14 @@ public class OperationInvokingOutboundGatewayTests {
|
||||
assertEquals(3, testBean.messages.size());
|
||||
}
|
||||
|
||||
@Test //INT-1029
|
||||
@Test //INT-1029, INT-2822
|
||||
public void testOutboundGatewayInsideChain() throws Exception {
|
||||
List handlers = TestUtils.getPropertyValue(this.operationInvokingWithinChain, "handlers", List.class);
|
||||
assertEquals(1, handlers.size());
|
||||
Object handler = handlers.get(0);
|
||||
assertTrue(handler instanceof OperationInvokingMessageHandler);
|
||||
assertTrue(TestUtils.getPropertyValue(handler, "requiresReply", Boolean.class));
|
||||
|
||||
jmxOutboundGatewayInsideChain.send(MessageBuilder.withPayload("1").build());
|
||||
assertEquals(1, ((List<?>) withReplyChannelOutput.receive().getPayload()).size());
|
||||
jmxOutboundGatewayInsideChain.send(MessageBuilder.withPayload("2").build());
|
||||
@@ -99,7 +115,7 @@ public class OperationInvokingOutboundGatewayTests {
|
||||
assertEquals(3, ((List<?>) withReplyChannelOutput.receive().getPayload()).size());
|
||||
}
|
||||
|
||||
public static class FooADvice extends AbstractRequestHandlerAdvice {
|
||||
public static class FooAdvice extends AbstractRequestHandlerAdvice {
|
||||
|
||||
@Override
|
||||
protected Object doInvoke(ExecutionCallback callback, Object target, Message<?> message) throws Exception {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -30,6 +30,7 @@ import org.w3c.dom.Element;
|
||||
* The Abstract Parser for the JPA Outbound Gateways.
|
||||
*
|
||||
* @author Gunnar Hillert
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 2.2
|
||||
*
|
||||
@@ -46,6 +47,7 @@ public abstract class AbstractJpaOutboundGatewayParser extends AbstractConsumerE
|
||||
.genericBeanDefinition(JpaOutboundGatewayFactoryBean.class);
|
||||
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaOutboundGatewayBuilder, gatewayElement, "reply-timeout");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaOutboundGatewayBuilder, gatewayElement, "requires-reply");
|
||||
|
||||
final String replyChannel = gatewayElement.getAttribute("reply-channel");
|
||||
|
||||
|
||||
@@ -70,6 +70,8 @@ public class JpaOutboundGatewayFactoryBean extends AbstractFactoryBean<MessageHa
|
||||
|
||||
private long replyTimeout;
|
||||
|
||||
private volatile boolean requiresReply = false;
|
||||
|
||||
private volatile String componentName;
|
||||
|
||||
/**
|
||||
@@ -118,6 +120,10 @@ public class JpaOutboundGatewayFactoryBean extends AbstractFactoryBean<MessageHa
|
||||
this.replyTimeout = replyTimeout;
|
||||
}
|
||||
|
||||
public void setRequiresReply(boolean requiresReply) {
|
||||
this.requiresReply = requiresReply;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the handler component.
|
||||
*
|
||||
@@ -140,7 +146,8 @@ public class JpaOutboundGatewayFactoryBean extends AbstractFactoryBean<MessageHa
|
||||
jpaOutboundGateway.setProducesReply(this.producesReply);
|
||||
jpaOutboundGateway.setOutputChannel(this.outputChannel);
|
||||
jpaOutboundGateway.setOrder(this.order);
|
||||
jpaOutboundGateway.setSendTimeout(replyTimeout);
|
||||
jpaOutboundGateway.setSendTimeout(this.replyTimeout);
|
||||
jpaOutboundGateway.setRequiresReply(this.requiresReply);
|
||||
jpaOutboundGateway.setComponentName(this.componentName);
|
||||
if (this.adviceChain != null) {
|
||||
jpaOutboundGateway.setAdviceChain(this.adviceChain);
|
||||
|
||||
@@ -363,6 +363,15 @@
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="requires-reply" type="xsd:string" use="optional" default="true">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Specify whether this outbound gateway must return a non-null value. This value is
|
||||
'true' by default, and a ReplyRequiredException will be thrown when
|
||||
the underlying service returns a null value.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:attributeGroup>
|
||||
|
||||
<xsd:attributeGroup name="commonUpdatingJpaAttributes">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
@@ -13,18 +13,24 @@
|
||||
package org.springframework.integration.jpa.config.xml;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.MessagingException;
|
||||
import org.springframework.integration.channel.AbstractMessageChannel;
|
||||
import org.springframework.integration.core.MessageHandler;
|
||||
import org.springframework.integration.endpoint.EventDrivenConsumer;
|
||||
import org.springframework.integration.handler.ReplyRequiredException;
|
||||
import org.springframework.integration.handler.advice.AbstractRequestHandlerAdvice;
|
||||
import org.springframework.integration.jpa.core.JpaExecutor;
|
||||
import org.springframework.integration.jpa.core.JpaOperations;
|
||||
@@ -42,14 +48,12 @@ import org.springframework.integration.test.util.TestUtils;
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
public class JpaOutboundGatewayParserTests {
|
||||
public class JpaOutboundGatewayParserTests extends AbstractRequestHandlerAdvice {
|
||||
|
||||
private ConfigurableApplicationContext context;
|
||||
|
||||
private EventDrivenConsumer consumer;
|
||||
|
||||
private static volatile int adviceCalled;
|
||||
|
||||
@Test
|
||||
public void testRetrievingJpaOutboundGatewayParser() throws Exception {
|
||||
setUp("JpaOutboundGatewayParserTests.xml", getClass(), "retrievingJpaOutboundGateway");
|
||||
@@ -69,6 +73,7 @@ public class JpaOutboundGatewayParserTests {
|
||||
|
||||
assertEquals(100, sendTimeout);
|
||||
|
||||
assertFalse(TestUtils.getPropertyValue(jpaOutboundGateway, "requiresReply", Boolean.class));
|
||||
|
||||
final JpaExecutor jpaExecutor = TestUtils.getPropertyValue(this.consumer, "handler.jpaExecutor", JpaExecutor.class);
|
||||
|
||||
@@ -87,7 +92,6 @@ public class JpaOutboundGatewayParserTests {
|
||||
final Integer maxNumberOfResults = TestUtils.getPropertyValue(jpaExecutor, "maxNumberOfResults", Integer.class);
|
||||
|
||||
assertEquals(Integer.valueOf(55), maxNumberOfResults);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -109,6 +113,8 @@ public class JpaOutboundGatewayParserTests {
|
||||
|
||||
assertEquals(100, sendTimeout);
|
||||
|
||||
assertFalse(TestUtils.getPropertyValue(jpaOutboundGateway, "requiresReply", Boolean.class));
|
||||
|
||||
final JpaExecutor jpaExecutor = TestUtils.getPropertyValue(this.consumer, "handler.jpaExecutor", JpaExecutor.class);
|
||||
|
||||
assertNotNull(jpaExecutor);
|
||||
@@ -136,14 +142,22 @@ public class JpaOutboundGatewayParserTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void advised() throws Exception {
|
||||
public void advised() throws Throwable {
|
||||
setUp("JpaOutboundGatewayParserTests.xml", getClass(), "advised");
|
||||
|
||||
MessageHandler jpaOutboundGateway = context.getBean("advised.handler", MessageHandler.class);
|
||||
FooAdvice advice = context.getBean("jpaFooAdvice", FooAdvice.class);
|
||||
assertTrue(AopUtils.isAopProxy(jpaOutboundGateway));
|
||||
|
||||
jpaOutboundGateway.handleMessage(new GenericMessage<String>("foo"));
|
||||
assertEquals(1, adviceCalled);
|
||||
try {
|
||||
jpaOutboundGateway.handleMessage(new GenericMessage<String>("foo"));
|
||||
fail("expected ReplyRequiredException");
|
||||
}
|
||||
catch (MessagingException e) {
|
||||
assertTrue(e instanceof ReplyRequiredException);
|
||||
}
|
||||
|
||||
Mockito.verify(advice).doInvoke(Mockito.any(ExecutionCallback.class), Mockito.any(Object.class), Mockito.any(Message.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -168,11 +182,16 @@ public class JpaOutboundGatewayParserTests {
|
||||
consumer = this.context.getBean(gatewayId, EventDrivenConsumer.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object doInvoke(ExecutionCallback callback, Object target, Message<?> message) throws Exception {
|
||||
// Workaround for access to protected AbstractRequestHandlerAdvice.ExecutionCallback
|
||||
return null;
|
||||
}
|
||||
|
||||
public static class FooAdvice extends AbstractRequestHandlerAdvice {
|
||||
|
||||
@Override
|
||||
protected Object doInvoke(ExecutionCallback callback, Object target, Message<?> message) throws Exception {
|
||||
adviceCalled++;
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,8 @@
|
||||
max-number-of-results="55"
|
||||
request-channel="in"
|
||||
reply-channel="out"
|
||||
reply-timeout="100"/>
|
||||
reply-timeout="100"
|
||||
requires-reply="false"/>
|
||||
|
||||
<int-jpa:updating-outbound-gateway id="updatingJpaOutboundGateway"
|
||||
entity-manager-factory="entityManagerFactory"
|
||||
@@ -34,7 +35,8 @@
|
||||
order="2"
|
||||
request-channel="in"
|
||||
reply-channel="out"
|
||||
reply-timeout="100"/>
|
||||
reply-timeout="100"
|
||||
requires-reply="false"/>
|
||||
|
||||
<int-jpa:updating-outbound-gateway id="advised"
|
||||
entity-manager-factory="entityManagerFactory"
|
||||
@@ -48,8 +50,14 @@
|
||||
reply-timeout="100">
|
||||
<int-jpa:transactional/>
|
||||
<int-jpa:request-handler-advice-chain>
|
||||
<bean class="org.springframework.integration.jpa.config.xml.JpaOutboundGatewayParserTests$FooAdvice"/>
|
||||
<ref bean="jpaFooAdvice"/>
|
||||
</int-jpa:request-handler-advice-chain>
|
||||
</int-jpa:updating-outbound-gateway>
|
||||
|
||||
<bean id="jpaFooAdvice" class="org.mockito.Mockito" factory-method="spy">
|
||||
<constructor-arg>
|
||||
<bean class="org.springframework.integration.jpa.config.xml.JpaOutboundGatewayParserTests$FooAdvice"/>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -101,6 +101,15 @@
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="requires-reply" type="xsd:string" use="optional" default="true">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Specify whether this outbound gateway must return a non-null value. This value is
|
||||
'true' by default, and a ReplyRequiredException will be thrown when
|
||||
the underlying service returns a null value.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,7 +17,9 @@
|
||||
package org.springframework.integration.rmi.config;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -60,6 +62,7 @@ public class RmiOutboundGatewayParserTests {
|
||||
"rmiOutboundGatewayParserTests.xml", this.getClass());
|
||||
RmiOutboundGateway gateway = context.getBean("gateway.handler", RmiOutboundGateway.class);
|
||||
assertEquals(23, TestUtils.getPropertyValue(gateway, "order"));
|
||||
assertTrue(TestUtils.getPropertyValue(gateway, "requiresReply", Boolean.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -67,6 +70,9 @@ public class RmiOutboundGatewayParserTests {
|
||||
ApplicationContext context = new ClassPathXmlApplicationContext(
|
||||
"rmiOutboundGatewayParserTests.xml", this.getClass());
|
||||
MessageChannel localChannel = (MessageChannel) context.getBean("advisedChannel");
|
||||
RmiOutboundGateway gateway = context.getBean("advised.handler", RmiOutboundGateway.class);
|
||||
assertFalse(TestUtils.getPropertyValue(gateway, "requiresReply", Boolean.class));
|
||||
|
||||
localChannel.send(new GenericMessage<String>("test"));
|
||||
Message<?> result = testChannel.receive(1000);
|
||||
assertNotNull(result);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
<rmi:outbound-gateway id="advised"
|
||||
request-channel="advisedChannel"
|
||||
remote-channel="testChannel"
|
||||
requires-reply="false"
|
||||
host="localhost">
|
||||
<rmi:request-handler-advice-chain>
|
||||
<beans:bean class="org.springframework.integration.rmi.config.RmiOutboundGatewayParserTests$FooAdvice" />
|
||||
@@ -30,7 +31,7 @@
|
||||
</rmi:outbound-gateway>
|
||||
|
||||
<chain input-channel="rmiOutboundGatewayInsideChain">
|
||||
<rmi:outbound-gateway remote-channel="testChannel" host="localhost"/>
|
||||
<rmi:outbound-gateway remote-channel="testChannel" host="localhost" requires-reply="false"/>
|
||||
</chain>
|
||||
|
||||
|
||||
|
||||
@@ -432,6 +432,15 @@
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="requires-reply" type="xsd:string" use="optional" default="true">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Specify whether this outbound gateway must return a non-null value. This value is
|
||||
'true' by default, and a ReplyRequiredException will be thrown when
|
||||
the underlying service returns a null value.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
command-options="-P"
|
||||
expression="payload"
|
||||
order="2"
|
||||
requires-reply="false"
|
||||
/>
|
||||
|
||||
<int-sftp:outbound-gateway id="gateway3"
|
||||
@@ -66,6 +67,7 @@
|
||||
command="get"
|
||||
command-options="-P"
|
||||
expression="payload"
|
||||
requires-reply="false"
|
||||
order="2">
|
||||
<int-sftp:request-handler-advice-chain>
|
||||
<bean class="org.springframework.integration.sftp.config.SftpOutboundGatewayParserTests$FooAdvice" />
|
||||
|
||||
@@ -73,6 +73,7 @@ public class SftpOutboundGatewayParserTests {
|
||||
assertNotNull(TestUtils.getPropertyValue(gateway, "outputChannel"));
|
||||
assertEquals(new File("local-test-dir"), TestUtils.getPropertyValue(gateway, "localDirectory"));
|
||||
assertFalse((Boolean) TestUtils.getPropertyValue(gateway, "autoCreateLocalDirectory"));
|
||||
assertTrue(TestUtils.getPropertyValue(gateway, "requiresReply", Boolean.class));
|
||||
assertNotNull(TestUtils.getPropertyValue(gateway, "filter"));
|
||||
assertEquals(Command.LS, TestUtils.getPropertyValue(gateway, "command"));
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -95,6 +96,7 @@ public class SftpOutboundGatewayParserTests {
|
||||
assertEquals(new File("local-test-dir"), TestUtils.getPropertyValue(gateway, "localDirectory"));
|
||||
assertFalse((Boolean) TestUtils.getPropertyValue(gateway, "autoCreateLocalDirectory"));
|
||||
assertEquals(Command.GET, TestUtils.getPropertyValue(gateway, "command"));
|
||||
assertFalse(TestUtils.getPropertyValue(gateway, "requiresReply", Boolean.class));
|
||||
@SuppressWarnings("unchecked")
|
||||
Set<String> options = TestUtils.getPropertyValue(gateway, "options", Set.class);
|
||||
assertTrue(options.contains(Option.PRESERVE_TIMESTAMP));
|
||||
|
||||
@@ -83,6 +83,7 @@ public class WebServiceOutboundGatewayParser extends AbstractOutboundGatewayPars
|
||||
}
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "reply-channel");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "reply-timeout", "sendTimeout");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "requires-reply");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "ignore-empty-responses");
|
||||
this.postProcessGateway(builder, element, parserContext);
|
||||
|
||||
|
||||
@@ -87,6 +87,16 @@
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="requires-reply" type="xsd:string" use="optional" default="false">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Specify whether this outbound gateway must return a non-null value. This value is
|
||||
'false' by default, otherwise a ReplyRequiredException will be thrown when
|
||||
the underlying service returns a null value, or an empty String (if
|
||||
'ignore-empty-responses' is 'true').
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="uri" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
@@ -139,7 +149,9 @@
|
||||
<xsd:attribute name="ignore-empty-responses" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Indicates whether empty String response payloads should be ignored. The default is TRUE.
|
||||
Indicates whether empty String response payloads should be considered as null. The default is TRUE.
|
||||
See also 'requires-reply'. Note that when 'requires-reply' is 'true' the response is not actually 'ignored',
|
||||
because it will cause a ReplyRequiredException to be thrown.
|
||||
Set this to FALSE if you want to send empty String responses in reply Messages.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
@@ -456,4 +468,4 @@ this list can also be simple patterns to be matched against the header names (e.
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
</xsd:schema>
|
||||
</xsd:schema>
|
||||
|
||||
@@ -17,13 +17,15 @@
|
||||
package org.springframework.integration.ws.config;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@@ -72,6 +74,7 @@ public class WebServiceOutboundGatewayParserTests {
|
||||
DirectFieldAccessor accessor = new DirectFieldAccessor(gateway);
|
||||
Object expected = context.getBean("outputChannel");
|
||||
assertEquals(expected, accessor.getPropertyValue("outputChannel"));
|
||||
Assert.assertEquals(Boolean.FALSE, accessor.getPropertyValue("requiresReply"));
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> requestHeaders = TestUtils.getPropertyValue(endpoint, "handler.headerMapper.requestHeaderNames", List.class);
|
||||
@@ -96,18 +99,20 @@ public class WebServiceOutboundGatewayParserTests {
|
||||
assertEquals(SimpleWebServiceOutboundGateway.class, gateway.getClass());
|
||||
DirectFieldAccessor accessor = new DirectFieldAccessor(gateway);
|
||||
assertEquals(Boolean.TRUE, accessor.getPropertyValue("ignoreEmptyResponses"));
|
||||
Assert.assertEquals(Boolean.FALSE, accessor.getPropertyValue("requiresReply"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleGatewayWithIgnoreEmptyResponses() {
|
||||
ApplicationContext context = new ClassPathXmlApplicationContext(
|
||||
"simpleWebServiceOutboundGatewayParserTests.xml", this.getClass());
|
||||
AbstractEndpoint endpoint = (AbstractEndpoint) context.getBean("gatewayWithIgnoreEmptyResponsesFalse");
|
||||
AbstractEndpoint endpoint = (AbstractEndpoint) context.getBean("gatewayWithIgnoreEmptyResponsesFalseAndRequiresReplyTrue");
|
||||
assertEquals(EventDrivenConsumer.class, endpoint.getClass());
|
||||
Object gateway = new DirectFieldAccessor(endpoint).getPropertyValue("handler");
|
||||
assertEquals(SimpleWebServiceOutboundGateway.class, gateway.getClass());
|
||||
DirectFieldAccessor accessor = new DirectFieldAccessor(gateway);
|
||||
assertEquals(Boolean.FALSE, accessor.getPropertyValue("ignoreEmptyResponses"));
|
||||
Assert.assertEquals(Boolean.TRUE, accessor.getPropertyValue("requiresReply"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -31,10 +31,11 @@
|
||||
mapped-request-headers="testRequest"
|
||||
mapped-reply-headers="testReply"/>
|
||||
|
||||
<ws:outbound-gateway id="gatewayWithIgnoreEmptyResponsesFalse"
|
||||
<ws:outbound-gateway id="gatewayWithIgnoreEmptyResponsesFalseAndRequiresReplyTrue"
|
||||
request-channel="inputChannel"
|
||||
uri="http://example.org"
|
||||
ignore-empty-responses="false"/>
|
||||
ignore-empty-responses="false"
|
||||
requires-reply="true"/>
|
||||
|
||||
<ws:outbound-gateway id="gatewayWithDefaultSourceExtractor"
|
||||
request-channel="inputChannel"
|
||||
|
||||
@@ -272,5 +272,38 @@
|
||||
For more information see <xref linkend="ip-headers"/>.
|
||||
</para>
|
||||
</section>
|
||||
<section id="3.0-outbound-gateway-requires-reply">
|
||||
<title>'requires-reply' Attribute for Outbound Gateways</title>
|
||||
<para>
|
||||
All Outbound Gateways (e.g. <code><jdbc:outbound-gateway/></code> or <code><jms:outbound-gateway/></code>)
|
||||
are designed for 'request-reply' scenarios. A response is expected from the external service and
|
||||
will be published to the <code>reply-channel</code>, or the <code>replyChannel</code> message header.
|
||||
However, there are some cases where the external system might not always return a
|
||||
result, e.g. a <code><jdbc:outbound-gateway/></code>, when a SELECT ends with an empty <interfacename>ResultSet</interfacename>
|
||||
or, say, a Web Service is One-Way. An option is therefore needed to configure whether or not a
|
||||
<emphasis>reply</emphasis> is required.
|
||||
For this purpose, the <emphasis>requires-reply</emphasis> attribute has been introduced for Outbound Gateway components.
|
||||
In most cases, the default value for <emphasis>requires-reply</emphasis> is <code>true</code> and, if there is not any result,
|
||||
a <classname>ReplyRequiredException</classname> will be thrown. Changing the value to <code>false</code>
|
||||
means that, if an external service doesn't return anything, the message-flow will end at that point,
|
||||
similar to an Outbound Channel Adapter.
|
||||
</para>
|
||||
<note>
|
||||
The WebService outbound gateway has an additional attribute <code>ignore-empty-responses</code>; this is used to
|
||||
treat an empty String response as if no response was received. It is true by default but can be set to false to
|
||||
allow the application to receive an empty String in the reply message payload. When the attribute is true an empty
|
||||
string is treated as no response for the purposes of the <emphasis>requires-reply</emphasis> attribute.
|
||||
<emphasis>requires-reply</emphasis> is false by default for the WebService outbound gateway.
|
||||
</note>
|
||||
<para>
|
||||
Note, the <code>requiresReply</code> property was previously present in the <classname>AbstractReplyProducingMessageHandler</classname>
|
||||
but set to <code>false</code>, and there wasn't any way to configure it on Outbound Gateways using the XML namespace.
|
||||
</para>
|
||||
<important>
|
||||
Previously, a gateway receiving no reply would silently end the flow (with a DEBUG log message); with this change an
|
||||
exception will now be thrown by default by most gateways. To revert to the previous behavior,
|
||||
set <code>requires-reply</code> to false.
|
||||
</important>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||
|
||||
Reference in New Issue
Block a user