From e2e98d8c2c9d184b09800508822d1ea12fbd6fc9 Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Thu, 13 Nov 2008 21:22:40 +0000 Subject: [PATCH] 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. --- .../jms/HeaderMappingMessageConverter.java | 77 +++++++++++-------- .../integration/jms/JmsInboundGateway.java | 52 +++++++++---- .../jms/config/JmsInboundGatewayParser.java | 7 +- .../jms/config/spring-integration-jms-1.0.xsd | 4 +- .../config/JmsInboundGatewayParserTests.java | 32 ++++++-- ...msGatewaysWithExtractPayloadAttributes.xml | 19 ++++- 6 files changed, 130 insertions(+), 61 deletions(-) diff --git a/org.springframework.integration.jms/src/main/java/org/springframework/integration/jms/HeaderMappingMessageConverter.java b/org.springframework.integration.jms/src/main/java/org/springframework/integration/jms/HeaderMappingMessageConverter.java index d945b45733..54ed61810e 100644 --- a/org.springframework.integration.jms/src/main/java/org/springframework/integration/jms/HeaderMappingMessageConverter.java +++ b/org.springframework.integration.jms/src/main/java/org/springframework/integration/jms/HeaderMappingMessageConverter.java @@ -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 not - * 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. + * + *

The default value is true. + */ + 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. - * - *

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. * *

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 true. + * a Spring Integration Message, then set this to true. * 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 false 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 + * false to ensure that the actual Message will be passed + * along with its Serializable headers. * - *

The default value is false. + *

The default value is true. */ - 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 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); } diff --git a/org.springframework.integration.jms/src/main/java/org/springframework/integration/jms/JmsInboundGateway.java b/org.springframework.integration.jms/src/main/java/org/springframework/integration/jms/JmsInboundGateway.java index c3aee3c95a..d54d0db131 100644 --- a/org.springframework.integration.jms/src/main/java/org/springframework/integration/jms/JmsInboundGateway.java +++ b/org.springframework.integration.jms/src/main/java/org/springframework/integration/jms/JmsInboundGateway.java @@ -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. + * + *

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(); diff --git a/org.springframework.integration.jms/src/main/java/org/springframework/integration/jms/config/JmsInboundGatewayParser.java b/org.springframework.integration.jms/src/main/java/org/springframework/integration/jms/config/JmsInboundGatewayParser.java index d99dee806b..833676767a 100644 --- a/org.springframework.integration.jms/src/main/java/org/springframework/integration/jms/config/JmsInboundGatewayParser.java +++ b/org.springframework.integration.jms/src/main/java/org/springframework/integration/jms/config/JmsInboundGatewayParser.java @@ -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"); diff --git a/org.springframework.integration.jms/src/main/java/org/springframework/integration/jms/config/spring-integration-jms-1.0.xsd b/org.springframework.integration.jms/src/main/java/org/springframework/integration/jms/config/spring-integration-jms-1.0.xsd index 8ac91bd4ca..19002066bd 100644 --- a/org.springframework.integration.jms/src/main/java/org/springframework/integration/jms/config/spring-integration-jms-1.0.xsd +++ b/org.springframework.integration.jms/src/main/java/org/springframework/integration/jms/config/spring-integration-jms-1.0.xsd @@ -47,11 +47,13 @@ + + + - diff --git a/org.springframework.integration.jms/src/test/java/org/springframework/integration/jms/config/JmsInboundGatewayParserTests.java b/org.springframework.integration.jms/src/test/java/org/springframework/integration/jms/config/JmsInboundGatewayParserTests.java index 11ae0acd65..42d508f08c 100644 --- a/org.springframework.integration.jms/src/test/java/org/springframework/integration/jms/config/JmsInboundGatewayParserTests.java +++ b/org.springframework.integration.jms/src/test/java/org/springframework/integration/jms/config/JmsInboundGatewayParserTests.java @@ -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) diff --git a/org.springframework.integration.jms/src/test/java/org/springframework/integration/jms/config/jmsGatewaysWithExtractPayloadAttributes.xml b/org.springframework.integration.jms/src/test/java/org/springframework/integration/jms/config/jmsGatewaysWithExtractPayloadAttributes.xml index 4b81321099..4fdd996935 100644 --- a/org.springframework.integration.jms/src/test/java/org/springframework/integration/jms/config/jmsGatewaysWithExtractPayloadAttributes.xml +++ b/org.springframework.integration.jms/src/test/java/org/springframework/integration/jms/config/jmsGatewaysWithExtractPayloadAttributes.xml @@ -18,15 +18,26 @@ destination="testDestination" request-channel="requestChannel"/> - + extract-reply-payload="true"/> - + extract-reply-payload="false"/> + + + + +