INT-3884: Outbound Gateway replyChannel in Chain
JIRA: https://jira.spring.io/browse/INT-3884 Previously, an outbound gateway within a chain allowed a `reply-channel` attribute but it was ignored. The gateway's output channel is set to send the message to the next element in the chain, or the chain's output channel if the gateway is the last element. Tighten the parser logic to detect and disallow a reply channel within a chain. Polishing
This commit is contained in:
committed by
Artem Bilan
parent
051b393ed0
commit
33a40f6cae
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -95,12 +95,19 @@ public abstract class AbstractConsumerEndpointParser extends AbstractBeanDefinit
|
||||
String inputChannelAttributeName = this.getInputChannelAttributeName();
|
||||
boolean hasInputChannelAttribute = element.hasAttribute(inputChannelAttributeName);
|
||||
if (parserContext.isNested()) {
|
||||
String elementDescription = IntegrationNamespaceUtils.createElementDescription(element);
|
||||
if (hasInputChannelAttribute) {
|
||||
String elementDescription = IntegrationNamespaceUtils.createElementDescription(element);
|
||||
parserContext.getReaderContext().error("The '" + inputChannelAttributeName
|
||||
+ "' attribute isn't allowed for a nested (e.g. inside a <chain/>) endpoint element: "
|
||||
+ elementDescription + ".", element);
|
||||
}
|
||||
if (!replyChannelInChainAllowed(element)) {
|
||||
if (StringUtils.hasText(element.getAttribute("reply-channel"))) {
|
||||
parserContext.getReaderContext().error("The 'reply-channel' attribute isn't"
|
||||
+ " allowed for a nested (e.g. inside a <chain/>) outbound gateway element: "
|
||||
+ elementDescription + ".", element);
|
||||
}
|
||||
}
|
||||
return handlerBeanDefinition;
|
||||
}
|
||||
else {
|
||||
@@ -168,4 +175,14 @@ public abstract class AbstractConsumerEndpointParser extends AbstractBeanDefinit
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override to allow 'reply-channel' within a chain, for components where it
|
||||
* makes sense (e.g. enricher). Default is false for outbound gateways, else true.
|
||||
* @return true to allow a reply channel attribute within a chain.
|
||||
*/
|
||||
protected boolean replyChannelInChainAllowed(Element element) {
|
||||
String localName = element.getLocalName();
|
||||
return localName == null || !localName.contains("outbound-gateway");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -42,6 +42,7 @@ import org.springframework.util.xml.DomUtils;
|
||||
* @author Artem Bilan
|
||||
* @author Liujiong
|
||||
* @author Kris Jacyna
|
||||
* @author Gary Russell
|
||||
* @since 2.1
|
||||
*/
|
||||
public class EnricherParser extends AbstractConsumerEndpointParser {
|
||||
@@ -201,4 +202,9 @@ public class EnricherParser extends AbstractConsumerEndpointParser {
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean replyChannelInChainAllowed(Element element) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,16 +11,20 @@
|
||||
|
||||
<channel id="requestChannel"/>
|
||||
|
||||
<channel id="replyChannel"/>
|
||||
|
||||
<channel id="errChannel"/>
|
||||
|
||||
<channel id="outputChannel">
|
||||
<queue />
|
||||
</channel>
|
||||
|
||||
<enricher id="enricher"
|
||||
input-channel="inputChannel" request-channel="requestChannel"
|
||||
output-channel="outputChannel" error-channel="errChannel">
|
||||
<property name="name" expression="'Mr. ' + payload.name"/>
|
||||
</enricher>
|
||||
|
||||
<chain input-channel="inputChannel" output-channel="outputChannel">
|
||||
<enricher id="enricher"
|
||||
request-channel="requestChannel"
|
||||
reply-channel="replyChannel"
|
||||
error-channel="errChannel">
|
||||
<property name="name" expression="'Mr. ' + payload.name"/>
|
||||
</enricher>
|
||||
</chain>
|
||||
</beans:beans>
|
||||
|
||||
@@ -16,10 +16,13 @@
|
||||
|
||||
package org.springframework.integration.jms.config;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.mock;
|
||||
@@ -249,6 +252,12 @@ public class JmsOutboundGatewayParserTests {
|
||||
String result = gateway.echo("hello");
|
||||
verify(handler, times(1)).handleMessage(Mockito.any(Message.class));
|
||||
assertEquals("hello", result);
|
||||
JmsOutboundGateway gw1 = context.getBean("chain1$child.gateway.handler", JmsOutboundGateway.class);
|
||||
MessageChannel out = TestUtils.getPropertyValue(gw1, "outputChannel", MessageChannel.class);
|
||||
assertThat(out.getClass().getSimpleName(), equalTo("ReplyForwardingMessageChannel"));
|
||||
JmsOutboundGateway gw2 = context.getBean("chain2$child.gateway.handler", JmsOutboundGateway.class);
|
||||
out = TestUtils.getPropertyValue(gw2, "outputChannel", MessageChannel.class);
|
||||
assertThat(out.getClass().getName(), containsString("MessageHandlerChain$"));
|
||||
context.close();
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
http://www.springframework.org/schema/integration/jms http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xmlns:int-jms="http://www.springframework.org/schema/integration/jms">
|
||||
|
||||
|
||||
<int:message-history/>
|
||||
|
||||
<int:gateway id="gateway"
|
||||
@@ -19,17 +19,47 @@
|
||||
<int:header name="foo" value="bar"/>
|
||||
</int:method>
|
||||
</int:gateway>
|
||||
|
||||
|
||||
<int:chain input-channel="requests">
|
||||
<int-jms:outbound-gateway request-destination="requestQueueA"
|
||||
reply-destination="replyQueueB"
|
||||
<int-jms:outbound-gateway request-destination="requestQueueA"
|
||||
reply-destination="replyQueueB"
|
||||
connection-factory="connectionFactory"
|
||||
receive-timeout="100000"
|
||||
reply-timeout="200000"/>
|
||||
</int:chain>
|
||||
|
||||
|
||||
|
||||
|
||||
<int:chain id="chain1" input-channel="chainWithGatewayAtEnd">
|
||||
<int-jms:outbound-gateway id="gateway"
|
||||
request-destination="requestQueueA"
|
||||
reply-destination="replyQueueB"
|
||||
connection-factory="connectionFactory"
|
||||
receive-timeout="100000"
|
||||
reply-timeout="200000"/>
|
||||
</int:chain>
|
||||
|
||||
<int:chain id="chain2" input-channel="chainWithGatewayInMiddle">
|
||||
<int-jms:outbound-gateway id="gateway"
|
||||
request-destination="requestQueueA"
|
||||
reply-destination="replyQueueB"
|
||||
connection-factory="connectionFactory"
|
||||
receive-timeout="100000"
|
||||
reply-timeout="200000"/>
|
||||
<int:transformer expression="payload"/>
|
||||
</int:chain>
|
||||
|
||||
<!-- INT-3884
|
||||
<int:chain id="invalidChain" input-channel="chainWithInvalidGatewayReplyChannel">
|
||||
<int-jms:outbound-gateway id="badChainGateway"
|
||||
request-destination="requestQueueA"
|
||||
reply-destination="replyQueueB"
|
||||
connection-factory="connectionFactory"
|
||||
receive-timeout="100000"
|
||||
reply-channel="badOutputChannel"
|
||||
reply-timeout="200000"/>
|
||||
</int:chain>
|
||||
|
||||
<int:channel id="badOutputChannel"/>
|
||||
-->
|
||||
<bean id="requestQueueA" class="org.apache.activemq.command.ActiveMQQueue">
|
||||
<constructor-arg value="request.queueA"/>
|
||||
</bean>
|
||||
@@ -37,7 +67,7 @@
|
||||
<bean id="replyQueueB" class="org.apache.activemq.command.ActiveMQQueue">
|
||||
<constructor-arg value="reply.queueB"/>
|
||||
</bean>
|
||||
|
||||
|
||||
|
||||
<bean id="connectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
|
||||
<property name="targetConnectionFactory">
|
||||
@@ -48,11 +78,11 @@
|
||||
<property name="sessionCacheSize" value="10"/>
|
||||
<property name="cacheProducers" value="false"/>
|
||||
</bean>
|
||||
|
||||
|
||||
<int-jms:inbound-gateway id="inboundGateway" request-channel="jmsInput" request-destination="requestQueueA"/>
|
||||
|
||||
|
||||
<int:channel id="jmsInput"/>
|
||||
|
||||
|
||||
<!-- <int:service-activator input-channel="jmsInput">-->
|
||||
<!-- <bean class="org.springframework.integration.jms.config.JmsOutboundGatewayParserTests$SampleService"/>-->
|
||||
<!-- </int:service-activator>-->
|
||||
|
||||
@@ -13,3 +13,10 @@ development process.
|
||||
[[x4.3-general]]
|
||||
=== General Changes
|
||||
|
||||
==== Outbound Gateway within Chain
|
||||
|
||||
Previously, it was possible to specify a `reply-channel` on an outbound gateway within a chain.
|
||||
It was completely ignored; the gateway's reply goes to the next chain element, or to the chain's output channel
|
||||
if the gateway is the last element.
|
||||
This condition is now detected and disallowed.
|
||||
If you have such configuration, simply remove the `reply-channel`.
|
||||
|
||||
Reference in New Issue
Block a user