diff --git a/spring-boot-autoconfigure/pom.xml b/spring-boot-autoconfigure/pom.xml
index 40e3303c5cb..b36152d2572 100644
--- a/spring-boot-autoconfigure/pom.xml
+++ b/spring-boot-autoconfigure/pom.xml
@@ -25,6 +25,16 @@
spring-boot
+
+ com.atomikos
+ transactions-jdbc
+ true
+
+
+ com.atomikos
+ transactions-jta
+ true
+
com.fasterxml.jackson.core
jackson-databind
@@ -80,6 +90,11 @@
velocity
true
+
+ org.codehaus.btm
+ btm
+ true
+
org.codehaus.groovy
groovy-templates
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jta/AtomikosJtaConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jta/AtomikosJtaConfiguration.java
new file mode 100644
index 00000000000..65ee8083f5c
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jta/AtomikosJtaConfiguration.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2012-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.boot.autoconfigure.jta;
+
+import java.io.File;
+import java.util.Properties;
+
+import javax.transaction.TransactionManager;
+import javax.transaction.UserTransaction;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.ApplicationHome;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.jta.XAConnectionFactoryWrapper;
+import org.springframework.boot.jta.XADataSourceWrapper;
+import org.springframework.boot.jta.atomikos.AtomikosDependsOnBeanFactoryPostProcessor;
+import org.springframework.boot.jta.atomikos.AtomikosProperties;
+import org.springframework.boot.jta.atomikos.AtomikosXAConnectionFactoryWrapper;
+import org.springframework.boot.jta.atomikos.AtomikosXADataSourceWrapper;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.jta.JtaTransactionManager;
+import org.springframework.util.StringUtils;
+
+import com.atomikos.icatch.config.UserTransactionService;
+import com.atomikos.icatch.config.UserTransactionServiceImp;
+import com.atomikos.icatch.jta.UserTransactionManager;
+
+/**
+ * JTA Configuration for Atomikos.
+ *
+ * @author Josh Long
+ * @author Phillip Webb
+ * @since 1.2.0
+ */
+@Configuration
+@ConditionalOnClass(UserTransactionManager.class)
+@ConditionalOnMissingBean(PlatformTransactionManager.class)
+class AtomikosJtaConfiguration {
+
+ @Autowired
+ private JtaProperties jtaProperties;
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConfigurationProperties(prefix = JtaProperties.PREFIX)
+ public AtomikosProperties atomikosProperties() {
+ return new AtomikosProperties();
+ }
+
+ @Bean(initMethod = "init", destroyMethod = "shutdownForce")
+ @ConditionalOnMissingBean
+ public UserTransactionService userTransactionService(
+ AtomikosProperties atomikosProperties) {
+ Properties properties = new Properties();
+ properties.setProperty("com.atomikos.icatch.log_base_dir", getLogBaseDir());
+ properties.putAll(atomikosProperties.asProperties());
+ return new UserTransactionServiceImp(properties);
+ }
+
+ private String getLogBaseDir() {
+ if (StringUtils.hasLength(this.jtaProperties.getLogDir())) {
+ return this.jtaProperties.getLogDir();
+ }
+ File home = new ApplicationHome().getDir();
+ return new File(home, "transaction-logs").getAbsolutePath();
+ }
+
+ @Bean(initMethod = "init", destroyMethod = "close")
+ @ConditionalOnMissingBean
+ public UserTransactionManager atomikosTransactionManager(
+ UserTransactionService userTransactionService) throws Exception {
+ UserTransactionManager manager = new UserTransactionManager();
+ manager.setStartupTransactionService(false);
+ manager.setForceShutdown(true);
+ return manager;
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public XADataSourceWrapper xaDataSourceWrapper() {
+ return new AtomikosXADataSourceWrapper();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public XAConnectionFactoryWrapper xaConnectionFactoryWrapper() {
+ return new AtomikosXAConnectionFactoryWrapper();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public static AtomikosDependsOnBeanFactoryPostProcessor atomikosDependsOnBeanFactoryPostProcessor() {
+ return new AtomikosDependsOnBeanFactoryPostProcessor();
+ }
+
+ @Bean
+ public JtaTransactionManager transactionManager(UserTransaction userTransaction,
+ TransactionManager transactionManager) {
+ return new JtaTransactionManager(userTransaction, transactionManager);
+ }
+
+}
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jta/BitronixJtaConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jta/BitronixJtaConfiguration.java
new file mode 100644
index 00000000000..6a3407a5e49
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jta/BitronixJtaConfiguration.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2012-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.boot.autoconfigure.jta;
+
+import java.io.File;
+
+import javax.transaction.TransactionManager;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.ApplicationHome;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.jta.XAConnectionFactoryWrapper;
+import org.springframework.boot.jta.XADataSourceWrapper;
+import org.springframework.boot.jta.bitronix.BitronixDependentBeanFactoryPostProcessor;
+import org.springframework.boot.jta.bitronix.BitronixXAConnectionFactoryWrapper;
+import org.springframework.boot.jta.bitronix.BitronixXADataSourceWrapper;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.jta.JtaTransactionManager;
+import org.springframework.util.StringUtils;
+
+import bitronix.tm.TransactionManagerServices;
+import bitronix.tm.jndi.BitronixContext;
+
+/**
+ * JTA Configuration for Bitronix.
+ *
+ * @author Josh Long
+ * @author Phillip Webb
+ * @since 1.2.0
+ */
+@Configuration
+@ConditionalOnClass(BitronixContext.class)
+@ConditionalOnMissingBean(PlatformTransactionManager.class)
+class BitronixJtaConfiguration {
+
+ @Autowired
+ private JtaProperties jtaProperties;
+
+ @Bean
+ @ConditionalOnMissingBean
+ @ConfigurationProperties(prefix = JtaProperties.PREFIX)
+ public bitronix.tm.Configuration bitronixConfiguration(JtaProperties xxx) {
+ bitronix.tm.Configuration config = TransactionManagerServices.getConfiguration();
+ config.setServerId("spring-boot-jta-bitronix");
+ File logBaseDir = getLogBaseDir();
+ config.setLogPart1Filename(new File(logBaseDir, "part1.btm").getAbsolutePath());
+ config.setLogPart2Filename(new File(logBaseDir, "part2.btm").getAbsolutePath());
+ config.setDisableJmx(true);
+ return config;
+ }
+
+ private File getLogBaseDir() {
+ if (StringUtils.hasLength(this.jtaProperties.getLogDir())) {
+ return new File(this.jtaProperties.getLogDir());
+ }
+ File home = new ApplicationHome().getDir();
+ return new File(home, "transaction-logs");
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public TransactionManager bitronixTransactionManager(
+ bitronix.tm.Configuration configuration) {
+ // Inject configuration to force ordering
+ return TransactionManagerServices.getTransactionManager();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public XADataSourceWrapper xaDataSourceWrapper() {
+ return new BitronixXADataSourceWrapper();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public XAConnectionFactoryWrapper xaConnectionFactoryWrapper() {
+ return new BitronixXAConnectionFactoryWrapper();
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public static BitronixDependentBeanFactoryPostProcessor atomikosDependsOnBeanFactoryPostProcessor() {
+ return new BitronixDependentBeanFactoryPostProcessor();
+ }
+
+ @Bean
+ public JtaTransactionManager transactionManager(TransactionManager transactionManager) {
+ return new JtaTransactionManager(transactionManager);
+ }
+
+}
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jta/JtaAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jta/JtaAutoConfiguration.java
new file mode 100644
index 00000000000..803d4c55e2b
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jta/JtaAutoConfiguration.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2012-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.boot.autoconfigure.jta;
+
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Import;
+
+/**
+ * {@link EnableAutoConfiguration Auto-configuration} for JTA.
+ *
+ * @author Josh Long
+ * @author Phillip Webb
+ * @since 1.2.0
+ */
+@ConditionalOnClass(javax.transaction.Transaction.class)
+@Import({ BitronixJtaConfiguration.class, AtomikosJtaConfiguration.class })
+@EnableConfigurationProperties(JtaProperties.class)
+public class JtaAutoConfiguration {
+
+}
diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jta/JtaProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jta/JtaProperties.java
new file mode 100644
index 00000000000..02fda641e9a
--- /dev/null
+++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jta/JtaProperties.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2012-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.boot.autoconfigure.jta;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.transaction.jta.JtaTransactionManager;
+
+/**
+ * External configuration properties for a {@link JtaTransactionManager} created by
+ * Spring. All {@literal spring.jta.} properties are also applied to the appropriate
+ * vendor specific configuration.
+ *
+ * @author Josh Long
+ * @author Phillip Webb
+ * @since 1.2.0
+ */
+@ConfigurationProperties(prefix = JtaProperties.PREFIX, ignoreUnknownFields = true)
+public class JtaProperties {
+
+ public static final String PREFIX = "spring.jta";
+
+ private String logDir;
+
+ public void setLogDir(String logDir) {
+ this.logDir = logDir;
+ }
+
+ public String getLogDir() {
+ return this.logDir;
+ }
+
+}
diff --git a/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories
index 8f1ba96768d..f2f147692ee 100644
--- a/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories
+++ b/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories
@@ -25,6 +25,7 @@ org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,\
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,\
org.springframework.boot.autoconfigure.jms.hornetq.HornetQAutoConfiguration,\
+org.springframework.boot.autoconfigure.jta.JtaAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchAutoConfiguration,\
org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchDataAutoConfiguration,\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jta/JtaAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jta/JtaAutoConfigurationTests.java
new file mode 100644
index 00000000000..f07097a6b26
--- /dev/null
+++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jta/JtaAutoConfigurationTests.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2012-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.boot.autoconfigure.jta;
+
+import javax.transaction.TransactionManager;
+import javax.transaction.UserTransaction;
+
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.boot.jta.XAConnectionFactoryWrapper;
+import org.springframework.boot.jta.XADataSourceWrapper;
+import org.springframework.boot.jta.atomikos.AtomikosDependsOnBeanFactoryPostProcessor;
+import org.springframework.boot.jta.atomikos.AtomikosProperties;
+import org.springframework.boot.jta.bitronix.BitronixDependentBeanFactoryPostProcessor;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.jta.JtaTransactionManager;
+
+import com.atomikos.icatch.config.UserTransactionService;
+import com.atomikos.icatch.jta.UserTransactionManager;
+
+import static org.mockito.Mockito.mock;
+
+/**
+ * Tests for {@link JtaAutoConfiguration}.
+ *
+ * @author Josh Long
+ * @author Phillip Webb
+ */
+public class JtaAutoConfigurationTests {
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ private AnnotationConfigApplicationContext context;
+
+ @After
+ public void closeContext() {
+ if (this.context != null) {
+ this.context.close();
+ }
+ }
+
+ @Test
+ public void customPatformTransactionManager() throws Exception {
+ this.context = new AnnotationConfigApplicationContext(
+ CustomTransactionManagerConfig.class, JtaAutoConfiguration.class);
+ this.thrown.expect(NoSuchBeanDefinitionException.class);
+ this.context.getBean(JtaTransactionManager.class);
+ }
+
+ @Test
+ public void atomikosSanityCheck() throws Exception {
+ this.context = new AnnotationConfigApplicationContext(JtaProperties.class,
+ AtomikosJtaConfiguration.class);
+ this.context.getBean(AtomikosProperties.class);
+ this.context.getBean(UserTransactionService.class);
+ this.context.getBean(UserTransactionManager.class);
+ this.context.getBean(UserTransaction.class);
+ this.context.getBean(XADataSourceWrapper.class);
+ this.context.getBean(XAConnectionFactoryWrapper.class);
+ this.context.getBean(AtomikosDependsOnBeanFactoryPostProcessor.class);
+ this.context.getBean(JtaTransactionManager.class);
+ }
+
+ @Test
+ public void bitronixSanityCheck() throws Exception {
+ this.context = new AnnotationConfigApplicationContext(JtaProperties.class,
+ BitronixJtaConfiguration.class);
+ this.context.getBean(bitronix.tm.Configuration.class);
+ this.context.getBean(TransactionManager.class);
+ this.context.getBean(XADataSourceWrapper.class);
+ this.context.getBean(XAConnectionFactoryWrapper.class);
+ this.context.getBean(BitronixDependentBeanFactoryPostProcessor.class);
+ this.context.getBean(JtaTransactionManager.class);
+ }
+
+ @Configuration
+ public static class CustomTransactionManagerConfig {
+
+ @Bean
+ public PlatformTransactionManager transactionManager() {
+ return mock(PlatformTransactionManager.class);
+ }
+
+ }
+
+}
diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/AbstractJpaAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/AbstractJpaAutoConfigurationTests.java
index 1e6734d164e..d68309630f0 100644
--- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/AbstractJpaAutoConfigurationTests.java
+++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/AbstractJpaAutoConfigurationTests.java
@@ -17,11 +17,12 @@
package org.springframework.boot.autoconfigure.orm.jpa;
import java.lang.reflect.Field;
-import java.util.Collections;
+import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
+import org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
@@ -228,8 +229,10 @@ public abstract class AbstractJpaAutoConfigurationTests {
factoryBean.setJpaVendorAdapter(adapter);
factoryBean.setDataSource(dataSource);
factoryBean.setPersistenceUnitName("manually-configured");
- factoryBean.setJpaPropertyMap(Collections.singletonMap("configured",
- "manually"));
+ Map properties = new HashMap();
+ properties.put("configured", "manually");
+ properties.put("hibernate.transaction.jta.platform", NoJtaPlatform.INSTANCE);
+ factoryBean.setJpaPropertyMap(properties);
return factoryBean;
}
}
diff --git a/spring-boot/src/main/java/org/springframework/boot/jta/XAConnectionFactoryWrapper.java b/spring-boot/src/main/java/org/springframework/boot/jta/XAConnectionFactoryWrapper.java
new file mode 100644
index 00000000000..4680fb5c9a9
--- /dev/null
+++ b/spring-boot/src/main/java/org/springframework/boot/jta/XAConnectionFactoryWrapper.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2012-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.boot.jta;
+
+import javax.jms.ConnectionFactory;
+import javax.jms.XAConnectionFactory;
+import javax.transaction.TransactionManager;
+
+/**
+ * Strategy interface used to wrap a JMS {@link XAConnectionFactory} enrolling it with a
+ * JTA {@link TransactionManager}.
+ *
+ * @author Phillip Webb
+ * @since 1.2.0
+ */
+public interface XAConnectionFactoryWrapper {
+
+ /**
+ * Wrap the specific {@link XAConnectionFactory} and enroll it with a JTA
+ * {@link TransactionManager}.
+ * @param connectionFactory the connection factory to wrap
+ * @return the wrapped connection factory
+ */
+ ConnectionFactory wrapConnectionFactory(XAConnectionFactory connectionFactory)
+ throws Exception;
+
+}
diff --git a/spring-boot/src/main/java/org/springframework/boot/jta/XADataSourceWrapper.java b/spring-boot/src/main/java/org/springframework/boot/jta/XADataSourceWrapper.java
new file mode 100644
index 00000000000..1ee8d818b72
--- /dev/null
+++ b/spring-boot/src/main/java/org/springframework/boot/jta/XADataSourceWrapper.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2012-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.boot.jta;
+
+import javax.sql.DataSource;
+import javax.sql.XADataSource;
+import javax.transaction.TransactionManager;
+
+/**
+ * Strategy interface used to wrap a JMS {@link XADataSource} enrolling it with a JTA
+ * {@link TransactionManager}.
+ *
+ * @author Phillip Webb
+ * @since 1.2.0
+ */
+public interface XADataSourceWrapper {
+
+ /**
+ * Wrap the specific {@link XADataSource} and enroll it with a JTA
+ * {@link TransactionManager}.
+ * @param dataSource the data source to wrap
+ * @return the wrapped data source
+ */
+ DataSource wrapDataSource(XADataSource dataSource) throws Exception;
+
+}
diff --git a/spring-boot/src/main/java/org/springframework/boot/jta/atomikos/AtomikosXAConnectionFactoryWrapper.java b/spring-boot/src/main/java/org/springframework/boot/jta/atomikos/AtomikosXAConnectionFactoryWrapper.java
new file mode 100644
index 00000000000..c370bb945bd
--- /dev/null
+++ b/spring-boot/src/main/java/org/springframework/boot/jta/atomikos/AtomikosXAConnectionFactoryWrapper.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2012-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.boot.jta.atomikos;
+
+import javax.jms.ConnectionFactory;
+import javax.jms.XAConnectionFactory;
+
+import org.springframework.boot.jta.XAConnectionFactoryWrapper;
+
+/**
+ * {@link XAConnectionFactoryWrapper} that uses an {@link AtomikosConnectionFactoryBean}
+ * to wrap a {@link XAConnectionFactory}.
+ *
+ * @author Phillip Webb
+ * @since 1.2.0
+ */
+public class AtomikosXAConnectionFactoryWrapper implements XAConnectionFactoryWrapper {
+
+ @Override
+ public ConnectionFactory wrapConnectionFactory(XAConnectionFactory connectionFactory) {
+ AtomikosConnectionFactoryBean bean = new AtomikosConnectionFactoryBean();
+ bean.setXaConnectionFactory(connectionFactory);
+ return bean;
+ }
+
+}
diff --git a/spring-boot/src/main/java/org/springframework/boot/jta/atomikos/AtomikosXADataSourceWrapper.java b/spring-boot/src/main/java/org/springframework/boot/jta/atomikos/AtomikosXADataSourceWrapper.java
new file mode 100644
index 00000000000..28fc7f778bc
--- /dev/null
+++ b/spring-boot/src/main/java/org/springframework/boot/jta/atomikos/AtomikosXADataSourceWrapper.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2012-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.boot.jta.atomikos;
+
+import javax.sql.XADataSource;
+
+import org.springframework.boot.jta.XADataSourceWrapper;
+
+/**
+ * {@link XADataSourceWrapper} that uses an {@link AtomikosDataSourceBean} to wrap a
+ * {@link XADataSource}.
+ *
+ * @author Phillip Webb
+ * @since 1.2.0
+ */
+public class AtomikosXADataSourceWrapper implements XADataSourceWrapper {
+
+ @Override
+ public AtomikosDataSourceBean wrapDataSource(XADataSource dataSource)
+ throws Exception {
+ AtomikosDataSourceBean bean = new AtomikosDataSourceBean();
+ bean.setXaDataSource(dataSource);
+ return bean;
+ }
+
+}
diff --git a/spring-boot/src/main/java/org/springframework/boot/jta/bitronix/BitronixXAConnectionFactoryWrapper.java b/spring-boot/src/main/java/org/springframework/boot/jta/bitronix/BitronixXAConnectionFactoryWrapper.java
new file mode 100644
index 00000000000..6a539c9a0ca
--- /dev/null
+++ b/spring-boot/src/main/java/org/springframework/boot/jta/bitronix/BitronixXAConnectionFactoryWrapper.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2012-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.boot.jta.bitronix;
+
+import javax.jms.ConnectionFactory;
+import javax.jms.XAConnectionFactory;
+
+import org.springframework.boot.jta.XAConnectionFactoryWrapper;
+
+/**
+ * {@link XAConnectionFactoryWrapper} that uses a Bitronix
+ * {@link PoolingConnectionFactoryBean} to wrap a {@link XAConnectionFactory}.
+ *
+ * @author Phillip Webb
+ * @since 1.2.0
+ */
+public class BitronixXAConnectionFactoryWrapper implements XAConnectionFactoryWrapper {
+
+ @Override
+ public ConnectionFactory wrapConnectionFactory(XAConnectionFactory connectionFactory) {
+ PoolingConnectionFactoryBean pool = new PoolingConnectionFactoryBean();
+ pool.setConnectionFactory(connectionFactory);
+ return pool;
+ }
+
+}
diff --git a/spring-boot/src/main/java/org/springframework/boot/jta/bitronix/BitronixXADataSourceWrapper.java b/spring-boot/src/main/java/org/springframework/boot/jta/bitronix/BitronixXADataSourceWrapper.java
new file mode 100644
index 00000000000..2edd1a07bff
--- /dev/null
+++ b/spring-boot/src/main/java/org/springframework/boot/jta/bitronix/BitronixXADataSourceWrapper.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2012-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.boot.jta.bitronix;
+
+import javax.sql.XADataSource;
+
+import org.springframework.boot.jta.XADataSourceWrapper;
+
+/**
+ * {@link XADataSourceWrapper} that uses a Bitronix {@link PoolingDataSourceBean} to wrap
+ * a {@link XADataSource}.
+ *
+ * @author Phillip Webb
+ * @since 1.2.0
+ */
+public class BitronixXADataSourceWrapper implements XADataSourceWrapper {
+
+ @Override
+ public PoolingDataSourceBean wrapDataSource(XADataSource dataSource) throws Exception {
+ PoolingDataSourceBean pool = new PoolingDataSourceBean();
+ pool.setDataSource(dataSource);
+ return pool;
+ }
+
+}
diff --git a/spring-boot/src/test/java/org/springframework/boot/jta/atomikos/AtomikosXAConnectionFactoryWrapperTests.java b/spring-boot/src/test/java/org/springframework/boot/jta/atomikos/AtomikosXAConnectionFactoryWrapperTests.java
new file mode 100644
index 00000000000..3745522fd66
--- /dev/null
+++ b/spring-boot/src/test/java/org/springframework/boot/jta/atomikos/AtomikosXAConnectionFactoryWrapperTests.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2012-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.boot.jta.atomikos;
+
+import javax.jms.ConnectionFactory;
+import javax.jms.XAConnectionFactory;
+
+import org.junit.Test;
+
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+
+/**
+ * Tests for {@link AtomikosXAConnectionFactoryWrapper}.
+ *
+ * @author Phillip Webb
+ */
+public class AtomikosXAConnectionFactoryWrapperTests {
+
+ @Test
+ public void wrap() {
+ XAConnectionFactory connectionFactory = mock(XAConnectionFactory.class);
+ AtomikosXAConnectionFactoryWrapper wrapper = new AtomikosXAConnectionFactoryWrapper();
+ ConnectionFactory wrapped = wrapper.wrapConnectionFactory(connectionFactory);
+ assertThat(wrapped, instanceOf(AtomikosConnectionFactoryBean.class));
+ assertThat(((AtomikosConnectionFactoryBean) wrapped).getXaConnectionFactory(),
+ sameInstance(connectionFactory));
+ }
+
+}
diff --git a/spring-boot/src/test/java/org/springframework/boot/jta/atomikos/AtomikosXADataSourceWrapperTests.java b/spring-boot/src/test/java/org/springframework/boot/jta/atomikos/AtomikosXADataSourceWrapperTests.java
new file mode 100644
index 00000000000..c2d6e56a5fb
--- /dev/null
+++ b/spring-boot/src/test/java/org/springframework/boot/jta/atomikos/AtomikosXADataSourceWrapperTests.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2012-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.boot.jta.atomikos;
+
+import javax.sql.DataSource;
+import javax.sql.XADataSource;
+
+import org.junit.Test;
+
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+
+/**
+ * Tests for {@link AtomikosXADataSourceWrapper}.
+ *
+ * @author Phillip Webb
+ */
+public class AtomikosXADataSourceWrapperTests {
+
+ @Test
+ public void wrap() throws Exception {
+ XADataSource dataSource = mock(XADataSource.class);
+ AtomikosXADataSourceWrapper wrapper = new AtomikosXADataSourceWrapper();
+ DataSource wrapped = wrapper.wrapDataSource(dataSource);
+ assertThat(wrapped, instanceOf(AtomikosDataSourceBean.class));
+ assertThat(((AtomikosDataSourceBean) wrapped).getXaDataSource(),
+ sameInstance(dataSource));
+ }
+
+}
diff --git a/spring-boot/src/test/java/org/springframework/boot/jta/bitronix/BitronixXAConnectionFactoryWrapperTests.java b/spring-boot/src/test/java/org/springframework/boot/jta/bitronix/BitronixXAConnectionFactoryWrapperTests.java
new file mode 100644
index 00000000000..fca543971b5
--- /dev/null
+++ b/spring-boot/src/test/java/org/springframework/boot/jta/bitronix/BitronixXAConnectionFactoryWrapperTests.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2012-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.boot.jta.bitronix;
+
+import javax.jms.ConnectionFactory;
+import javax.jms.XAConnectionFactory;
+
+import org.junit.Test;
+
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+
+/**
+ * Tests for {@link BitronixXAConnectionFactoryWrapper}.
+ *
+ * @author Phillip Webb
+ */
+public class BitronixXAConnectionFactoryWrapperTests {
+
+ @Test
+ public void wrap() {
+ XAConnectionFactory connectionFactory = mock(XAConnectionFactory.class);
+ BitronixXAConnectionFactoryWrapper wrapper = new BitronixXAConnectionFactoryWrapper();
+ ConnectionFactory wrapped = wrapper.wrapConnectionFactory(connectionFactory);
+ assertThat(wrapped, instanceOf(PoolingConnectionFactoryBean.class));
+ assertThat(((PoolingConnectionFactoryBean) wrapped).getConnectionFactory(),
+ sameInstance(connectionFactory));
+ }
+
+}
diff --git a/spring-boot/src/test/java/org/springframework/boot/jta/bitronix/BitronixXADataSourceWrapperTests.java b/spring-boot/src/test/java/org/springframework/boot/jta/bitronix/BitronixXADataSourceWrapperTests.java
new file mode 100644
index 00000000000..abea4324404
--- /dev/null
+++ b/spring-boot/src/test/java/org/springframework/boot/jta/bitronix/BitronixXADataSourceWrapperTests.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2012-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.boot.jta.bitronix;
+
+import javax.sql.DataSource;
+import javax.sql.XADataSource;
+
+import org.junit.Test;
+
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.sameInstance;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+
+/**
+ * Tests for {@link BitronixXADataSourceWrapper}.
+ *
+ * @author Phillip Webb
+ */
+public class BitronixXADataSourceWrapperTests {
+
+ @Test
+ public void wrap() throws Exception {
+ XADataSource dataSource = mock(XADataSource.class);
+ BitronixXADataSourceWrapper wrapper = new BitronixXADataSourceWrapper();
+ DataSource wrapped = wrapper.wrapDataSource(dataSource);
+ assertThat(wrapped, instanceOf(PoolingDataSourceBean.class));
+ assertThat(((PoolingDataSourceBean) wrapped).getDataSource(),
+ sameInstance(dataSource));
+ }
+
+}