diff --git a/spring-integration-jms/src/main/java/org/springframework/integration/jms/JmsOutboundGateway.java b/spring-integration-jms/src/main/java/org/springframework/integration/jms/JmsOutboundGateway.java index 38a05ac5da..1140abd2f7 100644 --- a/spring-integration-jms/src/main/java/org/springframework/integration/jms/JmsOutboundGateway.java +++ b/spring-integration-jms/src/main/java/org/springframework/integration/jms/JmsOutboundGateway.java @@ -142,6 +142,8 @@ public class JmsOutboundGateway extends AbstractReplyProducingMessageHandler imp private final Object lifeCycleMonitor = new Object(); + private volatile boolean requiresReply; + /** * Set whether message delivery should be persistent or non-persistent, * specified as a boolean value ("true" or "false"). This will set the delivery @@ -389,6 +391,12 @@ public class JmsOutboundGateway extends AbstractReplyProducingMessageHandler imp this.useReplyContainer = useReplyContainer; } + @Override + public void setRequiresReply(boolean requiresReply) { + super.setRequiresReply(requiresReply); + this.requiresReply = requiresReply; + } + private Destination determineRequestDestination(Message message, Session session) throws JMSException { if (this.requestDestination != null) { return this.requestDestination; @@ -617,8 +625,13 @@ public class JmsOutboundGateway extends AbstractReplyProducingMessageHandler imp jmsReply = this.sendAndReceiveWithContainer(requestMessage); } if (jmsReply == null) { - throw new MessageTimeoutException(message, - "failed to receive JMS response within timeout of: " + this.receiveTimeout + "ms"); + if (this.requiresReply) { + throw new MessageTimeoutException(message, + "failed to receive JMS response within timeout of: " + this.receiveTimeout + "ms"); + } + else { + return null; + } } Object result = jmsReply; if (this.extractReplyPayload) { diff --git a/spring-integration-jms/src/test/java/org/springframework/integration/jms/JmsOutboundInsideChainTests-context.xml b/spring-integration-jms/src/test/java/org/springframework/integration/jms/JmsOutboundInsideChainTests-context.xml index 27c827d8a0..746624cd58 100644 --- a/spring-integration-jms/src/test/java/org/springframework/integration/jms/JmsOutboundInsideChainTests-context.xml +++ b/spring-integration-jms/src/test/java/org/springframework/integration/jms/JmsOutboundInsideChainTests-context.xml @@ -18,12 +18,33 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-integration-jms/src/test/java/org/springframework/integration/jms/JmsOutboundInsideChainTests.java b/spring-integration-jms/src/test/java/org/springframework/integration/jms/JmsOutboundInsideChainTests.java index 3cbe61cb31..4bb0d53f98 100644 --- a/spring-integration-jms/src/test/java/org/springframework/integration/jms/JmsOutboundInsideChainTests.java +++ b/spring-integration-jms/src/test/java/org/springframework/integration/jms/JmsOutboundInsideChainTests.java @@ -16,33 +16,58 @@ package org.springframework.integration.jms; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + import org.junit.Test; -import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.integration.Message; import org.springframework.integration.MessageChannel; import org.springframework.integration.core.PollableChannel; import org.springframework.integration.support.MessageBuilder; - -import static org.junit.Assert.*; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * //INT-2275 * * @author Artem Bilan */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration public class JmsOutboundInsideChainTests { + @Autowired + private MessageChannel outboundChainChannel; + + @Autowired + private PollableChannel receiveChannel; + + @Autowired + private MessageChannel outboundGatewayChainChannel; + + @Autowired + private PollableChannel repliesChannel; + @Test public void testJmsOutboundChannelInsideChain(){ - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("JmsOutboundInsideChainTests-context.xml", getClass()); - PollableChannel receiveChannel = context.getBean("receiveChannel", PollableChannel.class); - MessageChannel outboundChainChannel = context.getBean("outboundChainChannel", MessageChannel.class); String testString = "test"; Message shippedMessage = MessageBuilder.withPayload(testString).build(); - outboundChainChannel.send(shippedMessage); - Message receivedMessage = receiveChannel.receive(); + this.outboundChainChannel.send(shippedMessage); + Message receivedMessage = this.receiveChannel.receive(2000); assertEquals(testString, receivedMessage.getPayload()); - context.close(); + } + + @Test + public void testJmsOutboundGatewayRequiresReply(){ + this.outboundGatewayChainChannel.send(MessageBuilder.withPayload("test").build()); + assertNotNull(this.repliesChannel.receive(2000)); + + this.outboundGatewayChainChannel.send(MessageBuilder.withPayload("test").build()); + assertNull(this.repliesChannel.receive(2000)); } } diff --git a/src/reference/docbook/jms.xml b/src/reference/docbook/jms.xml index f8b8c5169d..7eb48b5bf8 100644 --- a/src/reference/docbook/jms.xml +++ b/src/reference/docbook/jms.xml @@ -315,7 +315,8 @@ request-destination-expression=""]]>]]>]]>]]>]]> @@ -497,6 +498,18 @@ This setting will only take effect if explicit-qos-enabled is true. + + + Specify whether this outbound gateway must return a non-null value. This value is + true by default, and a MessageTimeoutException will be thrown when + the underlying service does not return a value after the receive-timeout. + Note, it is important to keep in mind that, if the service is never expected + to return a reply, it would be better to use a <int-jms:outbound-channel-adapter/> + instead of a <int-jms:outbound-gateway/> with requires-reply="false". + With the latter, the sending thread is blocked, waiting for a reply for the receive-timeout + period. + + When this element is included, replies are received by a MessageListenerContainer