INT-3313: Fix JMS-outbound requires-reply Logic
JIRA: https://jira.springsource.org/browse/INT-3313 Previously, when `requires-reply="false"` on a `<jms:outbound-gateway/>` a `null` reply caused a `MessageTimeoutException`, instead of quiet ending of flow. Conflicts: spring-integration-jms/src/test/java/org/springframework/integration/jms/JmsOutboundInsideChainTests.java Resolved.
This commit is contained in:
committed by
Gary Russell
parent
1de46a8bdd
commit
ee73515047
@@ -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) {
|
||||
|
||||
@@ -18,12 +18,33 @@
|
||||
<jms:outbound-channel-adapter destination="testQueue"/>
|
||||
</int:chain>
|
||||
|
||||
<int:channel id="repliesChannel">
|
||||
<int:queue/>
|
||||
</int:channel>
|
||||
|
||||
<int:chain input-channel="outboundGatewayChainChannel" output-channel="repliesChannel">
|
||||
<jms:outbound-gateway request-destination="testQueue2" receive-timeout="1000" requires-reply="false"/>
|
||||
</int:chain>
|
||||
|
||||
|
||||
<jms:message-driven-channel-adapter destination="testQueue" channel="receiveChannel"/>
|
||||
|
||||
<jms:inbound-gateway request-channel="inboundJmsChannel" request-destination="testQueue2"/>
|
||||
|
||||
<bean id="jmsRequiresReplyFlag" class="java.util.concurrent.atomic.AtomicInteger"/>
|
||||
|
||||
<int:chain input-channel="inboundJmsChannel">
|
||||
<int:service-activator expression="@jmsRequiresReplyFlag.getAndIncrement() % 2 == 0 ? payload : null"/>
|
||||
</int:chain>
|
||||
|
||||
<bean id="testQueue" class="org.apache.activemq.command.ActiveMQQueue">
|
||||
<constructor-arg value="test.queue"/>
|
||||
</bean>
|
||||
|
||||
<bean id="testQueue2" class="org.apache.activemq.command.ActiveMQQueue">
|
||||
<constructor-arg value="test.queue2"/>
|
||||
</bean>
|
||||
|
||||
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
|
||||
<property name="brokerURL" value="vm://localhost?broker.persistent=false"/>
|
||||
</bean>
|
||||
|
||||
@@ -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<String> 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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -315,7 +315,8 @@
|
||||
request-destination-expression=""]]><co id="jog200" /><![CDATA[
|
||||
request-destination-name=""]]><co id="jog210" /><![CDATA[
|
||||
request-pub-sub-domain=""]]><co id="jog220" /><![CDATA[
|
||||
time-to-live="">]]><co id="jog230" /><![CDATA[
|
||||
time-to-live=""]]><co id="jog230" /><![CDATA[
|
||||
requires-reply="">]]><co id="jog231" /><![CDATA[
|
||||
<int-jms:reply-listener />]]><co id="jog240" /><![CDATA[
|
||||
</int-jms:outbound-gateway>]]></programlisting>
|
||||
<calloutlist>
|
||||
@@ -497,6 +498,18 @@
|
||||
This setting will only take effect if <code>explicit-qos-enabled</code> is <code>true</code>.
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="jog231">
|
||||
<para>
|
||||
Specify whether this outbound gateway must return a non-null value. This value is
|
||||
<code>true</code> by default, and a <classname>MessageTimeoutException</classname> will be thrown when
|
||||
the underlying service does not return a value after the <code>receive-timeout</code>.
|
||||
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 <code><int-jms:outbound-channel-adapter/></code>
|
||||
instead of a <code><int-jms:outbound-gateway/></code> with <code>requires-reply="false"</code>.
|
||||
With the latter, the sending thread is blocked, waiting for a reply for the <code>receive-timeout</code>
|
||||
period.
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="jog240">
|
||||
<para>
|
||||
When this element is included, replies are received by a <interfacename>MessageListenerContainer
|
||||
|
||||
Reference in New Issue
Block a user