INT-3944: Async JMS Outbound Gateway
JIRA: https://jira.spring.io/browse/INT-3944 Polishing (PR comments) and Doc Polish Polishing - PR Comments Remove custom `async` boolean in favor of the now public setter. Add exception to `JmsException` hierarchy. INT-3944: Polishing * Rename `asyncReplySupported` just to `async`. As well as its getter and setter. Plus fix docs on the matter * Polishing for the `JmsOutboundGateway` according PR comments * Rework `JmsOutboundGateway` to return `AbstractIntegrationMessageBuilder` instead of `Message` since `AbstractMessageProducingHandler` rebuilds `Message` for a new one to copy headers from request * Add `getPayload()` and `getHeaders()` to the `AbstractIntegrationMessageBuilder` to make the `Routing Slip` users happy, when the `AbstractIntegrationMessageBuilder` is pushed to the `Routing Slip path` function * Fix race condition in the `ChatMessageListeningEndpointTests`: the `stanza` parsing is done in the different Thread. Doc Polishing (Routing Slip) Fix timing issue in the `LastModifiedFileListFilterTests`: `Thread.sleep()` not always reflects the reality. Switch to the "past simulation" via explicit `File.setLastModified()`
This commit is contained in:
committed by
Artem Bilan
parent
0fd72d2d18
commit
4bfcdb9dfa
@@ -86,6 +86,7 @@ public class JmsOutboundGatewayParserTests {
|
||||
accessor = new DirectFieldAccessor(gateway);
|
||||
int deliveryMode = (Integer)accessor.getPropertyValue("deliveryMode");
|
||||
assertEquals(DeliveryMode.PERSISTENT, deliveryMode);
|
||||
assertTrue(TestUtils.getPropertyValue(gateway, "async", Boolean.class));
|
||||
DefaultMessageListenerContainer container = TestUtils.getPropertyValue(gateway, "replyContainer",
|
||||
DefaultMessageListenerContainer.class);
|
||||
assertEquals(4, TestUtils.getPropertyValue(container, "concurrentConsumers"));
|
||||
@@ -116,6 +117,7 @@ public class JmsOutboundGatewayParserTests {
|
||||
"jmsOutboundGatewayWithDeliveryPersistent.xml", this.getClass());
|
||||
EventDrivenConsumer endpoint = (EventDrivenConsumer) context.getBean("advised");
|
||||
JmsOutboundGateway gateway = TestUtils.getPropertyValue(endpoint, "handler", JmsOutboundGateway.class);
|
||||
assertFalse(TestUtils.getPropertyValue(gateway, "async", Boolean.class));
|
||||
gateway.handleMessage(new GenericMessage<String>("foo"));
|
||||
assertEquals(1, adviceCalled);
|
||||
assertEquals(3, TestUtils.getPropertyValue(gateway, "replyContainer.sessionAcknowledgeMode"));
|
||||
@@ -287,13 +289,17 @@ public class JmsOutboundGatewayParserTests {
|
||||
|
||||
|
||||
public interface SampleGateway{
|
||||
|
||||
String echo(String value);
|
||||
|
||||
}
|
||||
|
||||
public static class SampleService{
|
||||
|
||||
public String echo(String value){
|
||||
return value.toUpperCase();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class FooAdvice extends AbstractRequestHandlerAdvice {
|
||||
@@ -305,4 +311,5 @@ public class JmsOutboundGatewayParserTests {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
|
||||
http://www.springframework.org/schema/integration/jms
|
||||
http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd">
|
||||
|
||||
|
||||
<context:property-placeholder properties-ref="props"/>
|
||||
|
||||
|
||||
<util:properties id="props">
|
||||
<prop key="jmsAcknowledgeModeTransacted">transacted</prop>
|
||||
<prop key="jmsAcknowledgeModeDupsOk">dups-ok</prop>
|
||||
</util:properties>
|
||||
|
||||
|
||||
<si:channel id="requestChannel"/>
|
||||
|
||||
<jms:outbound-gateway id="jmsGateway"
|
||||
@@ -31,6 +31,8 @@
|
||||
request-channel="requestChannel"
|
||||
delivery-persistent="true"
|
||||
idle-reply-listener-timeout="1234"
|
||||
async="true"
|
||||
correlation-key="JMSCorrelationID"
|
||||
auto-startup="false">
|
||||
<jms:reply-listener
|
||||
acknowledge="${jmsAcknowledgeModeTransacted}"
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.jms.request_reply;
|
||||
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import javax.jms.JMSException;
|
||||
import javax.jms.Message;
|
||||
import javax.jms.Session;
|
||||
import javax.jms.TextMessage;
|
||||
|
||||
import org.apache.activemq.ActiveMQConnectionFactory;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.config.EnableIntegration;
|
||||
import org.springframework.integration.jms.JmsOutboundGateway;
|
||||
import org.springframework.integration.jms.JmsTimeoutException;
|
||||
import org.springframework.jms.connection.CachingConnectionFactory;
|
||||
import org.springframework.jms.core.JmsTemplate;
|
||||
import org.springframework.jms.core.MessageCreator;
|
||||
import org.springframework.jms.support.JmsHeaders;
|
||||
import org.springframework.messaging.MessagingException;
|
||||
import org.springframework.messaging.support.ErrorMessage;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* @author Gary Russell
|
||||
* @since 4.3
|
||||
*
|
||||
*/
|
||||
@ContextConfiguration
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@DirtiesContext
|
||||
public class AsyncGatewayTests {
|
||||
|
||||
@Autowired
|
||||
private CachingConnectionFactory ccf;
|
||||
|
||||
@Autowired
|
||||
private JmsOutboundGateway gateway1;
|
||||
|
||||
@Autowired
|
||||
private JmsOutboundGateway gateway2;
|
||||
|
||||
@Test
|
||||
public void testWithReply() throws Exception {
|
||||
QueueChannel replies = new QueueChannel();
|
||||
this.gateway1.setOutputChannel(replies);
|
||||
this.gateway1.start();
|
||||
this.gateway1.handleMessage(MessageBuilder.withPayload("foo")
|
||||
.setHeader(JmsHeaders.CORRELATION_ID, "baz")// make sure it's restored in case we're from an upstream gw
|
||||
.build());
|
||||
JmsTemplate template = new JmsTemplate(this.ccf);
|
||||
template.setReceiveTimeout(10000);
|
||||
final Message received = template.receive("asyncTest1");
|
||||
assertNotNull(received);
|
||||
template.send(received.getJMSReplyTo(), new MessageCreator() {
|
||||
|
||||
@Override
|
||||
public Message createMessage(Session session) throws JMSException {
|
||||
TextMessage textMessage = session.createTextMessage("bar");
|
||||
textMessage.setJMSCorrelationID(received.getJMSCorrelationID());
|
||||
return textMessage;
|
||||
}
|
||||
|
||||
});
|
||||
org.springframework.messaging.Message<?> reply = replies.receive(10000);
|
||||
assertNotNull(reply);
|
||||
assertEquals("bar", reply.getPayload());
|
||||
assertEquals("baz", reply.getHeaders().get(JmsHeaders.CORRELATION_ID));
|
||||
this.gateway1.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithTimeout() throws Exception {
|
||||
QueueChannel errors = new QueueChannel();
|
||||
this.gateway2.setOutputChannel(errors);
|
||||
this.gateway2.start();
|
||||
this.gateway2.handleMessage(MessageBuilder.withPayload("foo").setErrorChannel(errors).build());
|
||||
JmsTemplate template = new JmsTemplate(this.ccf);
|
||||
final Message received = template.receive("asyncTest3");
|
||||
assertNotNull(received);
|
||||
org.springframework.messaging.Message<?> error = errors.receive(10000);
|
||||
assertNotNull(error);
|
||||
assertThat(error, instanceOf(ErrorMessage.class));
|
||||
assertThat(error.getPayload(), instanceOf(MessagingException.class));
|
||||
assertThat(((MessagingException) error.getPayload()).getCause(), instanceOf(JmsTimeoutException.class));
|
||||
assertEquals("foo", ((MessagingException) error.getPayload()).getFailedMessage().getPayload());
|
||||
this.gateway1.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DirtiesContext
|
||||
public void testWithTimeoutNoReplyRequired() throws Exception {
|
||||
QueueChannel errors = new QueueChannel();
|
||||
this.gateway2.setOutputChannel(errors);
|
||||
this.gateway2.setRequiresReply(false);
|
||||
this.gateway2.start();
|
||||
this.gateway2.handleMessage(MessageBuilder.withPayload("foo").setErrorChannel(errors).build());
|
||||
JmsTemplate template = new JmsTemplate(this.ccf);
|
||||
final Message received = template.receive("asyncTest3");
|
||||
assertNotNull(received);
|
||||
org.springframework.messaging.Message<?> error = errors.receive(1000);
|
||||
assertNull(error);
|
||||
this.gateway1.stop();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableIntegration
|
||||
public static class Config {
|
||||
|
||||
@Bean
|
||||
public CachingConnectionFactory ccf() {
|
||||
return new CachingConnectionFactory(
|
||||
new ActiveMQConnectionFactory("vm://localhosti?broker.persistent=false"));
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JmsOutboundGateway gateway1() {
|
||||
JmsOutboundGateway gateway = new JmsOutboundGateway();
|
||||
gateway.setUseReplyContainer(true);
|
||||
gateway.setConnectionFactory(ccf());
|
||||
gateway.setRequestDestinationName("asyncTest1");
|
||||
gateway.setReplyDestinationName("asyncTest2");
|
||||
gateway.setRequiresReply(true);
|
||||
gateway.setReceiveTimeout(10000);
|
||||
gateway.setAsync(true);
|
||||
gateway.setCorrelationKey("JMSCorrelationID");
|
||||
return gateway;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JmsOutboundGateway gateway2() {
|
||||
JmsOutboundGateway gateway = new JmsOutboundGateway();
|
||||
gateway.setUseReplyContainer(true);
|
||||
gateway.setConnectionFactory(ccf());
|
||||
gateway.setRequestDestinationName("asyncTest3");
|
||||
gateway.setReplyDestinationName("asyncTest4");
|
||||
gateway.setRequiresReply(true);
|
||||
gateway.setReceiveTimeout(10);
|
||||
gateway.setAsync(true);
|
||||
gateway.setCorrelationKey("JMSCorrelationID");
|
||||
return gateway;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user