INT-3405 JMSCorrelationID* for JMSOutboundGateway
JIRA: https://jira.spring.io/browse/INT-3405 Disallow `JMSCorrelationID*` with reply-container Polishing; Docs, Test
This commit is contained in:
committed by
Gary Russell
parent
c5500a82fd
commit
cda5a07aad
@@ -318,12 +318,18 @@ public class JmsOutboundGateway extends AbstractReplyProducingMessageHandler imp
|
||||
* the receiver of the JMS Message would expect to represent the CorrelationID.
|
||||
* When waiting for the reply Message, a MessageSelector will be configured
|
||||
* to match this property name and the UUID value that was sent in the request.
|
||||
* If this value is NULL (the default) then the reply consumer's MessageSelector
|
||||
* <p>If this value is NULL (the default) then the reply consumer's MessageSelector
|
||||
* will be expecting the JMSCorrelationID to equal the Message ID of the request.
|
||||
* If you want to store the outbound correlation UUID value in the actual
|
||||
* <p>If you want to store the outbound correlation UUID value in the actual
|
||||
* JMSCorrelationID property, then set this value to "JMSCorrelationID".
|
||||
* However, any other value will be treated as a JMS String Property.
|
||||
*
|
||||
* <p>If you want to use and existing "JMSCorrelationID" from the inbound message
|
||||
* (mapped from 'jms_correlationId'),
|
||||
* you can set this property to "JMSCorrelationID*" with the trailing asterisk.
|
||||
* If the message has a correlation id, it will be used, otherwise a new one will
|
||||
* be set in the 'JMSCorrelationID' header. However, understand that the
|
||||
* gateway has no means to ensure uniqueness and unexpected side effects can
|
||||
* occur if the correlation id is not unique.
|
||||
* <p>This setting is not allowed if a reply listener is used.
|
||||
* @param correlationKey The correlation key.
|
||||
*/
|
||||
public void setCorrelationKey(String correlationKey) {
|
||||
@@ -530,6 +536,9 @@ public class JmsOutboundGateway extends AbstractReplyProducingMessageHandler imp
|
||||
this.useReplyContainer = false;
|
||||
}
|
||||
if (this.useReplyContainer) {
|
||||
Assert.state(!"JMSCorrelationID*".equals(this.correlationKey),
|
||||
"Using an existing 'JMSCorrelationID' mapped from the 'requestMessage' ('JMSCorrelationID*') " +
|
||||
"can't be used when using a 'reply-container'");
|
||||
GatewayReplyListenerContainer container = new GatewayReplyListenerContainer();
|
||||
setContainerProperties(container);
|
||||
container.afterPropertiesSet();
|
||||
@@ -715,13 +724,13 @@ public class JmsOutboundGateway extends AbstractReplyProducingMessageHandler imp
|
||||
}
|
||||
Destination requestDestination = this.determineRequestDestination(requestMessage, session);
|
||||
|
||||
/*
|
||||
* Remove any existing correlation id that was mapped from the inbound message
|
||||
* (it will be restored by normal ARPMH header processing).
|
||||
*/
|
||||
jmsRequest.setJMSCorrelationID(null);
|
||||
javax.jms.Message reply = null;
|
||||
if (this.correlationKey == null) {
|
||||
/*
|
||||
* Remove any existing correlation id that was mapped from the inbound message
|
||||
* (it will be restored in the reply by normal ARPMH header processing).
|
||||
*/
|
||||
jmsRequest.setJMSCorrelationID(null);
|
||||
reply = doSendAndReceiveAsyncDefaultCorrelation(requestDestination, jmsRequest, session, priority);
|
||||
}
|
||||
else {
|
||||
@@ -796,17 +805,24 @@ public class JmsOutboundGateway extends AbstractReplyProducingMessageHandler imp
|
||||
MessageConsumer messageConsumer = null;
|
||||
try {
|
||||
messageProducer = session.createProducer(requestDestination);
|
||||
String correlationId = UUID.randomUUID().toString().replaceAll("'", "''");
|
||||
Assert.state(this.correlationKey != null, "correlationKey must not be null");
|
||||
String messageSelector = null;
|
||||
if (this.correlationKey.equals("JMSCorrelationID")) {
|
||||
jmsRequest.setJMSCorrelationID(correlationId);
|
||||
messageSelector = "JMSCorrelationID = '" + correlationId + "'";
|
||||
if (!this.correlationKey.equals("JMSCorrelationID*") || jmsRequest.getJMSCorrelationID() == null) {
|
||||
String correlationId = UUID.randomUUID().toString().replaceAll("'", "''");
|
||||
if (this.correlationKey.equals("JMSCorrelationID")) {
|
||||
jmsRequest.setJMSCorrelationID(correlationId);
|
||||
messageSelector = "JMSCorrelationID = '" + correlationId + "'";
|
||||
}
|
||||
else {
|
||||
jmsRequest.setStringProperty(this.correlationKey, correlationId);
|
||||
jmsRequest.setJMSCorrelationID(null);
|
||||
messageSelector = this.correlationKey + " = '" + correlationId + "'";
|
||||
}
|
||||
}
|
||||
else {
|
||||
jmsRequest.setStringProperty(this.correlationKey, correlationId);
|
||||
messageSelector = this.correlationKey + " = '" + correlationId + "'";
|
||||
messageSelector = "JMSCorrelationID = '" + jmsRequest.getJMSCorrelationID() + "'";
|
||||
}
|
||||
|
||||
messageConsumer = session.createConsumer(replyTo, messageSelector);
|
||||
this.sendRequestMessage(jmsRequest, messageProducer, priority);
|
||||
return this.receiveReplyMessage(messageConsumer);
|
||||
@@ -875,6 +891,11 @@ public class JmsOutboundGateway extends AbstractReplyProducingMessageHandler imp
|
||||
}
|
||||
else {
|
||||
jmsRequest.setStringProperty(this.correlationKey, correlationId);
|
||||
/*
|
||||
* Remove any existing correlation id that was mapped from the inbound message
|
||||
* (it will be restored in the reply by normal ARPMH header processing).
|
||||
*/
|
||||
jmsRequest.setJMSCorrelationID(null);
|
||||
}
|
||||
LinkedBlockingQueue<javax.jms.Message> replyQueue = new LinkedBlockingQueue<javax.jms.Message>(1);
|
||||
if (logger.isDebugEnabled()) {
|
||||
@@ -1018,7 +1039,9 @@ public class JmsOutboundGateway extends AbstractReplyProducingMessageHandler imp
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace(this.getComponentName() + " Received " + message);
|
||||
}
|
||||
if (this.correlationKey == null || this.correlationKey.equals("JMSCorrelationID")) {
|
||||
if (this.correlationKey == null ||
|
||||
this.correlationKey.equals("JMSCorrelationID") ||
|
||||
this.correlationKey.equals("JMSCorrelationID*")) {
|
||||
correlationId = message.getJMSCorrelationID();
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -13,24 +13,30 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.jms.request_reply;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.integration.gateway.RequestReplyExchanger;
|
||||
import org.springframework.integration.jms.ActiveMQMultiContextTests;
|
||||
import org.springframework.integration.jms.JmsHeaders;
|
||||
import org.springframework.integration.jms.JmsOutboundGateway;
|
||||
import org.springframework.integration.jms.config.ActiveMqTestUtils;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.integration.test.support.LongRunningIntegrationTest;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.messaging.Message;
|
||||
/**
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Gary Russell
|
||||
* @author Artem Bilan
|
||||
*/
|
||||
public class RequestReplyScenariosWithCorrelationKeyProvidedTests extends ActiveMQMultiContextTests {
|
||||
|
||||
@@ -59,6 +65,21 @@ public class RequestReplyScenariosWithCorrelationKeyProvidedTests extends Active
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void messageCorrelationBasedOnProvidedJMSCorrelationID() throws Exception{
|
||||
ActiveMqTestUtils.prepare();
|
||||
|
||||
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("explicit-correlation-key.xml", this.getClass());
|
||||
RequestReplyExchanger gateway = context.getBean("existingCorrelationKeyGatewayB", RequestReplyExchanger.class);
|
||||
|
||||
String correlationId = UUID.randomUUID().toString().replaceAll("'", "''");
|
||||
Message<?> result = gateway.exchange(MessageBuilder.withPayload("foo")
|
||||
.setHeader(JmsHeaders.CORRELATION_ID, correlationId)
|
||||
.build());
|
||||
assertEquals(correlationId, result.getHeaders().get("receivedCorrelationId"));
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void messageCorrelationBasedCustomCorrelationKeyDelayedReplies() throws Exception{
|
||||
ActiveMqTestUtils.prepare();
|
||||
|
||||
@@ -38,14 +38,39 @@
|
||||
</bean>
|
||||
|
||||
<int-jms:inbound-gateway request-channel="requestInB"
|
||||
request-destination="explicitCorrelationJmsOutB"
|
||||
correlation-key="JMSCorrelationID"
|
||||
connection-factory="connectionFactory"/>
|
||||
request-destination="explicitCorrelationJmsOutB"
|
||||
correlation-key="JMSCorrelationID"
|
||||
connection-factory="connectionFactory"/>
|
||||
|
||||
<int:transformer input-channel="requestInB" expression="payload"/>
|
||||
|
||||
<!-- -->
|
||||
|
||||
<int:gateway id="existingCorrelationKeyGatewayB" default-request-channel="existingCorrelationInB"/>
|
||||
|
||||
<int-jms:outbound-gateway request-channel="existingCorrelationInB"
|
||||
connection-factory="connectionFactory"
|
||||
request-destination="existingCorrelationJmsOutB"
|
||||
correlation-key="JMSCorrelationID*"/>
|
||||
|
||||
<bean id="existingCorrelationJmsOutB" class="org.apache.activemq.command.ActiveMQQueue">
|
||||
<constructor-arg value="existingCorrelationJmsOutB"/>
|
||||
</bean>
|
||||
|
||||
<int-jms:inbound-gateway request-channel="requestExistingCorrelationInB"
|
||||
request-destination="existingCorrelationJmsOutB"
|
||||
correlation-key="JMSCorrelationID"
|
||||
connection-factory="connectionFactory"/>
|
||||
|
||||
<int:chain input-channel="requestExistingCorrelationInB" >
|
||||
<int:header-enricher>
|
||||
<int:header name="receivedCorrelationId" expression="headers['jms_correlationId']"/>
|
||||
</int:header-enricher>
|
||||
<int:transformer expression="payload"/>
|
||||
</int:chain>
|
||||
|
||||
<!-- -->
|
||||
|
||||
<int:gateway id="explicitCorrelationKeyGatewayC" default-request-channel="explicitCorrelationInC"/>
|
||||
|
||||
<int-jms:outbound-gateway id="outGateway" request-channel="explicitCorrelationInC"
|
||||
|
||||
@@ -374,6 +374,19 @@
|
||||
</code> is used, the correlation-key MUST be specified if an explicit <code>reply-destination</code>
|
||||
is provided.
|
||||
</para>
|
||||
<para>
|
||||
Starting with <emphasis>version 4.0.1</emphasis> this attribute also supports the value
|
||||
<code>JMSCorrelationID*</code>, which means that if the outbound message already has a
|
||||
<code>JMSCorrelationID</code> (mapped from the <code>jms_correlationId</code>) header,
|
||||
it will be used, instead of generating a new one.
|
||||
Note, the <code>JMSCorrelationID*</code> key is not allowed when using a
|
||||
<code><reply-container/></code> because the container needs to set up a
|
||||
message selector during initialization.
|
||||
<important>
|
||||
You should understand that the gateway has no means to ensure uniqueness and
|
||||
unexpected side effects can occur if the provided correlation id is not unique.
|
||||
</important>
|
||||
</para>
|
||||
</callout>
|
||||
<callout arearefs="jog030">
|
||||
<para>
|
||||
|
||||
Reference in New Issue
Block a user