Commit 441049cf authored by Stephane Nicoll's avatar Stephane Nicoll

Auto-detect JMS sessionTransacted flag

If a JtaTransactionManager is present, it is associated with the
auto-created JmsListenerContainerFactory. However, if no such transaction
manager is present, local transaction support is not enabled.

This gives a default situation where the message is acknowledged even
before the listener is invoked. We now make sure to turn on local JMS
transactions if no JtaTransactionManager is present.

Fixes gh-3393
parent f4c95eaf
...@@ -61,6 +61,9 @@ class JmsAnnotationDrivenConfiguration { ...@@ -61,6 +61,9 @@ class JmsAnnotationDrivenConfiguration {
if (this.transactionManager != null) { if (this.transactionManager != null) {
factory.setTransactionManager(this.transactionManager); factory.setTransactionManager(this.transactionManager);
} }
else {
factory.setSessionTransacted(true);
}
if (this.destinationResolver != null) { if (this.destinationResolver != null) {
factory.setDestinationResolver(this.destinationResolver); factory.setDestinationResolver(this.destinationResolver);
} }
......
...@@ -23,12 +23,14 @@ import org.apache.activemq.pool.PooledConnectionFactory; ...@@ -23,12 +23,14 @@ import org.apache.activemq.pool.PooledConnectionFactory;
import org.junit.After; import org.junit.After;
import org.junit.Test; import org.junit.Test;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration; import org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration;
import org.springframework.boot.test.EnvironmentTestUtils; import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jms.annotation.EnableJms; import org.springframework.jms.annotation.EnableJms;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory; import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerConfigUtils; import org.springframework.jms.config.JmsListenerConfigUtils;
...@@ -38,10 +40,13 @@ import org.springframework.jms.config.SimpleJmsListenerContainerFactory; ...@@ -38,10 +40,13 @@ import org.springframework.jms.config.SimpleJmsListenerContainerFactory;
import org.springframework.jms.core.JmsMessagingTemplate; import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.jms.core.JmsTemplate; import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.listener.DefaultMessageListenerContainer; import org.springframework.jms.listener.DefaultMessageListenerContainer;
import org.springframework.transaction.jta.JtaTransactionManager;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
...@@ -137,6 +142,48 @@ public class JmsAutoConfigurationTests { ...@@ -137,6 +142,48 @@ public class JmsAutoConfigurationTests {
jmsListenerContainerFactory.getClass()); jmsListenerContainerFactory.getClass());
} }
@Test
public void testDefaultContainerFactoryWithJtaTransactionManager() {
this.context = createContext(TestConfiguration7.class,
EnableJmsConfiguration.class);
JmsListenerContainerFactory<?> jmsListenerContainerFactory = this.context
.getBean("jmsListenerContainerFactory", JmsListenerContainerFactory.class);
assertEquals(DefaultJmsListenerContainerFactory.class,
jmsListenerContainerFactory.getClass());
DefaultMessageListenerContainer listenerContainer = ((DefaultJmsListenerContainerFactory)
jmsListenerContainerFactory).createListenerContainer(mock(JmsListenerEndpoint.class));
assertFalse("wrong session transacted flag with JTA transactions", listenerContainer.isSessionTransacted());
assertSame(this.context.getBean(JtaTransactionManager.class),
new DirectFieldAccessor(listenerContainer).getPropertyValue("transactionManager"));
}
@Test
public void testDefaultContainerFactoryNonJtaTransactionManager() {
this.context = createContext(TestConfiguration8.class,
EnableJmsConfiguration.class);
JmsListenerContainerFactory<?> jmsListenerContainerFactory = this.context
.getBean("jmsListenerContainerFactory", JmsListenerContainerFactory.class);
assertEquals(DefaultJmsListenerContainerFactory.class,
jmsListenerContainerFactory.getClass());
DefaultMessageListenerContainer listenerContainer = ((DefaultJmsListenerContainerFactory)
jmsListenerContainerFactory).createListenerContainer(mock(JmsListenerEndpoint.class));
assertTrue("wrong session transacted flag with no tx manager", listenerContainer.isSessionTransacted());
assertNull(new DirectFieldAccessor(listenerContainer).getPropertyValue("transactionManager"));
}
@Test
public void testDefaultContainerFactoryNoTransactionManager() {
this.context = createContext(EnableJmsConfiguration.class);
JmsListenerContainerFactory<?> jmsListenerContainerFactory = this.context
.getBean("jmsListenerContainerFactory", JmsListenerContainerFactory.class);
assertEquals(DefaultJmsListenerContainerFactory.class,
jmsListenerContainerFactory.getClass());
DefaultMessageListenerContainer listenerContainer = ((DefaultJmsListenerContainerFactory)
jmsListenerContainerFactory).createListenerContainer(mock(JmsListenerEndpoint.class));
assertTrue("wrong session transacted flag with no tx manager", listenerContainer.isSessionTransacted());
assertNull(new DirectFieldAccessor(listenerContainer).getPropertyValue("transactionManager"));
}
@Test @Test
public void testPubSubDisabledByDefault() { public void testPubSubDisabledByDefault() {
load(TestConfiguration.class); load(TestConfiguration.class);
...@@ -350,6 +397,26 @@ public class JmsAutoConfigurationTests { ...@@ -350,6 +397,26 @@ public class JmsAutoConfigurationTests {
} }
@Configuration
protected static class TestConfiguration7 {
@Bean
JtaTransactionManager transactionManager() {
return mock(JtaTransactionManager.class);
}
}
@Configuration
protected static class TestConfiguration8 {
@Bean
DataSourceTransactionManager transactionManager() {
return mock(DataSourceTransactionManager.class);
}
}
@Configuration @Configuration
@EnableJms @EnableJms
protected static class EnableJmsConfiguration { protected static class EnableJmsConfiguration {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment