diff --git a/spring-integration-jms/src/main/java/org/springframework/integration/jms/config/JmsAdapterParserUtils.java b/spring-integration-jms/src/main/java/org/springframework/integration/jms/config/JmsAdapterParserUtils.java
index f3c522b360..b3f1e01546 100644
--- a/spring-integration-jms/src/main/java/org/springframework/integration/jms/config/JmsAdapterParserUtils.java
+++ b/spring-integration-jms/src/main/java/org/springframework/integration/jms/config/JmsAdapterParserUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 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.
@@ -16,6 +16,8 @@
package org.springframework.integration.jms.config;
+import org.w3c.dom.Element;
+
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
@@ -23,7 +25,6 @@ import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.integration.jms.DynamicJmsTemplate;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.util.StringUtils;
-import org.w3c.dom.Element;
/**
* Utility methods and constants for JMS adapter parsers.
@@ -64,7 +65,7 @@ abstract class JmsAdapterParserUtils {
private static final String[] JMS_TEMPLATE_ATTRIBUTES = {
"connection-factory", "message-converter", "destination-resolver", "pub-sub-domain",
"time-to-live", "priority", "delivery-persistent", "explicit-qos-enabled", "acknowledge",
- "receive-timeout"
+ "receive-timeout", "session-transacted"
};
@@ -138,8 +139,14 @@ abstract class JmsAdapterParserUtils {
}
Integer acknowledgeMode = parseAcknowledgeMode(element, parserContext);
if (acknowledgeMode != null) {
+ if (acknowledgeMode == SESSION_TRANSACTED) {
+ parserContext.getReaderContext().error(
+ "'transacted' is not a valid 'acknowledge-mode' here, use 'session-transacted'" +
+ " to enable transactions", element);
+ }
builder.addPropertyValue("sessionAcknowledgeMode", acknowledgeMode);
}
+ IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "session-transacted");
return builder.getBeanDefinition();
}
diff --git a/spring-integration-jms/src/main/java/org/springframework/integration/jms/config/JmsInboundChannelAdapterParser.java b/spring-integration-jms/src/main/java/org/springframework/integration/jms/config/JmsInboundChannelAdapterParser.java
index a9decccdd7..de58758448 100644
--- a/spring-integration-jms/src/main/java/org/springframework/integration/jms/config/JmsInboundChannelAdapterParser.java
+++ b/spring-integration-jms/src/main/java/org/springframework/integration/jms/config/JmsInboundChannelAdapterParser.java
@@ -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.
@@ -23,6 +23,7 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.AbstractPollingInboundChannelAdapterParser;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
+import org.springframework.integration.jms.JmsDestinationPollingSource;
import org.springframework.util.StringUtils;
/**
@@ -32,18 +33,19 @@ import org.springframework.util.StringUtils;
*/
public class JmsInboundChannelAdapterParser extends AbstractPollingInboundChannelAdapterParser {
+ @Override
protected boolean shouldGenerateId() {
return false;
}
+ @Override
protected boolean shouldGenerateIdAsFallback() {
return true;
}
@Override
protected BeanMetadataElement parseSource(Element element, ParserContext parserContext) {
- BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
- "org.springframework.integration.jms.JmsDestinationPollingSource");
+ BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(JmsDestinationPollingSource.class);
String componentName = this.resolveId(element, builder.getBeanDefinition(), parserContext);
if (StringUtils.hasText(componentName)) {
builder.addPropertyValue("componentName", componentName);
diff --git a/spring-integration-jms/src/main/java/org/springframework/integration/jms/config/JmsOutboundChannelAdapterParser.java b/spring-integration-jms/src/main/java/org/springframework/integration/jms/config/JmsOutboundChannelAdapterParser.java
index e55f7196a6..d10151e070 100644
--- a/spring-integration-jms/src/main/java/org/springframework/integration/jms/config/JmsOutboundChannelAdapterParser.java
+++ b/spring-integration-jms/src/main/java/org/springframework/integration/jms/config/JmsOutboundChannelAdapterParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2011 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.
@@ -24,19 +24,20 @@ import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.ExpressionFactoryBean;
import org.springframework.integration.config.xml.AbstractOutboundChannelAdapterParser;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
+import org.springframework.integration.jms.JmsSendingMessageHandler;
import org.springframework.util.StringUtils;
/**
* Parser for the <outbound-channel-adapter/> element of the jms namespace.
- *
+ *
* @author Mark Fisher
+ * @author Gary Russell
*/
public class JmsOutboundChannelAdapterParser extends AbstractOutboundChannelAdapterParser {
@Override
protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) {
- BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
- "org.springframework.integration.jms.JmsSendingMessageHandler");
+ BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(JmsSendingMessageHandler.class);
String jmsTemplate = element.getAttribute(JmsAdapterParserUtils.JMS_TEMPLATE_ATTRIBUTE);
String destination = element.getAttribute(JmsAdapterParserUtils.DESTINATION_ATTRIBUTE);
String destinationName = element.getAttribute(JmsAdapterParserUtils.DESTINATION_NAME_ATTRIBUTE);
@@ -53,7 +54,7 @@ public class JmsOutboundChannelAdapterParser extends AbstractOutboundChannelAdap
else {
builder.addConstructorArgValue(JmsAdapterParserUtils.parseJmsTemplateBeanDefinition(element, parserContext));
}
-
+
if (hasDestinationRef || hasDestinationName || hasDestinationExpression) {
if (!(hasDestinationRef ^ hasDestinationName ^ hasDestinationExpression)) {
parserContext.getReaderContext().error("The 'destination', 'destination-name', and " +
diff --git a/spring-integration-jms/src/main/resources/org/springframework/integration/jms/config/spring-integration-jms-4.0.xsd b/spring-integration-jms/src/main/resources/org/springframework/integration/jms/config/spring-integration-jms-4.0.xsd
index 2afcbcb39b..f1d739066c 100644
--- a/spring-integration-jms/src/main/resources/org/springframework/integration/jms/config/spring-integration-jms-4.0.xsd
+++ b/spring-integration-jms/src/main/resources/org/springframework/integration/jms/config/spring-integration-jms-4.0.xsd
@@ -548,6 +548,14 @@
+
+
+
+
+
@@ -1178,6 +1186,16 @@
]]>
+
+
+
+
+
diff --git a/spring-integration-jms/src/test/java/org/springframework/integration/jms/ActiveMQMultiContextTests.java b/spring-integration-jms/src/test/java/org/springframework/integration/jms/ActiveMQMultiContextTests.java
index 9b6475385f..28cefde979 100644
--- a/spring-integration-jms/src/test/java/org/springframework/integration/jms/ActiveMQMultiContextTests.java
+++ b/spring-integration-jms/src/test/java/org/springframework/integration/jms/ActiveMQMultiContextTests.java
@@ -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.
@@ -15,10 +15,13 @@
*/
package org.springframework.integration.jms;
+import javax.jms.ConnectionFactory;
+
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.transport.vm.VMTransport;
import org.junit.AfterClass;
import org.junit.BeforeClass;
+
import org.springframework.jms.connection.CachingConnectionFactory;
/**
@@ -31,8 +34,10 @@ import org.springframework.jms.connection.CachingConnectionFactory;
*/
public abstract class ActiveMQMultiContextTests {
- private static final CachingConnectionFactory connectionFactory = new CachingConnectionFactory(
- new ActiveMQConnectionFactory("vm://localhost?broker.persistent=false"));
+ protected static final ConnectionFactory amqFactory = new ActiveMQConnectionFactory("vm://localhost?broker.persistent=false");
+
+ protected static final CachingConnectionFactory connectionFactory = new CachingConnectionFactory(
+ amqFactory);
@BeforeClass
public static void startUp() throws Exception {
@@ -43,4 +48,5 @@ public abstract class ActiveMQMultiContextTests {
public static void shutDown() {
connectionFactory.resetConnection();
}
+
}
diff --git a/spring-integration-jms/src/test/java/org/springframework/integration/jms/JmsInboundChannelAdapterTests-context.xml b/spring-integration-jms/src/test/java/org/springframework/integration/jms/JmsInboundChannelAdapterTests-context.xml
new file mode 100644
index 0000000000..46cbab445a
--- /dev/null
+++ b/spring-integration-jms/src/test/java/org/springframework/integration/jms/JmsInboundChannelAdapterTests-context.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-integration-jms/src/test/java/org/springframework/integration/jms/JmsInboundChannelAdapterTests.java b/spring-integration-jms/src/test/java/org/springframework/integration/jms/JmsInboundChannelAdapterTests.java
new file mode 100644
index 0000000000..6364e1d041
--- /dev/null
+++ b/spring-integration-jms/src/test/java/org/springframework/integration/jms/JmsInboundChannelAdapterTests.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 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.
+ * 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;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import javax.jms.ConnectionFactory;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.ImportResource;
+import org.springframework.integration.jms.JmsInboundChannelAdapterTests.CFConfig;
+import org.springframework.jms.core.JmsTemplate;
+import org.springframework.messaging.PollableChannel;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+/**
+ * @author Gary Russell
+ * @since 4.0
+ *
+ */
+@ContextConfiguration(classes=CFConfig.class)
+@RunWith(SpringJUnit4ClassRunner.class)
+@DirtiesContext
+public class JmsInboundChannelAdapterTests extends ActiveMQMultiContextTests {
+
+ @Autowired
+ private PollableChannel out;
+
+ @Test
+ public void testTransactionalReceive() {
+ JmsTemplate template = new JmsTemplate(connectionFactory);
+ template.convertAndSend("foo", "bar");
+ assertNotNull(out.receive(2000));
+ /*
+ * INT-3288 - previously acknowledge="transacted"
+ * Caused by: javax.jms.JMSException: acknowledgeMode SESSION_TRANSACTED cannot be used for an non-transacted Session
+ */
+ assertNull(out.receive(1000));
+ }
+
+ @Configuration
+ @ImportResource("org/springframework/integration/jms/JmsInboundChannelAdapterTests-context.xml")
+ public static class CFConfig {
+
+ @Bean
+ public ConnectionFactory connectionFactory() {
+ return amqFactory;
+ }
+ }
+
+}
diff --git a/spring-integration-jms/src/test/java/org/springframework/integration/jms/JmsOutboundChannelAdapterTests-context.xml b/spring-integration-jms/src/test/java/org/springframework/integration/jms/JmsOutboundChannelAdapterTests-context.xml
new file mode 100644
index 0000000000..af8c0b1cfd
--- /dev/null
+++ b/spring-integration-jms/src/test/java/org/springframework/integration/jms/JmsOutboundChannelAdapterTests-context.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-integration-jms/src/test/java/org/springframework/integration/jms/JmsOutboundChannelAdapterTests.java b/spring-integration-jms/src/test/java/org/springframework/integration/jms/JmsOutboundChannelAdapterTests.java
new file mode 100644
index 0000000000..1eda51e267
--- /dev/null
+++ b/spring-integration-jms/src/test/java/org/springframework/integration/jms/JmsOutboundChannelAdapterTests.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 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.
+ * 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;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import javax.jms.ConnectionFactory;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.ImportResource;
+import org.springframework.integration.jms.JmsOutboundChannelAdapterTests.CFConfig;
+import org.springframework.jms.core.JmsTemplate;
+import org.springframework.messaging.PollableChannel;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+/**
+ * @author Gary Russell
+ * @since 4.0
+ *
+ */
+@ContextConfiguration(classes=CFConfig.class)
+@RunWith(SpringJUnit4ClassRunner.class)
+@DirtiesContext
+public class JmsOutboundChannelAdapterTests extends ActiveMQMultiContextTests {
+
+ @Autowired
+ private PollableChannel out;
+
+ @Autowired
+ private Aborter aborter;
+
+ @Autowired
+ private JmsMessageDrivenEndpoint endpoint;
+
+ @Test
+ public void testTransactionalSend() {
+ JmsTemplate template = new JmsTemplate(connectionFactory);
+ template.convertAndSend("foo", "Hello, world!");
+ template.setReceiveTimeout(1000);
+ assertNotNull(template.receive("bar"));
+
+ this.aborter.abort = true;
+ template.convertAndSend("foo", "Hello, world!");
+ assertNull(template.receive("bar"));
+ endpoint.stop();
+ }
+
+ @Configuration
+ @ImportResource("org/springframework/integration/jms/JmsOutboundChannelAdapterTests-context.xml")
+ public static class CFConfig {
+
+ @Bean
+ public ConnectionFactory connectionFactory() {
+ return connectionFactory;
+ }
+ }
+
+ public static class Aborter {
+
+ private volatile boolean abort;
+
+ public void foo() {
+ if (abort) {
+ throw new RuntimeException("intentional");
+ }
+ }
+ }
+
+}
diff --git a/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/JmsInboundChannelAdapterParserTests.java b/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/JmsInboundChannelAdapterParserTests.java
index fe4859d670..aa502f8007 100644
--- a/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/JmsInboundChannelAdapterParserTests.java
+++ b/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/JmsInboundChannelAdapterParserTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2010 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.
@@ -17,7 +17,9 @@
package org.springframework.integration.jms.config;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import java.util.Properties;
@@ -27,21 +29,22 @@ import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
-import org.springframework.messaging.Message;
-import org.springframework.messaging.PollableChannel;
import org.springframework.integration.history.MessageHistory;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.jms.core.JmsTemplate;
+import org.springframework.messaging.Message;
+import org.springframework.messaging.PollableChannel;
/**
* @author Mark Fisher
+ * @author Gary Russell
*/
public class JmsInboundChannelAdapterParserTests {
long timeoutOnReceive = 3000;
-
+
@Test
- public void adapterWithJmsTemplate() {
+ public void adapterWithJmsTemplate() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"jmsInboundWithJmsTemplate.xml", this.getClass());
PollableChannel output = (PollableChannel) context.getBean("output");
@@ -54,16 +57,18 @@ public class JmsInboundChannelAdapterParserTests {
assertNotNull("message should not be null", message);
assertEquals("polling-test", message.getPayload());
context.stop();
+ context.close();
}
-
+
@Test
- public void adapterWithoutJmsTemplateAndAcknowlegeMode() {
+ public void adapterWithoutJmsTemplateAndAcknowlegeMode() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"jmsInboundWithJmsTemplate.xml", this.getClass());
- JmsTemplate jmsTemplate =
+ JmsTemplate jmsTemplate =
TestUtils.getPropertyValue(context.getBean("inboundAdapterWithoutJmsTemplate"), "source.jmsTemplate", JmsTemplate.class);
- assertEquals(0, jmsTemplate.getSessionAcknowledgeMode());
+ assertTrue(jmsTemplate.isSessionTransacted());
context.stop();
+ context.close();
}
@Test
@@ -74,7 +79,10 @@ public class JmsInboundChannelAdapterParserTests {
Message> message = output.receive(timeoutOnReceive);
assertNotNull("message should not be null", message);
assertEquals("polling-test", message.getPayload());
+ assertFalse(TestUtils.getPropertyValue(context.getBean("adapter"), "source.jmsTemplate", JmsTemplate.class)
+ .isSessionTransacted());
context.stop();
+ context.close();
}
@Test
@@ -86,11 +94,12 @@ public class JmsInboundChannelAdapterParserTests {
assertNotNull("message should not be null", message);
assertEquals("polling-test", message.getPayload());
context.stop();
+ context.close();
}
@Test(expected = BeanDefinitionStoreException.class)
public void adapterWithConnectionFactoryOnly() {
- new ClassPathXmlApplicationContext("jmsInboundWithConnectionFactoryOnly.xml", this.getClass());
+ new ClassPathXmlApplicationContext("jmsInboundWithConnectionFactoryOnly.xml", this.getClass()).close();
}
@Test(expected = BeanCreationException.class)
@@ -114,11 +123,12 @@ public class JmsInboundChannelAdapterParserTests {
assertNotNull("message should not be null", message);
assertEquals("polling-test", message.getPayload());
context.stop();
+ context.close();
}
@Test(expected=BeanCreationException.class)
public void adapterWithDestinationNameOnly() {
- new ClassPathXmlApplicationContext("jmsInboundWithDestinationNameOnly.xml", this.getClass());
+ new ClassPathXmlApplicationContext("jmsInboundWithDestinationNameOnly.xml", this.getClass()).close();
}
@Test
@@ -130,6 +140,7 @@ public class JmsInboundChannelAdapterParserTests {
assertNotNull("message should not be null", message);
assertEquals("polling-test", message.getPayload());
context.stop();
+ context.close();
}
@Test
@@ -143,6 +154,7 @@ public class JmsInboundChannelAdapterParserTests {
assertEquals("foo", message.getHeaders().get("testProperty"));
assertEquals(new Integer(123), message.getHeaders().get("testAttribute"));
context.stop();
+ context.close();
}
@Test
@@ -154,15 +166,17 @@ public class JmsInboundChannelAdapterParserTests {
assertNotNull("message should not be null", message);
assertEquals("test [with selector: TestProperty = 'foo']", message.getPayload());
context.stop();
+ context.close();
}
@Test
public void pollingAdapterWithReceiveTimeout() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"jmsInboundWithReceiveTimeout.xml", this.getClass());
- JmsTemplate jmsTemplate =
+ JmsTemplate jmsTemplate =
TestUtils.getPropertyValue(context.getBean("adapter"), "source.jmsTemplate", JmsTemplate.class);
assertEquals(99, jmsTemplate.getReceiveTimeout());
+ context.close();
}
@Test
@@ -174,6 +188,7 @@ public class JmsInboundChannelAdapterParserTests {
assertNotNull("message should not be null", message);
assertEquals("converted-test", message.getPayload());
context.stop();
+ context.close();
}
@Test
@@ -185,6 +200,7 @@ public class JmsInboundChannelAdapterParserTests {
assertNotNull("message should not be null", message);
assertEquals("converted-test", message.getPayload());
context.stop();
+ context.close();
}
}
diff --git a/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/JmsOutboundChannelAdapterParserTests.java b/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/JmsOutboundChannelAdapterParserTests.java
index 3d4371fcbf..7178593440 100644
--- a/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/JmsOutboundChannelAdapterParserTests.java
+++ b/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/JmsOutboundChannelAdapterParserTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 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.
@@ -17,24 +17,26 @@
package org.springframework.integration.jms.config;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import javax.jms.DeliveryMode;
import org.junit.Test;
+
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
-import org.springframework.messaging.Message;
-import org.springframework.messaging.MessageHandler;
import org.springframework.integration.endpoint.EventDrivenConsumer;
import org.springframework.integration.handler.advice.AbstractRequestHandlerAdvice;
import org.springframework.integration.jms.JmsHeaderMapper;
-import org.springframework.messaging.support.GenericMessage;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.support.converter.MessageConverter;
+import org.springframework.messaging.Message;
+import org.springframework.messaging.MessageHandler;
+import org.springframework.messaging.support.GenericMessage;
/**
* @author Mark Fisher
@@ -52,6 +54,8 @@ public class JmsOutboundChannelAdapterParserTests {
DirectFieldAccessor accessor = new DirectFieldAccessor(
new DirectFieldAccessor(endpoint).getPropertyValue("handler"));
assertNotNull(accessor.getPropertyValue("jmsTemplate"));
+ assertTrue(TestUtils.getPropertyValue(endpoint, "handler.jmsTemplate.sessionTransacted", Boolean.class));
+ context.close();
}
@Test
@@ -62,6 +66,7 @@ public class JmsOutboundChannelAdapterParserTests {
MessageHandler handler = TestUtils.getPropertyValue(endpoint, "handler", MessageHandler.class);
handler.handleMessage(new GenericMessage("foo"));
assertEquals(1, adviceCalled);
+ context.close();
}
@Test
@@ -72,6 +77,8 @@ public class JmsOutboundChannelAdapterParserTests {
DirectFieldAccessor accessor = new DirectFieldAccessor(
new DirectFieldAccessor(endpoint).getPropertyValue("handler"));
assertNotNull(accessor.getPropertyValue("jmsTemplate"));
+ assertFalse(TestUtils.getPropertyValue(endpoint, "handler.jmsTemplate.sessionTransacted", Boolean.class));
+ context.close();
}
@Test
@@ -82,6 +89,7 @@ public class JmsOutboundChannelAdapterParserTests {
DirectFieldAccessor accessor = new DirectFieldAccessor(
new DirectFieldAccessor(endpoint).getPropertyValue("handler"));
assertNotNull(accessor.getPropertyValue("jmsTemplate"));
+ context.close();
}
@Test
@@ -93,6 +101,7 @@ public class JmsOutboundChannelAdapterParserTests {
new DirectFieldAccessor(endpoint).getPropertyValue("handler"));
Object order = accessor.getPropertyValue("order");
assertEquals(123, order);
+ context.close();
}
@Test
@@ -105,6 +114,7 @@ public class JmsOutboundChannelAdapterParserTests {
JmsHeaderMapper headerMapper = (JmsHeaderMapper) accessor.getPropertyValue("headerMapper");
assertNotNull(headerMapper);
assertEquals(TestJmsHeaderMapper.class, headerMapper.getClass());
+ context.close();
}
@Test
@@ -116,6 +126,7 @@ public class JmsOutboundChannelAdapterParserTests {
JmsTemplate jmsTemplate = (JmsTemplate) handlerAccessor.getPropertyValue("jmsTemplate");
assertNotNull(jmsTemplate);
assertEquals(context.getBean("template"), jmsTemplate);
+ context.close();
}
@Test
@@ -130,6 +141,7 @@ public class JmsOutboundChannelAdapterParserTests {
assertTrue(jmsTemplate.isExplicitQosEnabled());
assertEquals(7, jmsTemplate.getPriority());
assertEquals(12345, jmsTemplate.getTimeToLive());
+ context.close();
}
@Test
@@ -143,6 +155,7 @@ public class JmsOutboundChannelAdapterParserTests {
MessageConverter messageConverter = jmsTemlate.getMessageConverter();
assertNotNull(messageConverter);
assertEquals(TestMessageConverter.class, messageConverter.getClass());
+ context.close();
}
@Test(expected = BeanDefinitionStoreException.class)
@@ -168,6 +181,7 @@ public class JmsOutboundChannelAdapterParserTests {
assertEquals(12345L, accessor.getPropertyValue("timeToLive"));
assertEquals(7, accessor.getPropertyValue("priority"));
assertEquals(DeliveryMode.NON_PERSISTENT, accessor.getPropertyValue("deliveryMode"));
+ context.close();
}
@Test
@@ -179,6 +193,7 @@ public class JmsOutboundChannelAdapterParserTests {
new DirectFieldAccessor(new DirectFieldAccessor(endpoint).getPropertyValue("handler"))
.getPropertyValue("jmsTemplate"));
assertEquals(false, accessor.getPropertyValue("explicitQosEnabled"));
+ context.close();
}
public static class FooAdvice extends AbstractRequestHandlerAdvice {
diff --git a/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/jmsInboundWithConnectionFactoryAndDestination.xml b/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/jmsInboundWithConnectionFactoryAndDestination.xml
index d15818e15f..30844bd9a9 100644
--- a/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/jmsInboundWithConnectionFactoryAndDestination.xml
+++ b/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/jmsInboundWithConnectionFactoryAndDestination.xml
@@ -10,7 +10,8 @@
http://www.springframework.org/schema/integration/jms
http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd">
-
diff --git a/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/jmsInboundWithJmsTemplate.xml b/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/jmsInboundWithJmsTemplate.xml
index 6e1c3a1a5f..8f4ce253d0 100644
--- a/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/jmsInboundWithJmsTemplate.xml
+++ b/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/jmsInboundWithJmsTemplate.xml
@@ -14,7 +14,8 @@
-
diff --git a/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/jmsOutboundWithConnectionFactoryAndDestination.xml b/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/jmsOutboundWithConnectionFactoryAndDestination.xml
index 7681480200..eab56aa780 100644
--- a/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/jmsOutboundWithConnectionFactoryAndDestination.xml
+++ b/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/jmsOutboundWithConnectionFactoryAndDestination.xml
@@ -15,7 +15,8 @@
+ destination="testDestination"
+ session-transacted="true" />
diff --git a/src/reference/docbook/jms.xml b/src/reference/docbook/jms.xml
index d89adefea8..731cd6dd17 100644
--- a/src/reference/docbook/jms.xml
+++ b/src/reference/docbook/jms.xml
@@ -75,6 +75,28 @@
]]>
+
+ Transactions
+
+ Starting with version 4.0, the inbound channel adapter supports the
+ session-transacted attribute. In earlier versions, you had to inject a
+ JmsTemplate with sessionTransacted set to true.
+ (The adapter did allow the acknowledge attribute to be set to
+ transacted but this was incorrect and did not work).
+
+
+ Note, however, that setting session-transacted to true has
+ little value because the transaction is committed immediately after the receive()
+ and before the message is sent to the channel,
+
+
+ If you want the entire flow to be transactional (for example if there is a downstream
+ outbound channel adapter), you must use a transactional poller, with a
+ JmsTransactionManager. Or, consider using a
+ jms-message-driven-channel-adapter with acknowledge
+ set to transacted.
+
+
@@ -151,6 +173,18 @@
those cases, it's the JMS properties mapping to Spring Integration MessageHeaders).
+
+ Transactions
+
+ Starting with version 4.0, the outbound channel adapter supports the
+ session-transacted attribute. In earlier versions, you had to inject a
+ JmsTemplate with sessionTransacted set to true.
+ The attribute now sets the property on the built-in default JmsTemplate.
+ If a transaction exists (perhaps from an upstream message-driven-channel-adapter)
+ the send will be performed within the same transaction. Otherwise a new transaction will
+ be started.
+
+
diff --git a/src/reference/docbook/whats-new.xml b/src/reference/docbook/whats-new.xml
index 688bef819a..e2aca6ccf9 100644
--- a/src/reference/docbook/whats-new.xml
+++ b/src/reference/docbook/whats-new.xml
@@ -107,6 +107,24 @@
considered for outbound messages. For more information see .
+
+ JMS Outbound Channel Adapter
+
+ The JMS outbound channel adapter now supports the session-transacted attribute
+ (default false). Previously, you had to inject a customized JmsTemplate
+ to use transactions. See .
+
+
+
+ JMS Inbound Channel Adapter
+
+ The JMS inbound channel adapter now supports the session-transacted attribute
+ (default false). Previously, you had to inject a customized JmsTemplate
+ to use transactions (the adapter allowed 'transacted' in the acknowledgeMode which was
+ incorrect, and didn't work; this value is no longer allowed). See
+ .
+
+