INT-2269 Add ReplyChannelRegistry
Allows reply channel resolution after a message has been serialized somewhere in a flow. Previously, the reply channel was lost. With this change, the reply channel can be registered and the header becomes a string (channel name) that can be serialized. JIRA: https://jira.springsource.org/browse/INT-2269 INT-2269 Rename Registry to HeaderChannelRegistry - Extract interface - DefaultHeaderChannelRgistry INT-2269 Polishing; PR Comments - Add errorChannel registration as well. INT-2269 HeaderChannelRegistry - Fix The internal BridgeHandler in MessagingGatewaySupport did not have a channel resolver. When a reply was explicitly routed to the gateway's reply channel, the String representation of the reply channel could not be resolved to a channel. Set the BeanFactory on the bridge handler. Add tests. INT-2269 HeaderChannelRegistry - Fix JMS/Enricher The JMS inbound gateway and ContentEnricher instantiate a MessagingGatewaySupport internally it does not get a reference to the BeanFactory. This means that the internal BridgeHandler cannot resolve the String representation of the reply channel to a channel. Make ChannelPublishingJmsMessageListener BeanFactory aware, and propagate the bean factory to the MGS. Set the MGS bean factory in the ContentEnricher (which is already BFA). INT-2269: Polishing
This commit is contained in:
committed by
Artem Bilan
parent
1d0c28852f
commit
836c8e2556
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2013 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.
|
||||
@@ -28,6 +28,9 @@ import javax.jms.Session;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.MessageChannel;
|
||||
@@ -47,18 +50,18 @@ import org.springframework.util.Assert;
|
||||
* Message and sends that Message to a channel. If the 'expectReply' value is
|
||||
* <code>true</code>, it will also wait for a Spring Integration reply Message
|
||||
* and convert that into a JMS reply.
|
||||
*
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Juergen Hoeller
|
||||
* @author Oleg Zhurakousky
|
||||
*/
|
||||
public class ChannelPublishingJmsMessageListener
|
||||
implements SessionAwareMessageListener<javax.jms.Message>, InitializingBean, TrackableComponent {
|
||||
|
||||
public class ChannelPublishingJmsMessageListener
|
||||
implements SessionAwareMessageListener<javax.jms.Message>, InitializingBean, TrackableComponent, BeanFactoryAware {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
|
||||
private volatile boolean expectReply;
|
||||
|
||||
|
||||
private volatile MessageConverter messageConverter = new SimpleMessageConverter();
|
||||
|
||||
private volatile boolean extractRequestPayload = true;
|
||||
@@ -80,9 +83,11 @@ public class ChannelPublishingJmsMessageListener
|
||||
private volatile DestinationResolver destinationResolver = new DynamicDestinationResolver();
|
||||
|
||||
private volatile JmsHeaderMapper headerMapper = new DefaultJmsHeaderMapper();
|
||||
|
||||
|
||||
private final GatewayDelegate gatewayDelegate = new GatewayDelegate();
|
||||
|
||||
private volatile BeanFactory beanFactory;
|
||||
|
||||
/**
|
||||
* Specify whether a JMS reply Message is expected.
|
||||
*/
|
||||
@@ -93,39 +98,42 @@ public class ChannelPublishingJmsMessageListener
|
||||
public void setComponentName(String componentName){
|
||||
this.gatewayDelegate.setComponentName(componentName);
|
||||
}
|
||||
|
||||
|
||||
public void setRequestChannel(MessageChannel requestChannel){
|
||||
this.gatewayDelegate.setRequestChannel(requestChannel);
|
||||
}
|
||||
|
||||
|
||||
public void setReplyChannel(MessageChannel replyChannel){
|
||||
this.gatewayDelegate.setReplyChannel(replyChannel);
|
||||
}
|
||||
|
||||
|
||||
public void setErrorChannel(MessageChannel errorChannel){
|
||||
this.gatewayDelegate.setErrorChannel(errorChannel);
|
||||
}
|
||||
|
||||
|
||||
public void setRequestTimeout(long requestTimeout){
|
||||
this.gatewayDelegate.setRequestTimeout(requestTimeout);
|
||||
}
|
||||
|
||||
|
||||
public void setReplyTimeout(long replyTimeout){
|
||||
this.gatewayDelegate.setReplyTimeout(replyTimeout);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setShouldTrack(boolean shouldTrack) {
|
||||
this.gatewayDelegate.setShouldTrack(shouldTrack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getComponentName() {
|
||||
return this.gatewayDelegate.getComponentName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getComponentType() {
|
||||
return this.gatewayDelegate.getComponentType();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the default reply destination to send reply messages to. This will
|
||||
* be applied in case of a request message that does not carry a
|
||||
@@ -189,7 +197,7 @@ public class ChannelPublishingJmsMessageListener
|
||||
* JMSMessageID from the request will be copied into the JMSCorrelationID of the reply
|
||||
* unless there is already a value in the JMSCorrelationID property of the newly created
|
||||
* reply Message in which case nothing will be copied. If the JMSCorrelationID of the
|
||||
* request Message should be copied into the JMSCorrelationID of the reply Message
|
||||
* request Message should be copied into the JMSCorrelationID of the reply Message
|
||||
* instead, then this value should be set to "JMSCorrelationID".
|
||||
* Any other value will be treated as a JMS String Property to be copied as-is
|
||||
* from the request Message into the reply Message with the same property name.
|
||||
@@ -200,7 +208,7 @@ public class ChannelPublishingJmsMessageListener
|
||||
|
||||
/**
|
||||
* Specify whether explicit QoS should be enabled for replies
|
||||
* (for timeToLive, priority, and deliveryMode settings).
|
||||
* (for timeToLive, priority, and deliveryMode settings).
|
||||
*/
|
||||
public void setExplicitQosEnabledForReplies(boolean explicitQosEnabledForReplies) {
|
||||
this.explicitQosEnabledForReplies = explicitQosEnabledForReplies;
|
||||
@@ -224,7 +232,7 @@ public class ChannelPublishingJmsMessageListener
|
||||
* converting between JMS Messages and Spring Integration Messages.
|
||||
* If none is provided, a {@link SimpleMessageConverter} will
|
||||
* be used.
|
||||
*
|
||||
*
|
||||
* @param messageConverter
|
||||
*/
|
||||
public void setMessageConverter(MessageConverter messageConverter) {
|
||||
@@ -260,6 +268,12 @@ public class ChannelPublishingJmsMessageListener
|
||||
this.extractReplyPayload = extractReplyPayload;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(javax.jms.Message jmsMessage, Session session) throws JMSException {
|
||||
Object result = jmsMessage;
|
||||
if (this.extractRequestPayload) {
|
||||
@@ -268,10 +282,10 @@ public class ChannelPublishingJmsMessageListener
|
||||
logger.debug("converted JMS Message [" + jmsMessage + "] to integration Message payload [" + result + "]");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Map<String, Object> headers = headerMapper.toHeaders(jmsMessage);
|
||||
Message<?> requestMessage = (result instanceof Message<?>) ?
|
||||
MessageBuilder.fromMessage((Message<?>) result).copyHeaders(headers).build() :
|
||||
MessageBuilder.fromMessage((Message<?>) result).copyHeaders(headers).build() :
|
||||
MessageBuilder.withPayload(result).copyHeaders(headers).build();
|
||||
if (!this.expectReply) {
|
||||
this.gatewayDelegate.send(requestMessage);
|
||||
@@ -305,18 +319,22 @@ public class ChannelPublishingJmsMessageListener
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
if (this.beanFactory != null) {
|
||||
this.gatewayDelegate.setBeanFactory(this.beanFactory);
|
||||
}
|
||||
this.gatewayDelegate.afterPropertiesSet();
|
||||
}
|
||||
|
||||
|
||||
protected void start(){
|
||||
this.gatewayDelegate.start();
|
||||
}
|
||||
|
||||
|
||||
protected void stop(){
|
||||
this.gatewayDelegate.stop();
|
||||
}
|
||||
|
||||
|
||||
private void copyCorrelationIdFromRequestToReply(javax.jms.Message requestMessage, javax.jms.Message replyMessage) throws JMSException {
|
||||
if (this.correlationKey != null) {
|
||||
if (this.correlationKey.equals("JMSCorrelationID")) {
|
||||
@@ -416,17 +434,20 @@ public class ChannelPublishingJmsMessageListener
|
||||
this.isTopic = isTopic;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class GatewayDelegate extends MessagingGatewaySupport {
|
||||
|
||||
@Override
|
||||
protected void send(Object request) {
|
||||
super.send(request);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Message<?> sendAndReceiveMessage(Object request) {
|
||||
return super.sendAndReceiveMessage(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getComponentType() {
|
||||
if (expectReply) {
|
||||
return "jms:inbound-gateway";
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xmlns:int-jms="http://www.springframework.org/schema/integration/jms"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/jms http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd">
|
||||
|
||||
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
|
||||
<property name="brokerURL" value="vm://localhost"/>
|
||||
</bean>
|
||||
|
||||
<int:channel id="input" />
|
||||
|
||||
<int:channel id="output">
|
||||
<int:queue />
|
||||
</int:channel>
|
||||
|
||||
<int-jms:outbound-gateway request-channel="input" reply-channel="output"
|
||||
connection-factory="connectionFactory"
|
||||
request-destination-name="serialized.reply.channel" />
|
||||
|
||||
<int-jms:inbound-gateway request-channel="foo" reply-channel="baz"
|
||||
request-destination-name="serialized.reply.channel"
|
||||
connection-factory="connectionFactory"/>
|
||||
|
||||
<int:header-enricher input-channel="foo" output-channel="bar">
|
||||
<int:header-channels-to-string />
|
||||
</int:header-enricher>
|
||||
|
||||
<int:transformer input-channel="bar" output-channel="baz"
|
||||
expression="'echo:' + payload" />
|
||||
|
||||
<int:channel id="baz" />
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2013 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.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import org.junit.Test;
|
||||
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.message.GenericMessage;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* @author Gary Russell
|
||||
* @since 3.0
|
||||
*
|
||||
*/
|
||||
@ContextConfiguration
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class GatewaySerializedReplyChannelTests {
|
||||
|
||||
@Autowired
|
||||
MessageChannel input;
|
||||
|
||||
@Autowired
|
||||
PollableChannel output;
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
input.send(new GenericMessage<String>("foo"));
|
||||
Message<?> reply = output.receive(0);
|
||||
assertNotNull(reply);
|
||||
assertEquals("echo:foo", reply.getPayload());
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user