Add Atomikos support classes

Add support classes for the Atomikos JTA library, including:

- A Spring friendly ConnectionFactoryBean and DataSourceBean.
- A PostProcessor to apply "depends-on" ordering automatically.
- A bindable properties class for type-safe configuration.

See gh-947
This commit is contained in:
Phillip Webb 2014-08-22 10:09:14 -07:00
parent bacdd5a408
commit 983ec0ebc8
12 changed files with 860 additions and 0 deletions

View File

@ -48,6 +48,7 @@
<!-- Third Party -->
<activemq.version>5.9.1</activemq.version>
<aspectj.version>1.8.2</aspectj.version>
<atomikos.version>3.9.3</atomikos.version>
<codahale-metrics.version>3.0.2</codahale-metrics.version>
<commons-beanutils.version>1.9.2</commons-beanutils.version>
<commons-collections.version>3.2.1</commons-collections.version>
@ -85,6 +86,7 @@
<jolokia.version>1.2.2</jolokia.version>
<json-path.version>0.9.1</json-path.version>
<jstl.version>1.2</jstl.version>
<jta.version>1.1</jta.version>
<junit.version>4.11</junit.version>
<liquibase.version>3.0.8</liquibase.version>
<log4j.version>1.2.17</log4j.version>
@ -350,6 +352,21 @@
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-jdbc</artifactId>
<version>${atomikos.version}</version>
</dependency>
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-jms</artifactId>
<version>${atomikos.version}</version>
</dependency>
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-jta</artifactId>
<version>${atomikos.version}</version>
</dependency>
<dependency>
<groupId>com.codahale.metrics</groupId>
<artifactId>metrics-graphite</artifactId>
@ -482,6 +499,11 @@
<artifactId>jstl</artifactId>
<version>${jstl.version}</version>
</dependency>
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>jta</artifactId>
<version>${jta.version}</version>
</dependency>
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>

View File

@ -34,11 +34,31 @@
<artifactId>logback-classic</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-jms</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-jta</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-jdbc</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>javax.jms</groupId>
<artifactId>jms-api</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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 <a
* href="http://www.atomikos.com/Documentation/SpringIntegration">correct Atomikos
* ordering</a>.
*
* @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<String> dependsOn = new LinkedHashSet<String>(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<String> dependsOn = new LinkedHashSet<String>(asList(bean.getDependsOn()));
dependsOn.addAll(asList(transactionManagers));
bean.setDependsOn(dependsOn.toArray(new String[dependsOn.size()]));
}
}
private void addDependencies(ConfigurableListableBeanFactory beanFactory,
String type, Set<String> 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<String> asList(String[] array) {
return (array == null ? Collections.<String> emptyList() : Arrays.asList(array));
}
@Override
public int getOrder() {
return this.order;
}
public void setOrder(int order) {
this.order = order;
}
}

View File

@ -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
}

View File

@ -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 <a
* href="http://www.atomikos.com/Documentation/JtaProperties">Atomikos configuration
* properties</a>. 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<String, String> values = new TreeMap<String, String>();
/**
* 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;
}
}

View File

@ -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;

View File

@ -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() {
}
}
}

View File

@ -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() {
}
}
}

View File

@ -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<String> dependsOn = new HashSet<String>(Arrays.asList(definition
.getDependsOn()));
assertThat(dependsOn, equalTo(new HashSet<String>(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();
}
}
}

View File

@ -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));
}
}