The 'extract-payload-for-reply' attribute for a JMS inbound-gateway is now 'extract-reply-payload'. The 'extract-request-payload' attribute has also been added. Both have default values of TRUE (the default for 'extract-reply-payload' had been FALSE). This work is related to INT-368, INT-460, and INT-467.
This commit is contained in:
@@ -16,11 +16,9 @@
|
||||
|
||||
package org.springframework.integration.jms;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.jms.JMSException;
|
||||
import javax.jms.ObjectMessage;
|
||||
import javax.jms.Session;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -31,7 +29,7 @@ import org.springframework.integration.core.MessageHeaders;
|
||||
import org.springframework.integration.message.MessageBuilder;
|
||||
import org.springframework.jms.support.converter.MessageConversionException;
|
||||
import org.springframework.jms.support.converter.MessageConverter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.jms.support.converter.SimpleMessageConverter;
|
||||
|
||||
/**
|
||||
* A {@link MessageConverter} implementation that is capable of delegating to
|
||||
@@ -57,13 +55,14 @@ public class HeaderMappingMessageConverter implements MessageConverter {
|
||||
|
||||
private final JmsHeaderMapper headerMapper;
|
||||
|
||||
private volatile boolean extractPayload;
|
||||
private volatile boolean extractRequestPayload = true;
|
||||
|
||||
private volatile boolean extractReplyPayload = true;
|
||||
|
||||
|
||||
/**
|
||||
* Create a HeaderMappingMessageConverter instance that will <em>not</em>
|
||||
* delegate to another {@link MessageConverter} and will use the default
|
||||
* implementation of the {@link JmsHeaderMapper} strategy.
|
||||
* Create a HeaderMappingMessageConverter instance that will rely on the
|
||||
* default {@link SimpleMessageConverter} and {@link DefaultJmsHeaderMapper}.
|
||||
*/
|
||||
public HeaderMappingMessageConverter() {
|
||||
this(null, null);
|
||||
@@ -78,36 +77,54 @@ public class HeaderMappingMessageConverter implements MessageConverter {
|
||||
this(converter, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a HeaderMappingMessageConverter instance that will delegate to
|
||||
* the provided {@link JmsHeaderMapper} instance and will use the default
|
||||
* {@link SimpleMessageConverter} implementation.
|
||||
*/
|
||||
public HeaderMappingMessageConverter(JmsHeaderMapper headerMapper) {
|
||||
this(null, headerMapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a HeaderMappingMessageConverter instance that will delegate to
|
||||
* the provided {@link MessageConverter} and {@link JmsHeaderMapper}.
|
||||
*/
|
||||
public HeaderMappingMessageConverter(MessageConverter converter, JmsHeaderMapper headerMapper) {
|
||||
this.converter = converter;
|
||||
this.converter = (converter != null ? converter : new SimpleMessageConverter());
|
||||
this.headerMapper = (headerMapper != null ? headerMapper : new DefaultJmsHeaderMapper());
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether the inbound JMS Message's payload should be extracted
|
||||
* during the conversion process. Otherwise, the raw JMS Message itself
|
||||
* will be the payload of the created Spring Integration Message. The
|
||||
* HeaderMapper will be applied to the Message regardless of this value.
|
||||
*
|
||||
* <p>The default value is <code>true</code>.
|
||||
*/
|
||||
public void setExtractRequestPayload(boolean extractRequestPayload) {
|
||||
this.extractRequestPayload = extractRequestPayload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether the integration Message's payload should be extracted
|
||||
* prior to conversion. Otherwise, the integration Message itself will be
|
||||
* passed to the converter.
|
||||
*
|
||||
* <p>If no {@link MessageConverter} is available (the default), the
|
||||
* integration Message will be sent within a JMS {@link ObjectMessage}.
|
||||
* Specify whether the outbound integration Message's payload should be
|
||||
* extracted prior to conversion into a JMS Message. Otherwise, the
|
||||
* integration Message itself will be passed to the converter.
|
||||
*
|
||||
* <p>Typically, this setting should be determined by the expectations of
|
||||
* the target system. If the target system is not capable of understanding
|
||||
* a Spring Integration Message, then set this to <code>true</code>.
|
||||
* a Spring Integration Message, then set this to <code>true</code>.
|
||||
* On the other hand, if the system is not only capable of understanding a
|
||||
* Spring Integration Message but actually expected to rely upon header
|
||||
* values, then this must be set to <code>false</code> so that the actual
|
||||
* Message along with its headers will be passed.
|
||||
* Spring Integration Message but actually expected to rely upon Spring
|
||||
* Integration Message Header values, then this must be set to
|
||||
* <code>false</code> to ensure that the actual Message will be passed
|
||||
* along with its Serializable headers.
|
||||
*
|
||||
* <p>The default value is <code>false</code>.
|
||||
* <p>The default value is <code>true</code>.
|
||||
*/
|
||||
public void setExtractPayload(boolean extractPayload) {
|
||||
this.extractPayload = extractPayload;
|
||||
public void setExtractReplyPayload(boolean extractReplyPayload) {
|
||||
this.extractReplyPayload = extractReplyPayload;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -115,10 +132,7 @@ public class HeaderMappingMessageConverter implements MessageConverter {
|
||||
*/
|
||||
public Object fromMessage(javax.jms.Message jmsMessage) throws JMSException, MessageConversionException {
|
||||
MessageBuilder<?> builder = null;
|
||||
if (this.converter == null) {
|
||||
builder = MessageBuilder.withPayload(jmsMessage);
|
||||
}
|
||||
else {
|
||||
if (this.extractRequestPayload) {
|
||||
Object conversionResult = this.converter.fromMessage(jmsMessage);
|
||||
if (conversionResult == null) {
|
||||
return null;
|
||||
@@ -130,6 +144,9 @@ public class HeaderMappingMessageConverter implements MessageConverter {
|
||||
builder = MessageBuilder.withPayload(conversionResult);
|
||||
}
|
||||
}
|
||||
else {
|
||||
builder = MessageBuilder.withPayload(jmsMessage);
|
||||
}
|
||||
Map<String, Object> headers = this.headerMapper.toHeaders(jmsMessage);
|
||||
Message<?> message = builder.copyHeadersIfAbsent(headers).build();
|
||||
if (logger.isDebugEnabled()) {
|
||||
@@ -146,17 +163,11 @@ public class HeaderMappingMessageConverter implements MessageConverter {
|
||||
javax.jms.Message jmsMessage = null;
|
||||
if (object instanceof Message) {
|
||||
headers = ((Message<?>) object).getHeaders();
|
||||
if (this.extractPayload) {
|
||||
if (this.extractReplyPayload) {
|
||||
object = ((Message<?>) object).getPayload();
|
||||
}
|
||||
}
|
||||
if (this.converter == null) {
|
||||
Assert.isInstanceOf(Serializable.class, object, "Object must implement Serializable");
|
||||
jmsMessage = session.createObjectMessage((Serializable) object);
|
||||
}
|
||||
else {
|
||||
jmsMessage = this.converter.toMessage(object, session);
|
||||
}
|
||||
jmsMessage = this.converter.toMessage(object, session);
|
||||
if (headers != null) {
|
||||
this.headerMapper.fromHeaders(headers, jmsMessage);
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@ import org.springframework.jms.listener.DefaultMessageListenerContainer;
|
||||
import org.springframework.jms.listener.SessionAwareMessageListener;
|
||||
import org.springframework.jms.listener.adapter.MessageListenerAdapter;
|
||||
import org.springframework.jms.support.converter.MessageConverter;
|
||||
import org.springframework.jms.support.converter.SimpleMessageConverter;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -52,6 +51,12 @@ public class JmsInboundGateway extends SimpleMessagingGateway implements Disposa
|
||||
|
||||
private volatile MessageConverter messageConverter;
|
||||
|
||||
private volatile JmsHeaderMapper headerMapper;
|
||||
|
||||
private volatile boolean extractRequestPayload = true;
|
||||
|
||||
private volatile boolean extractReplyPayload = true;
|
||||
|
||||
private volatile TaskExecutor taskExecutor;
|
||||
|
||||
private volatile PlatformTransactionManager transactionManager;
|
||||
@@ -68,8 +73,6 @@ public class JmsInboundGateway extends SimpleMessagingGateway implements Disposa
|
||||
|
||||
private volatile int idleTaskExecutionLimit = 1;
|
||||
|
||||
private volatile boolean extractPayloadForReply = false;
|
||||
|
||||
|
||||
public void setContainer(AbstractMessageListenerContainer container) {
|
||||
this.container = container;
|
||||
@@ -87,11 +90,40 @@ public class JmsInboundGateway extends SimpleMessagingGateway implements Disposa
|
||||
this.destinationName = destinationName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a {@link MessageConverter} implementation to use when
|
||||
* converting between JMS Messages and Spring Integration Messages.
|
||||
* If none is provided, a {@link HeaderMappingMessageConverter} will
|
||||
* be used and the {@link JmsHeaderMapper} instance provided to the
|
||||
* {@link #setHeaderMapper(JmsHeaderMapper)} method will be included
|
||||
* in the conversion process.
|
||||
*/
|
||||
public void setMessageConverter(MessageConverter messageConverter) {
|
||||
Assert.notNull(messageConverter, "'messageConverter' must not be null");
|
||||
this.messageConverter = messageConverter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a {@link JmsHeaderMapper} implementation to use when
|
||||
* converting between JMS Messages and Spring Integration Messages.
|
||||
* If none is provided, a {@link DefaultJmsHeaderMapper} will be used.
|
||||
*
|
||||
* <p>This property will be ignored if a {@link MessageConverter} is
|
||||
* provided to the {@link #setMessageConverter(MessageConverter)} method.
|
||||
* However, you may provide your own implementation of the delegating
|
||||
* {@link HeaderMappingMessageConverter} implementation.
|
||||
*/
|
||||
public void setHeaderMapper(JmsHeaderMapper headerMapper) {
|
||||
this.headerMapper = headerMapper;
|
||||
}
|
||||
|
||||
public void setExtractRequestPayload(boolean extractRequestPayload) {
|
||||
this.extractRequestPayload = extractRequestPayload;
|
||||
}
|
||||
|
||||
public void setExtractReplyPayload(boolean extractReplyPayload) {
|
||||
this.extractReplyPayload = extractReplyPayload;
|
||||
}
|
||||
|
||||
public void setTaskExecutor(TaskExecutor taskExecutor) {
|
||||
this.taskExecutor = taskExecutor;
|
||||
}
|
||||
@@ -124,21 +156,15 @@ public class JmsInboundGateway extends SimpleMessagingGateway implements Disposa
|
||||
this.idleTaskExecutionLimit = idleTaskExecutionLimit;
|
||||
}
|
||||
|
||||
public void setExtractPayloadForReply(boolean extractPayloadForReply) {
|
||||
this.extractPayloadForReply = extractPayloadForReply;
|
||||
}
|
||||
|
||||
|
||||
private void initialize() {
|
||||
if (this.container == null) {
|
||||
this.container = createDefaultContainer();
|
||||
}
|
||||
if (this.messageConverter == null) {
|
||||
this.messageConverter = new SimpleMessageConverter();
|
||||
}
|
||||
if (!(this.messageConverter instanceof HeaderMappingMessageConverter)) {
|
||||
HeaderMappingMessageConverter hmmc = new HeaderMappingMessageConverter(this.messageConverter);
|
||||
hmmc.setExtractPayload(this.extractPayloadForReply);
|
||||
HeaderMappingMessageConverter hmmc = new HeaderMappingMessageConverter(null, this.headerMapper);
|
||||
hmmc.setExtractRequestPayload(this.extractRequestPayload);
|
||||
hmmc.setExtractReplyPayload(this.extractReplyPayload);
|
||||
this.messageConverter = hmmc;
|
||||
}
|
||||
MessageListenerAdapter listener = new MessageListenerAdapter();
|
||||
|
||||
@@ -87,9 +87,10 @@ public class JmsInboundGatewayParser extends AbstractSingleBeanDefinitionParser
|
||||
builder.addPropertyValue("sessionAcknowledgeMode", acknowledgeMode);
|
||||
}
|
||||
}
|
||||
if ("true".equals(element.getAttribute("extract-payload-for-reply"))) {
|
||||
builder.addPropertyValue("extractPayloadForReply", Boolean.TRUE);
|
||||
}
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "message-converter");
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "header-mapper");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "extract-request-payload");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "extract-reply-payload");
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "transaction-manager");
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "request-channel");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "request-timeout");
|
||||
|
||||
@@ -47,11 +47,13 @@
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="jmsInboundAdapterType">
|
||||
<xsd:attribute name="message-converter" type="xsd:string"/>
|
||||
<xsd:attribute name="header-mapper" type="xsd:string"/>
|
||||
<xsd:attribute name="extract-request-payload" type="xsd:string" default="true"/>
|
||||
<xsd:attribute name="extract-reply-payload" type="xsd:string" default="true"/>
|
||||
<xsd:attribute name="request-channel" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="reply-channel" type="xsd:string"/>
|
||||
<xsd:attribute name="request-timeout" type="xsd:string"/>
|
||||
<xsd:attribute name="reply-timeout" type="xsd:string"/>
|
||||
<xsd:attribute name="extract-payload-for-reply" type="xsd:string" default="false"/>
|
||||
<xsd:attribute name="transaction-manager" type="xsd:string"/>
|
||||
<xsd:attribute name="concurrent-consumers" type="xsd:string"/>
|
||||
<xsd:attribute name="max-concurrent-consumers" type="xsd:string"/>
|
||||
|
||||
@@ -85,25 +85,43 @@ public class JmsInboundGatewayParserTests {
|
||||
"jmsGatewaysWithExtractPayloadAttributes.xml", this.getClass());
|
||||
JmsInboundGateway gateway = (JmsInboundGateway) context.getBean("defaultGateway");
|
||||
DirectFieldAccessor accessor = new DirectFieldAccessor(gateway);
|
||||
assertEquals(Boolean.FALSE, accessor.getPropertyValue("extractPayloadForReply"));
|
||||
assertEquals(Boolean.TRUE, accessor.getPropertyValue("extractReplyPayload"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGatewayWithExtractPayloadTrue() {
|
||||
public void testGatewayWithExtractReplyPayloadTrue() {
|
||||
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
|
||||
"jmsGatewaysWithExtractPayloadAttributes.xml", this.getClass());
|
||||
JmsInboundGateway gateway = (JmsInboundGateway) context.getBean("gatewayExpectingReply");
|
||||
JmsInboundGateway gateway = (JmsInboundGateway) context.getBean("extractReplyPayloadTrue");
|
||||
DirectFieldAccessor accessor = new DirectFieldAccessor(gateway);
|
||||
assertEquals(Boolean.TRUE, accessor.getPropertyValue("extractPayloadForReply"));
|
||||
assertEquals(Boolean.TRUE, accessor.getPropertyValue("extractReplyPayload"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGatewayWithExtractPayloadFalse() {
|
||||
public void testGatewayWithExtractReplyPayloadFalse() {
|
||||
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
|
||||
"jmsGatewaysWithExtractPayloadAttributes.xml", this.getClass());
|
||||
JmsInboundGateway gateway = (JmsInboundGateway) context.getBean("gatewayNotExpectingReply");
|
||||
JmsInboundGateway gateway = (JmsInboundGateway) context.getBean("extractReplyPayloadFalse");
|
||||
DirectFieldAccessor accessor = new DirectFieldAccessor(gateway);
|
||||
assertEquals(Boolean.FALSE, accessor.getPropertyValue("extractPayloadForReply"));
|
||||
assertEquals(Boolean.FALSE, accessor.getPropertyValue("extractReplyPayload"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGatewayWithExtractRequestPayloadTrue() {
|
||||
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
|
||||
"jmsGatewaysWithExtractPayloadAttributes.xml", this.getClass());
|
||||
JmsInboundGateway gateway = (JmsInboundGateway) context.getBean("extractRequestPayloadTrue");
|
||||
DirectFieldAccessor accessor = new DirectFieldAccessor(gateway);
|
||||
assertEquals(Boolean.TRUE, accessor.getPropertyValue("extractRequestPayload"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGatewayWithExtractRequestPayloadFalse() {
|
||||
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
|
||||
"jmsGatewaysWithExtractPayloadAttributes.xml", this.getClass());
|
||||
JmsInboundGateway gateway = (JmsInboundGateway) context.getBean("extractRequestPayloadFalse");
|
||||
DirectFieldAccessor accessor = new DirectFieldAccessor(gateway);
|
||||
assertEquals(Boolean.FALSE, accessor.getPropertyValue("extractRequestPayload"));
|
||||
}
|
||||
|
||||
@Test(expected=BeanDefinitionStoreException.class)
|
||||
|
||||
@@ -18,15 +18,26 @@
|
||||
destination="testDestination"
|
||||
request-channel="requestChannel"/>
|
||||
|
||||
<jms:inbound-gateway id="gatewayNotExpectingReply"
|
||||
<jms:inbound-gateway id="extractReplyPayloadTrue"
|
||||
destination="testDestination"
|
||||
request-channel="requestChannel"
|
||||
extract-payload-for-reply="false"/>
|
||||
extract-reply-payload="true"/>
|
||||
|
||||
<jms:inbound-gateway id="gatewayExpectingReply"
|
||||
<jms:inbound-gateway id="extractReplyPayloadFalse"
|
||||
destination="testDestination"
|
||||
request-channel="requestChannel"
|
||||
extract-payload-for-reply="true"/>
|
||||
extract-reply-payload="false"/>
|
||||
|
||||
|
||||
<jms:inbound-gateway id="extractRequestPayloadTrue"
|
||||
destination="testDestination"
|
||||
request-channel="requestChannel"
|
||||
extract-request-payload="true"/>
|
||||
|
||||
<jms:inbound-gateway id="extractRequestPayloadFalse"
|
||||
destination="testDestination"
|
||||
request-channel="requestChannel"
|
||||
extract-request-payload="false"/>
|
||||
|
||||
<bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory">
|
||||
<constructor-arg>
|
||||
|
||||
Reference in New Issue
Block a user