diff --git a/spring-boot-dependencies/pom.xml b/spring-boot-dependencies/pom.xml
index 9a5707e86e..1811d1b319 100644
--- a/spring-boot-dependencies/pom.xml
+++ b/spring-boot-dependencies/pom.xml
@@ -48,6 +48,7 @@
5.9.1
1.8.2
+ 3.9.3
3.0.2
1.9.2
3.2.1
@@ -85,6 +86,7 @@
1.2.2
0.9.1
1.2
+ 1.1
4.11
3.0.8
1.2.17
@@ -350,6 +352,21 @@
logback-classic
${logback.version}
+
+ com.atomikos
+ transactions-jdbc
+ ${atomikos.version}
+
+
+ com.atomikos
+ transactions-jms
+ ${atomikos.version}
+
+
+ com.atomikos
+ transactions-jta
+ ${atomikos.version}
+
com.codahale.metrics
metrics-graphite
@@ -482,6 +499,11 @@
jstl
${jstl.version}
+
+ javax.transaction
+ jta
+ ${jta.version}
+
jaxen
jaxen
diff --git a/spring-boot/pom.xml b/spring-boot/pom.xml
index 86d4e5f2df..d37027dc2c 100644
--- a/spring-boot/pom.xml
+++ b/spring-boot/pom.xml
@@ -34,11 +34,31 @@
logback-classic
true
+
+ com.atomikos
+ transactions-jms
+ true
+
+
+ com.atomikos
+ transactions-jta
+ true
+
+
+ com.atomikos
+ transactions-jdbc
+ true
+
com.fasterxml.jackson.core
jackson-databind
true
+
+ javax.jms
+ jms-api
+ true
+
javax.servlet
javax.servlet-api
diff --git a/spring-boot/src/main/java/org/springframework/boot/jta/atomikos/AtomikosConnectionFactoryBean.java b/spring-boot/src/main/java/org/springframework/boot/jta/atomikos/AtomikosConnectionFactoryBean.java
new file mode 100644
index 0000000000..9559ed1b5f
--- /dev/null
+++ b/spring-boot/src/main/java/org/springframework/boot/jta/atomikos/AtomikosConnectionFactoryBean.java
@@ -0,0 +1,54 @@
+/*
+ * 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 org.springframework.beans.factory.BeanNameAware;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.util.StringUtils;
+
+/**
+ * Spring friendly version of {@link com.atomikos.jms.AtomikosConnectionFactoryBean}.
+ *
+ * @author Phillip Webb
+ * @since 1.2.0
+ */
+public class AtomikosConnectionFactoryBean extends
+ com.atomikos.jms.AtomikosConnectionFactoryBean implements BeanNameAware,
+ InitializingBean, DisposableBean {
+
+ private String beanName;
+
+ @Override
+ public void setBeanName(String name) {
+ this.beanName = name;
+ }
+
+ @Override
+ public void afterPropertiesSet() throws Exception {
+ if (!StringUtils.hasLength(getUniqueResourceName())) {
+ setUniqueResourceName(this.beanName);
+ }
+ init();
+ }
+
+ @Override
+ public void destroy() throws Exception {
+ close();
+ }
+
+}
diff --git a/spring-boot/src/main/java/org/springframework/boot/jta/atomikos/AtomikosDataSourceBean.java b/spring-boot/src/main/java/org/springframework/boot/jta/atomikos/AtomikosDataSourceBean.java
new file mode 100644
index 0000000000..d601aaf37a
--- /dev/null
+++ b/spring-boot/src/main/java/org/springframework/boot/jta/atomikos/AtomikosDataSourceBean.java
@@ -0,0 +1,53 @@
+/*
+ * 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 org.springframework.beans.factory.BeanNameAware;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.util.StringUtils;
+
+/**
+ * Spring friendly version of {@link com.atomikos.jdbc.AtomikosDataSourceBean}.
+ *
+ * @author Phillip Webb
+ * @since 1.2.0
+ */
+public class AtomikosDataSourceBean extends com.atomikos.jdbc.AtomikosDataSourceBean
+ implements BeanNameAware, InitializingBean, DisposableBean {
+
+ private String beanName;
+
+ @Override
+ public void setBeanName(String name) {
+ this.beanName = name;
+ }
+
+ @Override
+ public void afterPropertiesSet() throws Exception {
+ if (!StringUtils.hasLength(getUniqueResourceName())) {
+ setUniqueResourceName(this.beanName);
+ }
+ init();
+ }
+
+ @Override
+ public void destroy() throws Exception {
+ close();
+ }
+
+}
diff --git a/spring-boot/src/main/java/org/springframework/boot/jta/atomikos/AtomikosDependsOnBeanFactoryPostProcessor.java b/spring-boot/src/main/java/org/springframework/boot/jta/atomikos/AtomikosDependsOnBeanFactoryPostProcessor.java
new file mode 100644
index 0000000000..4d0fdc22dd
--- /dev/null
+++ b/spring-boot/src/main/java/org/springframework/boot/jta/atomikos/AtomikosDependsOnBeanFactoryPostProcessor.java
@@ -0,0 +1,113 @@
+/*
+ * 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 java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.core.Ordered;
+
+import com.atomikos.icatch.jta.UserTransactionManager;
+
+/**
+ * {@link BeanFactoryPostProcessor} to automatically setup the recommended
+ * {@link BeanDefinition#setDependsOn(String[]) dependsOn} settings for correct Atomikos
+ * ordering.
+ *
+ * @author Phillip Webb
+ * @since 1.2.0
+ */
+public class AtomikosDependsOnBeanFactoryPostProcessor implements
+ BeanFactoryPostProcessor, Ordered {
+
+ private static final String[] NO_BEANS = {};
+
+ private int order = Ordered.LOWEST_PRECEDENCE;
+
+ @Override
+ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
+ throws BeansException {
+ String[] transactionManagers = beanFactory.getBeanNamesForType(
+ UserTransactionManager.class, true, false);
+ for (String transactionManager : transactionManagers) {
+ addTransactionManagerDependencies(beanFactory, transactionManager);
+ }
+ addMessageDrivenContainerDependencies(beanFactory, transactionManagers);
+ }
+
+ private void addTransactionManagerDependencies(
+ ConfigurableListableBeanFactory beanFactory, String transactionManager) {
+ BeanDefinition bean = beanFactory.getBeanDefinition(transactionManager);
+ Set dependsOn = new LinkedHashSet(asList(bean.getDependsOn()));
+ int initialSize = dependsOn.size();
+ addDependencies(beanFactory, "javax.jms.ConnectionFactory", dependsOn);
+ addDependencies(beanFactory, "javax.sql.DataSource", dependsOn);
+ if (dependsOn.size() != initialSize) {
+ bean.setDependsOn(dependsOn.toArray(new String[dependsOn.size()]));
+ }
+ }
+
+ private void addMessageDrivenContainerDependencies(
+ ConfigurableListableBeanFactory beanFactory, String[] transactionManagers) {
+ String[] messageDrivenContainers = getBeanNamesForType(beanFactory,
+ "com.atomikos.jms.extra.MessageDrivenContainer");
+ for (String messageDrivenContainer : messageDrivenContainers) {
+ BeanDefinition bean = beanFactory.getBeanDefinition(messageDrivenContainer);
+ Set dependsOn = new LinkedHashSet(asList(bean.getDependsOn()));
+ dependsOn.addAll(asList(transactionManagers));
+ bean.setDependsOn(dependsOn.toArray(new String[dependsOn.size()]));
+ }
+ }
+
+ private void addDependencies(ConfigurableListableBeanFactory beanFactory,
+ String type, Set dependsOn) {
+ dependsOn.addAll(asList(getBeanNamesForType(beanFactory, type)));
+ }
+
+ private String[] getBeanNamesForType(ConfigurableListableBeanFactory beanFactory,
+ String type) {
+ try {
+ return beanFactory.getBeanNamesForType(Class.forName(type), true, false);
+ }
+ catch (ClassNotFoundException ex) {
+ // Ignore
+ }
+ return NO_BEANS;
+ }
+
+ private List asList(String[] array) {
+ return (array == null ? Collections. emptyList() : Arrays.asList(array));
+ }
+
+ @Override
+ public int getOrder() {
+ return this.order;
+ }
+
+ public void setOrder(int order) {
+ this.order = order;
+ }
+
+}
diff --git a/spring-boot/src/main/java/org/springframework/boot/jta/atomikos/AtomikosLoggingLevel.java b/spring-boot/src/main/java/org/springframework/boot/jta/atomikos/AtomikosLoggingLevel.java
new file mode 100644
index 0000000000..39e5fca759
--- /dev/null
+++ b/spring-boot/src/main/java/org/springframework/boot/jta/atomikos/AtomikosLoggingLevel.java
@@ -0,0 +1,43 @@
+/*
+ * 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;
+
+/**
+ * Logging levels supported by Atomikos.
+ *
+ * @author Phillip Webb
+ * @see AtomikosProperties
+ * @since 1.2.0
+ */
+public enum AtomikosLoggingLevel {
+
+ /**
+ * Debug Level.
+ */
+ DEBUG,
+
+ /**
+ * Info Level.
+ */
+ INFO,
+
+ /**
+ * Warning Level.
+ */
+ WARN
+
+}
diff --git a/spring-boot/src/main/java/org/springframework/boot/jta/atomikos/AtomikosProperties.java b/spring-boot/src/main/java/org/springframework/boot/jta/atomikos/AtomikosProperties.java
new file mode 100644
index 0000000000..5222846035
--- /dev/null
+++ b/spring-boot/src/main/java/org/springframework/boot/jta/atomikos/AtomikosProperties.java
@@ -0,0 +1,237 @@
+/*
+ * 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 java.util.Map;
+import java.util.Properties;
+import java.util.TreeMap;
+
+/**
+ * Bean friendly variant of Atomikos configuration
+ * properties. Allows for setter based configuration and is amiable to relaxed data
+ * binding.
+ *
+ * @author Phillip Webb
+ * @see #asProperties()
+ * @since 1.2.0
+ */
+public class AtomikosProperties {
+
+ private final Map values = new TreeMap();
+
+ /**
+ * Specifies the transaction manager implementation that should be started. There is
+ * no default value and this must be set. Generally,
+ * {@literal com.atomikos.icatch.standalone.UserTransactionServiceFactory} is the
+ * value you should set.
+ * @param service the service
+ */
+ public void setService(String service) {
+ set("service", service);
+ }
+
+ /**
+ * Specifies the maximum timeout (in milliseconds) that can be allowed for
+ * transactions. Defaults to {@literal 300000}. This means that calls to
+ * UserTransaction.setTransactionTimeout() with a value higher than configured here
+ * will be max'ed to this value.
+ * @param maxTimeout the max timeout
+ */
+ public void setMaxTimeout(long maxTimeout) {
+ set("max_timeout", maxTimeout);
+ }
+
+ /**
+ * The default timeout for JTA transactions (optional, defaults to {@literal 10000}
+ * ms).
+ * @param defaultJtaTimeout the default JTA timeout
+ */
+ public void setDefaultJtaTimeout(long defaultJtaTimeout) {
+ set("default_jta_timeout", defaultJtaTimeout);
+ }
+
+ /**
+ * Specifies the maximum number of active transactions. Defaults to {@literal 50}. A
+ * negative value means infinite amount. You will get an {@code IllegalStateException}
+ * with error message "Max number of active transactions reached" if you call
+ * {@code UserTransaction.begin()} while there are already n concurrent transactions
+ * running, n being this value.
+ * @param maxActivities the max activities
+ */
+ public void setMaxActives(int maxActivities) {
+ set("max_actives", maxActivities);
+ }
+
+ /**
+ * Specifies if disk logging should be enabled or not. Defaults to true. It is useful
+ * for JUnit testing, or to profile code without seeing the transaction manager's
+ * activity as a hot spot but this should never be disabled on production or data
+ * integrity cannot be guaranteed.
+ * @param enableLogging if logging is enabled
+ */
+ public void setEnableLogging(boolean enableLogging) {
+ set("enable_logging", enableLogging);
+ }
+
+ /**
+ * Specifies the transaction manager's unique name. Defaults to the machine's IP
+ * address. If you plan to run more than one transaction manager against one database
+ * you must set this property to a unique value or you might run into duplicate
+ * transaction ID (XID) problems that can be quite subtle (example:
+ * {@literal http://fogbugz.atomikos.com/default.asp?community.6.2225.7}). If multiple
+ * instances need to use the same properties file then the easiest way to ensure
+ * uniqueness for this property is by referencing a system property specified at VM
+ * startup.
+ * @param uniqueName the unique name
+ */
+ public void setTransactionManagerUniqueName(String uniqueName) {
+ set("tm_unique_name", uniqueName);
+ }
+
+ /**
+ * Specifies if subtransactions should be joined when possible. Defaults to true. When
+ * false, no attempt to call {@code XAResource.start(TM_JOIN)} will be made for
+ * different but related subtransctions. This setting has no effect on resource access
+ * within one and the same transaction. If you don't use subtransactions then this
+ * setting can be ignored.
+ * @param serialJtaTransactions if serial JTA transaction are supported
+ */
+ public void setSerialJtaTransactions(boolean serialJtaTransactions) {
+ set("serial_jta_transactions", serialJtaTransactions);
+ }
+
+ /**
+ * Specifies whether VM shutdown should trigger forced shutdown of the transaction
+ * core. Defaults to false.
+ * @param forceShutdownOnVmExit
+ */
+ public void setForceShutdownOnVmExit(boolean forceShutdownOnVmExit) {
+ set("force_shutdown_on_vm_exit", forceShutdownOnVmExit);
+ }
+
+ /**
+ * Specifies the transactions log file base name. Defaults to {@literal tmlog}. The
+ * transactions logs are stored in files using this name appended with a number and
+ * the extension {@literal .log}. At checkpoint, a new transactions log file is
+ * created and the number is incremented.
+ * @param logBaseName the log base name
+ */
+ public void setLogBaseName(String logBaseName) {
+ set("log_base_name", logBaseName);
+ }
+
+ /**
+ * Specifies the directory in which the log files should be stored. Defaults to the
+ * current working directory. This directory should be a stable storage like a SAN,
+ * RAID or at least backed up location. The transactions logs files are as important
+ * as the data themselves to guarantee consistency in case of failures.
+ * @param logBaseDir the log base dir
+ */
+ public void setLogBaseDir(String logBaseDir) {
+ set("log_base_dir", logBaseDir);
+ }
+
+ /**
+ * Specifies the interval between checkpoints. A checkpoint reduces the log file size
+ * at the expense of adding some overhead in the runtime. Defaults to {@literal 500}.
+ * @param checkpointInterval the checkpoint interval
+ */
+ public void setCheckpointInterval(long checkpointInterval) {
+ set("checkpoint_interval", checkpointInterval);
+ }
+
+ /**
+ * Specifies the console log level. Defaults to {@link AtomikosLoggingLevel#WARN}.
+ * @param consoleLogLevel the console log level
+ */
+ public void setConsoleLogLevel(AtomikosLoggingLevel consoleLogLevel) {
+ set("console_log_level", consoleLogLevel);
+ }
+
+ /**
+ * Specifies the directory in which to store the debug log files. Defaults to the
+ * current working directory.
+ * @param outputDir the output dir
+ */
+ public void setOutputDir(String outputDir) {
+ set("output_dir", outputDir);
+ }
+
+ /**
+ * Specifies the debug logs file name. Defaults to {@literal tm.out}.
+ * @param consoleFileName the console file name
+ */
+ public void setConsoleFileName(String consoleFileName) {
+ set("console_file_name", consoleFileName);
+ }
+
+ /**
+ * Specifies how many debug logs files can be created. Defaults to {@literal 1}.
+ * @param consoleFileCount the console file count
+ */
+ public void setConsoleFileCount(int consoleFileCount) {
+ set("console_file_count", consoleFileCount);
+ }
+
+ /**
+ * Specifies how many bytes can be stored at most in debug logs files. Defaults to
+ * {@literal -1}. Negative values means unlimited.
+ * @param consoleFileLimit the console file limit
+ */
+ public void setConsoleFileLimit(int consoleFileLimit) {
+ set("console_file_limit", consoleFileLimit);
+ }
+
+ /**
+ * Specifies whether or not to use different (and concurrent) threads for two-phase
+ * commit on the participating resources. Setting this to {@literal true} implies that
+ * the commit is more efficient since waiting for acknowledgements is done in
+ * parallel. Defaults to {@literal true}. If you set this to {@literal false}, then
+ * commits will happen in the order that resources are accessed within the
+ * transaction.
+ * @param threadedTwoPhaseCommit if threaded two phase commits should be used
+ */
+ public void setThreadedTwoPhaseCommit(boolean threadedTwoPhaseCommit) {
+ set("threaded_2pc", threadedTwoPhaseCommit);
+ }
+
+ private void set(String key, Object value) {
+ set("com.atomikos.icatch.", key, value);
+ }
+
+ private void set(String keyPrefix, String key, Object value) {
+ if (value != null) {
+ this.values.put(keyPrefix + key, value.toString());
+ }
+ else {
+ this.values.remove(keyPrefix + key);
+ }
+ }
+
+ /**
+ * Returns the properties as a {@link Properties} object that can be used with
+ * Atomikos.
+ * @return the properties
+ */
+ public Properties asProperties() {
+ Properties properties = new Properties();
+ properties.putAll(this.values);
+ return properties;
+ }
+
+}
diff --git a/spring-boot/src/main/java/org/springframework/boot/jta/package-info.java b/spring-boot/src/main/java/org/springframework/boot/jta/package-info.java
new file mode 100644
index 0000000000..3ca0cc266b
--- /dev/null
+++ b/spring-boot/src/main/java/org/springframework/boot/jta/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+/**
+ * Support for the Java Transaction API.
+ */
+package org.springframework.boot.jta;
+
diff --git a/spring-boot/src/test/java/org/springframework/boot/jta/atomikos/AtomikosConnectionFactoryBeanTests.java b/spring-boot/src/test/java/org/springframework/boot/jta/atomikos/AtomikosConnectionFactoryBeanTests.java
new file mode 100644
index 0000000000..55b7f0bcf7
--- /dev/null
+++ b/spring-boot/src/test/java/org/springframework/boot/jta/atomikos/AtomikosConnectionFactoryBeanTests.java
@@ -0,0 +1,61 @@
+/*
+ * 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.JMSException;
+
+import org.junit.Test;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+/**
+ * Tests for {@link AtomikosConnectionFactoryBean}.
+ *
+ * @author Phillip Webb
+ */
+public class AtomikosConnectionFactoryBeanTests {
+
+ @Test
+ public void beanMethods() throws Exception {
+ MockAtomikosConnectionFactoryBean bean = spy(new MockAtomikosConnectionFactoryBean());
+ bean.setBeanName("bean");
+ bean.afterPropertiesSet();
+ assertThat(bean.getUniqueResourceName(), equalTo("bean"));
+ verify(bean).init();
+ verify(bean, never()).close();
+ bean.destroy();
+ verify(bean).close();
+ }
+
+ private static class MockAtomikosConnectionFactoryBean extends
+ AtomikosConnectionFactoryBean {
+
+ @Override
+ public synchronized void init() throws JMSException {
+ }
+
+ @Override
+ public synchronized void close() {
+ }
+
+ }
+
+}
diff --git a/spring-boot/src/test/java/org/springframework/boot/jta/atomikos/AtomikosDataSourceBeanTests.java b/spring-boot/src/test/java/org/springframework/boot/jta/atomikos/AtomikosDataSourceBeanTests.java
new file mode 100644
index 0000000000..10348aa5bf
--- /dev/null
+++ b/spring-boot/src/test/java/org/springframework/boot/jta/atomikos/AtomikosDataSourceBeanTests.java
@@ -0,0 +1,60 @@
+/*
+ * 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 org.junit.Test;
+
+import com.atomikos.jdbc.AtomikosSQLException;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+/**
+ * Tests for {@link AtomikosDataSourceBean}.
+ *
+ * @author Phillip Webb
+ */
+public class AtomikosDataSourceBeanTests {
+
+ @Test
+ public void beanMethods() throws Exception {
+ MockAtomikosDataSourceBean bean = spy(new MockAtomikosDataSourceBean());
+ bean.setBeanName("bean");
+ bean.afterPropertiesSet();
+ assertThat(bean.getUniqueResourceName(), equalTo("bean"));
+ verify(bean).init();
+ verify(bean, never()).close();
+ bean.destroy();
+ verify(bean).close();
+ }
+
+ private static class MockAtomikosDataSourceBean extends AtomikosDataSourceBean {
+
+ @Override
+ public synchronized void init() throws AtomikosSQLException {
+ }
+
+ @Override
+ public synchronized void close() {
+ }
+
+ }
+
+}
diff --git a/spring-boot/src/test/java/org/springframework/boot/jta/atomikos/AtomikosDependsOnBeanFactoryPostProcessorTests.java b/spring-boot/src/test/java/org/springframework/boot/jta/atomikos/AtomikosDependsOnBeanFactoryPostProcessorTests.java
new file mode 100644
index 0000000000..485f46d953
--- /dev/null
+++ b/spring-boot/src/test/java/org/springframework/boot/jta/atomikos/AtomikosDependsOnBeanFactoryPostProcessorTests.java
@@ -0,0 +1,99 @@
+/*
+ * 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 java.util.Arrays;
+import java.util.HashSet;
+
+import javax.jms.ConnectionFactory;
+import javax.sql.DataSource;
+
+import org.junit.Test;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import com.atomikos.icatch.jta.UserTransactionManager;
+import com.atomikos.jms.extra.MessageDrivenContainer;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+/**
+ * Tests for {@link AtomikosDependsOnBeanFactoryPostProcessor}.
+ *
+ * @author Phillip Webb
+ */
+public class AtomikosDependsOnBeanFactoryPostProcessorTests {
+
+ private AnnotationConfigApplicationContext context;
+
+ @Test
+ public void setsDependsOn() {
+ this.context = new AnnotationConfigApplicationContext(Config.class);
+ assertDependsOn("dataSource");
+ assertDependsOn("connectionFactory");
+ assertDependsOn("userTransactionManager", "dataSource", "connectionFactory");
+ assertDependsOn("messageDrivenContainer", "userTransactionManager");
+ this.context.close();
+ }
+
+ private void assertDependsOn(String bean, String... expected) {
+ BeanDefinition definition = this.context.getBeanDefinition(bean);
+ if (definition.getDependsOn() == null) {
+ assertTrue("No dependsOn expected for " + bean, expected.length == 0);
+ return;
+ }
+ HashSet dependsOn = new HashSet(Arrays.asList(definition
+ .getDependsOn()));
+ assertThat(dependsOn, equalTo(new HashSet(Arrays.asList(expected))));
+ }
+
+ @Configuration
+ static class Config {
+
+ @Bean
+ public DataSource dataSource() {
+ return mock(DataSource.class);
+ }
+
+ @Bean
+ public ConnectionFactory connectionFactory() {
+ return mock(ConnectionFactory.class);
+ }
+
+ @Bean
+ public UserTransactionManager userTransactionManager() {
+ return mock(UserTransactionManager.class);
+ }
+
+ @Bean
+ public MessageDrivenContainer messageDrivenContainer() {
+ return mock(MessageDrivenContainer.class);
+ }
+
+ @Bean
+ public static AtomikosDependsOnBeanFactoryPostProcessor atomikosPostProcessor() {
+ return new AtomikosDependsOnBeanFactoryPostProcessor();
+ }
+
+ }
+
+}
diff --git a/spring-boot/src/test/java/org/springframework/boot/jta/atomikos/AtomikosPropertiesTests.java b/spring-boot/src/test/java/org/springframework/boot/jta/atomikos/AtomikosPropertiesTests.java
new file mode 100644
index 0000000000..3060a60cb3
--- /dev/null
+++ b/spring-boot/src/test/java/org/springframework/boot/jta/atomikos/AtomikosPropertiesTests.java
@@ -0,0 +1,77 @@
+/*
+ * 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 org.junit.Test;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Tests for ;@link AtomikosProperties}.
+ *
+ * @author Phillip Webb
+ */
+public class AtomikosPropertiesTests {
+
+ private AtomikosProperties properties = new AtomikosProperties();
+
+ @Test
+ public void testProperties() {
+ this.properties.setService("service");
+ this.properties.setMaxTimeout(1L);
+ this.properties.setDefaultJtaTimeout(2L);
+ this.properties.setMaxActives(3);
+ this.properties.setEnableLogging(true);
+ this.properties.setTransactionManagerUniqueName("uniqueName");
+ this.properties.setSerialJtaTransactions(true);
+ this.properties.setForceShutdownOnVmExit(true);
+ this.properties.setLogBaseName("logBaseName");
+ this.properties.setLogBaseDir("logBaseDir");
+ this.properties.setCheckpointInterval(4);
+ this.properties.setConsoleLogLevel(AtomikosLoggingLevel.WARN);
+ this.properties.setOutputDir("outputDir");
+ this.properties.setConsoleFileName("consoleFileName");
+ this.properties.setConsoleFileCount(5);
+ this.properties.setConsoleFileLimit(6);
+ this.properties.setThreadedTwoPhaseCommit(true);
+
+ assertThat(this.properties.asProperties().size(), equalTo(17));
+ assertProperty("com.atomikos.icatch.service", "service");
+ assertProperty("com.atomikos.icatch.max_timeout", "1");
+ assertProperty("com.atomikos.icatch.default_jta_timeout", "2");
+ assertProperty("com.atomikos.icatch.max_actives", "3");
+ assertProperty("com.atomikos.icatch.enable_logging", "true");
+ assertProperty("com.atomikos.icatch.tm_unique_name", "uniqueName");
+ assertProperty("com.atomikos.icatch.serial_jta_transactions", "true");
+ assertProperty("com.atomikos.icatch.force_shutdown_on_vm_exit", "true");
+ assertProperty("com.atomikos.icatch.log_base_name", "logBaseName");
+ assertProperty("com.atomikos.icatch.log_base_dir", "logBaseDir");
+ assertProperty("com.atomikos.icatch.checkpoint_interval", "4");
+ assertProperty("com.atomikos.icatch.console_log_level", "WARN");
+ assertProperty("com.atomikos.icatch.output_dir", "outputDir");
+ assertProperty("com.atomikos.icatch.console_file_name", "consoleFileName");
+ assertProperty("com.atomikos.icatch.console_file_count", "5");
+ assertProperty("com.atomikos.icatch.console_file_limit", "6");
+ assertProperty("com.atomikos.icatch.threaded_2pc", "true");
+ }
+
+ private void assertProperty(String key, String value) {
+ assertThat(this.properties.asProperties().getProperty(key), equalTo(value));
+ }
+
+}