diff --git a/spring-integration-amqp/src/main/java/org/springframework/integration/amqp/config/AmqpOutboundGatewayParser.java b/spring-integration-amqp/src/main/java/org/springframework/integration/amqp/config/AmqpOutboundGatewayParser.java index 7c1c95e919..58bc7315ba 100644 --- a/spring-integration-amqp/src/main/java/org/springframework/integration/amqp/config/AmqpOutboundGatewayParser.java +++ b/spring-integration-amqp/src/main/java/org/springframework/integration/amqp/config/AmqpOutboundGatewayParser.java @@ -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"); diff --git a/spring-integration-amqp/src/main/resources/org/springframework/integration/amqp/config/spring-integration-amqp-3.0.xsd b/spring-integration-amqp/src/main/resources/org/springframework/integration/amqp/config/spring-integration-amqp-3.0.xsd index 90089d4475..f07cf095f8 100644 --- a/spring-integration-amqp/src/main/resources/org/springframework/integration/amqp/config/spring-integration-amqp-3.0.xsd +++ b/spring-integration-amqp/src/main/resources/org/springframework/integration/amqp/config/spring-integration-amqp-3.0.xsd @@ -199,6 +199,15 @@ ]]> + + + + 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. + + + diff --git a/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundGatewayParserTests-context.xml b/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundGatewayParserTests-context.xml index 63ec21901b..f42ad1aefc 100644 --- a/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundGatewayParserTests-context.xml +++ b/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundGatewayParserTests-context.xml @@ -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*"/> diff --git a/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundGatewayParserTests.java b/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundGatewayParserTests.java index 15da4042a5..73a33b8c37 100644 --- a/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundGatewayParserTests.java +++ b/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundGatewayParserTests.java @@ -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); diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractOutboundGatewayParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractOutboundGatewayParser.java index e5bcacff75..a593e4a735 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractOutboundGatewayParser.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractOutboundGatewayParser.java @@ -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; } diff --git a/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-3.0.xsd b/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-3.0.xsd index feb0ffd0ab..071527fdc8 100644 --- a/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-3.0.xsd +++ b/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-3.0.xsd @@ -1075,7 +1075,6 @@ - @@ -1083,10 +1082,8 @@ 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. @@ -3153,9 +3150,9 @@ is provided, the return value is expected to match a channel name exactly. - 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. diff --git a/spring-integration-file/src/main/java/org/springframework/integration/file/config/AbstractRemoteFileOutboundGatewayParser.java b/spring-integration-file/src/main/java/org/springframework/integration/file/config/AbstractRemoteFileOutboundGatewayParser.java index c869b02ac3..ca68e7f0b4 100644 --- a/spring-integration-file/src/main/java/org/springframework/integration/file/config/AbstractRemoteFileOutboundGatewayParser.java +++ b/spring-integration-file/src/main/java/org/springframework/integration/file/config/AbstractRemoteFileOutboundGatewayParser.java @@ -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) { diff --git a/spring-integration-file/src/main/java/org/springframework/integration/file/config/FileOutboundGatewayParser.java b/spring-integration-file/src/main/java/org/springframework/integration/file/config/FileOutboundGatewayParser.java index 7209ebb0c6..284b76a4f5 100644 --- a/spring-integration-file/src/main/java/org/springframework/integration/file/config/FileOutboundGatewayParser.java +++ b/spring-integration-file/src/main/java/org/springframework/integration/file/config/FileOutboundGatewayParser.java @@ -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; } diff --git a/spring-integration-file/src/main/resources/org/springframework/integration/file/config/spring-integration-file-3.0.xsd b/spring-integration-file/src/main/resources/org/springframework/integration/file/config/spring-integration-file-3.0.xsd index ab6855010e..c74b77fbc9 100644 --- a/spring-integration-file/src/main/resources/org/springframework/integration/file/config/spring-integration-file-3.0.xsd +++ b/spring-integration-file/src/main/resources/org/springframework/integration/file/config/spring-integration-file-3.0.xsd @@ -394,6 +394,15 @@ Only files matching this regular expression will be picked up by this adapter. ]]> + + + + 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. + + + diff --git a/spring-integration-file/src/test/java/org/springframework/integration/file/config/FileOutboundGatewayParserTests-context.xml b/spring-integration-file/src/test/java/org/springframework/integration/file/config/FileOutboundGatewayParserTests-context.xml index b105a54cb0..ae2ce6fc6a 100644 --- a/spring-integration-file/src/test/java/org/springframework/integration/file/config/FileOutboundGatewayParserTests-context.xml +++ b/spring-integration-file/src/test/java/org/springframework/integration/file/config/FileOutboundGatewayParserTests-context.xml @@ -19,7 +19,7 @@ + auto-startup="false" order="777" filename-generator-expression="'foo.txt'" requires-reply="false"> @@ -28,7 +28,7 @@ + directory="test" requires-reply="false"/> + + + + 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. + + + diff --git a/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/config/FtpOutboundGatewayParserTests-context.xml b/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/config/FtpOutboundGatewayParserTests-context.xml index 3a9a7fbb27..152d56cc9a 100644 --- a/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/config/FtpOutboundGatewayParserTests-context.xml +++ b/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/config/FtpOutboundGatewayParserTests-context.xml @@ -43,6 +43,7 @@ command-options="-P" expression="payload" order="2" + requires-reply="false" > diff --git a/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/config/FtpOutboundGatewayParserTests.java b/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/config/FtpOutboundGatewayParserTests.java index 6178f01b7c..43d8229ed9 100644 --- a/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/config/FtpOutboundGatewayParserTests.java +++ b/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/config/FtpOutboundGatewayParserTests.java @@ -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 options = TestUtils.getPropertyValue(gateway, "options", Set.class); assertTrue(options.contains(Option.PRESERVE_TIMESTAMP)); gateway.handleMessage(new GenericMessage("foo")); + assertFalse(TestUtils.getPropertyValue(gateway, "requiresReply", Boolean.class)); assertEquals(1, adviceCalled); } diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayParser.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayParser.java index 864b264959..378b57aed6 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayParser.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayParser.java @@ -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)) { diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/StoredProcOutboundGatewayParser.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/StoredProcOutboundGatewayParser.java index ae73e34d29..2d72923c5b 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/StoredProcOutboundGatewayParser.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/config/StoredProcOutboundGatewayParser.java @@ -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)) { diff --git a/spring-integration-jdbc/src/main/resources/org/springframework/integration/jdbc/config/spring-integration-jdbc-3.0.xsd b/spring-integration-jdbc/src/main/resources/org/springframework/integration/jdbc/config/spring-integration-jdbc-3.0.xsd index 1282510588..78007adeb0 100644 --- a/spring-integration-jdbc/src/main/resources/org/springframework/integration/jdbc/config/spring-integration-jdbc-3.0.xsd +++ b/spring-integration-jdbc/src/main/resources/org/springframework/integration/jdbc/config/spring-integration-jdbc-3.0.xsd @@ -502,6 +502,15 @@ + + + + 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. + + + @@ -967,6 +976,15 @@ + + + + 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. + + + diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayParserTests.java b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayParserTests.java index e4ee01c087..00cdd7b42a 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayParserTests.java +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/JdbcOutboundGatewayParserTests.java @@ -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); diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/StoredProcOutboundGatewayParserTests.java b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/StoredProcOutboundGatewayParserTests.java index 83077d8a2b..02951a1da8 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/StoredProcOutboundGatewayParserTests.java +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/StoredProcOutboundGatewayParserTests.java @@ -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"); diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/handlingMapPayloadJdbcOutboundGatewayTest.xml b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/handlingMapPayloadJdbcOutboundGatewayTest.xml index fa1e44b942..6b2ff1ccc1 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/handlingMapPayloadJdbcOutboundGatewayTest.xml +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/handlingMapPayloadJdbcOutboundGatewayTest.xml @@ -26,7 +26,7 @@ + data-source="dataSource" requires-reply="false"/> diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/storedProcOutboundGatewayParserTest.xml b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/storedProcOutboundGatewayParserTest.xml index 2592380e0e..dfb4f2b367 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/storedProcOutboundGatewayParserTest.xml +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/storedProcOutboundGatewayParserTest.xml @@ -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"> diff --git a/spring-integration-jms/src/main/java/org/springframework/integration/jms/config/JmsOutboundGatewayParser.java b/spring-integration-jms/src/main/java/org/springframework/integration/jms/config/JmsOutboundGatewayParser.java index 96ec1cb690..d587dab3fe 100644 --- a/spring-integration-jms/src/main/java/org/springframework/integration/jms/config/JmsOutboundGatewayParser.java +++ b/spring-integration-jms/src/main/java/org/springframework/integration/jms/config/JmsOutboundGatewayParser.java @@ -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 { diff --git a/spring-integration-jms/src/main/resources/org/springframework/integration/jms/config/spring-integration-jms-3.0.xsd b/spring-integration-jms/src/main/resources/org/springframework/integration/jms/config/spring-integration-jms-3.0.xsd index 10c1ff8a21..dc4b0470b7 100644 --- a/spring-integration-jms/src/main/resources/org/springframework/integration/jms/config/spring-integration-jms-3.0.xsd +++ b/spring-integration-jms/src/main/resources/org/springframework/integration/jms/config/spring-integration-jms-3.0.xsd @@ -1065,6 +1065,15 @@ ]]> + + + + 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. + + + @@ -1469,4 +1478,4 @@ - \ No newline at end of file + diff --git a/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/JmsOutboundGatewayParserTests.java b/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/JmsOutboundGatewayParserTests.java index 31762490c6..deabab1b24 100644 --- a/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/JmsOutboundGatewayParserTests.java +++ b/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/JmsOutboundGatewayParserTests.java @@ -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 diff --git a/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/jmsOutboundGatewayWithDeliveryPersistent.xml b/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/jmsOutboundGatewayWithDeliveryPersistent.xml index f406f83c19..93630ff89d 100644 --- a/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/jmsOutboundGatewayWithDeliveryPersistent.xml +++ b/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/jmsOutboundGatewayWithDeliveryPersistent.xml @@ -14,7 +14,7 @@ http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd"> - + + auto-startup="false" + requires-reply="false"> diff --git a/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/jmsOutboundGatewayWithOrder.xml b/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/jmsOutboundGatewayWithOrder.xml index e7a6095ac1..def46dfc37 100644 --- a/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/jmsOutboundGatewayWithOrder.xml +++ b/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/jmsOutboundGatewayWithOrder.xml @@ -15,7 +15,7 @@ + order="99" requires-reply="true"/> diff --git a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/OperationInvokingOutboundGatewayParser.java b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/OperationInvokingOutboundGatewayParser.java index 7c78355656..0c2222d862 100644 --- a/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/OperationInvokingOutboundGatewayParser.java +++ b/spring-integration-jmx/src/main/java/org/springframework/integration/jmx/config/OperationInvokingOutboundGatewayParser.java @@ -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; } diff --git a/spring-integration-jmx/src/main/resources/org/springframework/integration/jmx/config/spring-integration-jmx-3.0.xsd b/spring-integration-jmx/src/main/resources/org/springframework/integration/jmx/config/spring-integration-jmx-3.0.xsd index fab13b0289..ceaae8ef8b 100644 --- a/spring-integration-jmx/src/main/resources/org/springframework/integration/jmx/config/spring-integration-jmx-3.0.xsd +++ b/spring-integration-jmx/src/main/resources/org/springframework/integration/jmx/config/spring-integration-jmx-3.0.xsd @@ -47,6 +47,15 @@ + + + + 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. + + + diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/OperationInvokingOutboundGatewayTests-context.xml b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/OperationInvokingOutboundGatewayTests-context.xml index 64482bbe5d..f412ab7bd6 100644 --- a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/OperationInvokingOutboundGatewayTests-context.xml +++ b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/OperationInvokingOutboundGatewayTests-context.xml @@ -29,18 +29,19 @@ object-name="org.springframework.integration.jmx.config:type=TestBean,name=testBeanGateway" operation-name="testWithReturn"> - + - - + + operation-name="test" + requires-reply="false"/> diff --git a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/OperationInvokingOutboundGatewayTests.java b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/OperationInvokingOutboundGatewayTests.java index b4e985b72c..618b54175c 100644 --- a/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/OperationInvokingOutboundGatewayTests.java +++ b/spring-integration-jmx/src/test/java/org/springframework/integration/jmx/config/OperationInvokingOutboundGatewayTests.java @@ -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 { diff --git a/spring-integration-jpa/src/main/java/org/springframework/integration/jpa/config/xml/AbstractJpaOutboundGatewayParser.java b/spring-integration-jpa/src/main/java/org/springframework/integration/jpa/config/xml/AbstractJpaOutboundGatewayParser.java index dc23e12eee..a6d662858b 100644 --- a/spring-integration-jpa/src/main/java/org/springframework/integration/jpa/config/xml/AbstractJpaOutboundGatewayParser.java +++ b/spring-integration-jpa/src/main/java/org/springframework/integration/jpa/config/xml/AbstractJpaOutboundGatewayParser.java @@ -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"); diff --git a/spring-integration-jpa/src/main/java/org/springframework/integration/jpa/outbound/JpaOutboundGatewayFactoryBean.java b/spring-integration-jpa/src/main/java/org/springframework/integration/jpa/outbound/JpaOutboundGatewayFactoryBean.java index 9700ba77de..f3c39fb9b7 100644 --- a/spring-integration-jpa/src/main/java/org/springframework/integration/jpa/outbound/JpaOutboundGatewayFactoryBean.java +++ b/spring-integration-jpa/src/main/java/org/springframework/integration/jpa/outbound/JpaOutboundGatewayFactoryBean.java @@ -70,6 +70,8 @@ public class JpaOutboundGatewayFactoryBean extends AbstractFactoryBean + + + + 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. + + + diff --git a/spring-integration-jpa/src/test/java/org/springframework/integration/jpa/config/xml/JpaOutboundGatewayParserTests.java b/spring-integration-jpa/src/test/java/org/springframework/integration/jpa/config/xml/JpaOutboundGatewayParserTests.java index ac331ff70a..06b9ff3141 100644 --- a/spring-integration-jpa/src/test/java/org/springframework/integration/jpa/config/xml/JpaOutboundGatewayParserTests.java +++ b/spring-integration-jpa/src/test/java/org/springframework/integration/jpa/config/xml/JpaOutboundGatewayParserTests.java @@ -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("foo")); - assertEquals(1, adviceCalled); + try { + jpaOutboundGateway.handleMessage(new GenericMessage("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; } diff --git a/spring-integration-jpa/src/test/java/org/springframework/integration/jpa/config/xml/JpaOutboundGatewayParserTests.xml b/spring-integration-jpa/src/test/java/org/springframework/integration/jpa/config/xml/JpaOutboundGatewayParserTests.xml index 2a468fc56e..3471e9e2f3 100644 --- a/spring-integration-jpa/src/test/java/org/springframework/integration/jpa/config/xml/JpaOutboundGatewayParserTests.xml +++ b/spring-integration-jpa/src/test/java/org/springframework/integration/jpa/config/xml/JpaOutboundGatewayParserTests.xml @@ -23,7 +23,8 @@ max-number-of-results="55" request-channel="in" reply-channel="out" - reply-timeout="100"/> + reply-timeout="100" + requires-reply="false"/> + reply-timeout="100" + requires-reply="false"/> - + + + + + + + diff --git a/spring-integration-rmi/src/main/resources/org/springframework/integration/rmi/config/spring-integration-rmi-3.0.xsd b/spring-integration-rmi/src/main/resources/org/springframework/integration/rmi/config/spring-integration-rmi-3.0.xsd index 63524faa44..fe601f2fca 100644 --- a/spring-integration-rmi/src/main/resources/org/springframework/integration/rmi/config/spring-integration-rmi-3.0.xsd +++ b/spring-integration-rmi/src/main/resources/org/springframework/integration/rmi/config/spring-integration-rmi-3.0.xsd @@ -101,6 +101,15 @@ + + + + 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. + + + diff --git a/spring-integration-rmi/src/test/java/org/springframework/integration/rmi/config/RmiOutboundGatewayParserTests.java b/spring-integration-rmi/src/test/java/org/springframework/integration/rmi/config/RmiOutboundGatewayParserTests.java index d6043ce61b..a7727dbc67 100644 --- a/spring-integration-rmi/src/test/java/org/springframework/integration/rmi/config/RmiOutboundGatewayParserTests.java +++ b/spring-integration-rmi/src/test/java/org/springframework/integration/rmi/config/RmiOutboundGatewayParserTests.java @@ -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("test")); Message result = testChannel.receive(1000); assertNotNull(result); diff --git a/spring-integration-rmi/src/test/java/org/springframework/integration/rmi/config/rmiOutboundGatewayParserTests.xml b/spring-integration-rmi/src/test/java/org/springframework/integration/rmi/config/rmiOutboundGatewayParserTests.xml index 8254ef1ccb..5d966d2cd6 100644 --- a/spring-integration-rmi/src/test/java/org/springframework/integration/rmi/config/rmiOutboundGatewayParserTests.xml +++ b/spring-integration-rmi/src/test/java/org/springframework/integration/rmi/config/rmiOutboundGatewayParserTests.xml @@ -23,6 +23,7 @@ @@ -30,7 +31,7 @@ - + diff --git a/spring-integration-sftp/src/main/resources/org/springframework/integration/sftp/config/spring-integration-sftp-3.0.xsd b/spring-integration-sftp/src/main/resources/org/springframework/integration/sftp/config/spring-integration-sftp-3.0.xsd index 0387e63e7c..b8baa78a12 100644 --- a/spring-integration-sftp/src/main/resources/org/springframework/integration/sftp/config/spring-integration-sftp-3.0.xsd +++ b/spring-integration-sftp/src/main/resources/org/springframework/integration/sftp/config/spring-integration-sftp-3.0.xsd @@ -432,6 +432,15 @@ + + + + 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. + + + diff --git a/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/config/SftpOutboundGatewayParserTests-context.xml b/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/config/SftpOutboundGatewayParserTests-context.xml index bbb8f8b56a..03434774fe 100644 --- a/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/config/SftpOutboundGatewayParserTests-context.xml +++ b/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/config/SftpOutboundGatewayParserTests-context.xml @@ -43,6 +43,7 @@ command-options="-P" expression="payload" order="2" + requires-reply="false" /> diff --git a/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/config/SftpOutboundGatewayParserTests.java b/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/config/SftpOutboundGatewayParserTests.java index 165d8f4d69..de91c54377 100644 --- a/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/config/SftpOutboundGatewayParserTests.java +++ b/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/config/SftpOutboundGatewayParserTests.java @@ -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 options = TestUtils.getPropertyValue(gateway, "options", Set.class); assertTrue(options.contains(Option.PRESERVE_TIMESTAMP)); diff --git a/spring-integration-ws/src/main/java/org/springframework/integration/ws/config/WebServiceOutboundGatewayParser.java b/spring-integration-ws/src/main/java/org/springframework/integration/ws/config/WebServiceOutboundGatewayParser.java index 431dbd2c56..ccb8d77e7d 100644 --- a/spring-integration-ws/src/main/java/org/springframework/integration/ws/config/WebServiceOutboundGatewayParser.java +++ b/spring-integration-ws/src/main/java/org/springframework/integration/ws/config/WebServiceOutboundGatewayParser.java @@ -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); diff --git a/spring-integration-ws/src/main/resources/org/springframework/integration/ws/config/spring-integration-ws-3.0.xsd b/spring-integration-ws/src/main/resources/org/springframework/integration/ws/config/spring-integration-ws-3.0.xsd index 156d307e3a..2c87344730 100644 --- a/spring-integration-ws/src/main/resources/org/springframework/integration/ws/config/spring-integration-ws-3.0.xsd +++ b/spring-integration-ws/src/main/resources/org/springframework/integration/ws/config/spring-integration-ws-3.0.xsd @@ -87,6 +87,16 @@ ]]> + + + + 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'). + + + @@ -456,4 +468,4 @@ this list can also be simple patterns to be matched against the header names (e. - \ No newline at end of file + diff --git a/spring-integration-ws/src/test/java/org/springframework/integration/ws/config/WebServiceOutboundGatewayParserTests.java b/spring-integration-ws/src/test/java/org/springframework/integration/ws/config/WebServiceOutboundGatewayParserTests.java index 6f32183bcd..aaed1d3cba 100644 --- a/spring-integration-ws/src/test/java/org/springframework/integration/ws/config/WebServiceOutboundGatewayParserTests.java +++ b/spring-integration-ws/src/test/java/org/springframework/integration/ws/config/WebServiceOutboundGatewayParserTests.java @@ -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 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 diff --git a/spring-integration-ws/src/test/java/org/springframework/integration/ws/config/simpleWebServiceOutboundGatewayParserTests.xml b/spring-integration-ws/src/test/java/org/springframework/integration/ws/config/simpleWebServiceOutboundGatewayParserTests.xml index 80a615ded9..49485a95ce 100644 --- a/spring-integration-ws/src/test/java/org/springframework/integration/ws/config/simpleWebServiceOutboundGatewayParserTests.xml +++ b/spring-integration-ws/src/test/java/org/springframework/integration/ws/config/simpleWebServiceOutboundGatewayParserTests.xml @@ -31,10 +31,11 @@ mapped-request-headers="testRequest" mapped-reply-headers="testReply"/> - + ignore-empty-responses="false" + requires-reply="true"/> . +
+ 'requires-reply' Attribute for Outbound Gateways + + All Outbound Gateways (e.g. <jdbc:outbound-gateway/> or <jms:outbound-gateway/>) + are designed for 'request-reply' scenarios. A response is expected from the external service and + will be published to the reply-channel, or the replyChannel message header. + However, there are some cases where the external system might not always return a + result, e.g. a <jdbc:outbound-gateway/>, when a SELECT ends with an empty ResultSet + or, say, a Web Service is One-Way. An option is therefore needed to configure whether or not a + reply is required. + For this purpose, the requires-reply attribute has been introduced for Outbound Gateway components. + In most cases, the default value for requires-reply is true and, if there is not any result, + a ReplyRequiredException will be thrown. Changing the value to false + means that, if an external service doesn't return anything, the message-flow will end at that point, + similar to an Outbound Channel Adapter. + + + The WebService outbound gateway has an additional attribute ignore-empty-responses; 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 requires-reply attribute. + requires-reply is false by default for the WebService outbound gateway. + + + Note, the requiresReply property was previously present in the AbstractReplyProducingMessageHandler + but set to false, and there wasn't any way to configure it on Outbound Gateways using the XML namespace. + + + 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 requires-reply to false. + +