Remove Narayana support
The Spring Boot integration is now handled by the Narayana project itself at https://github.com/snowdrop/narayana-spring-boot This commit removes our support. Closes gh-12026pull/13997/merge
parent
598f630b8c
commit
930c838da9
@ -1,172 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-2018 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.transaction.jta;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
import javax.jms.Message;
|
|
||||||
import javax.transaction.TransactionManager;
|
|
||||||
import javax.transaction.UserTransaction;
|
|
||||||
|
|
||||||
import com.arjuna.ats.arjuna.recovery.RecoveryManager;
|
|
||||||
import com.arjuna.ats.jbossatx.jta.RecoveryManagerService;
|
|
||||||
import org.jboss.narayana.jta.jms.TransactionHelper;
|
|
||||||
import org.jboss.tm.XAResourceRecoveryRegistry;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
|
||||||
import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;
|
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
|
||||||
import org.springframework.boot.jdbc.XADataSourceWrapper;
|
|
||||||
import org.springframework.boot.jms.XAConnectionFactoryWrapper;
|
|
||||||
import org.springframework.boot.jta.narayana.NarayanaBeanFactoryPostProcessor;
|
|
||||||
import org.springframework.boot.jta.narayana.NarayanaConfigurationBean;
|
|
||||||
import org.springframework.boot.jta.narayana.NarayanaProperties;
|
|
||||||
import org.springframework.boot.jta.narayana.NarayanaRecoveryManagerBean;
|
|
||||||
import org.springframework.boot.jta.narayana.NarayanaXAConnectionFactoryWrapper;
|
|
||||||
import org.springframework.boot.jta.narayana.NarayanaXADataSourceWrapper;
|
|
||||||
import org.springframework.boot.system.ApplicationHome;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.context.annotation.DependsOn;
|
|
||||||
import org.springframework.transaction.PlatformTransactionManager;
|
|
||||||
import org.springframework.transaction.jta.JtaTransactionManager;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JTA Configuration for <a href="http://narayana.io/">Narayana</a>.
|
|
||||||
*
|
|
||||||
* @author Gytis Trikleris
|
|
||||||
* @author Kazuki Shimizu
|
|
||||||
* @since 1.4.0
|
|
||||||
*/
|
|
||||||
@Configuration
|
|
||||||
@ConditionalOnClass({ JtaTransactionManager.class,
|
|
||||||
com.arjuna.ats.jta.UserTransaction.class, XAResourceRecoveryRegistry.class })
|
|
||||||
@ConditionalOnMissingBean(PlatformTransactionManager.class)
|
|
||||||
@EnableConfigurationProperties(JtaProperties.class)
|
|
||||||
public class NarayanaJtaConfiguration {
|
|
||||||
|
|
||||||
private final JtaProperties jtaProperties;
|
|
||||||
|
|
||||||
private final TransactionManagerCustomizers transactionManagerCustomizers;
|
|
||||||
|
|
||||||
public NarayanaJtaConfiguration(JtaProperties jtaProperties,
|
|
||||||
ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
|
|
||||||
this.jtaProperties = jtaProperties;
|
|
||||||
this.transactionManagerCustomizers = transactionManagerCustomizers
|
|
||||||
.getIfAvailable();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@ConditionalOnMissingBean
|
|
||||||
public NarayanaProperties narayanaProperties() {
|
|
||||||
return new NarayanaProperties();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@ConditionalOnMissingBean
|
|
||||||
public NarayanaConfigurationBean narayanaConfiguration(
|
|
||||||
NarayanaProperties properties) {
|
|
||||||
properties.setLogDir(getLogDir().getAbsolutePath());
|
|
||||||
if (this.jtaProperties.getTransactionManagerId() != null) {
|
|
||||||
properties.setTransactionManagerId(
|
|
||||||
this.jtaProperties.getTransactionManagerId());
|
|
||||||
}
|
|
||||||
return new NarayanaConfigurationBean(properties);
|
|
||||||
}
|
|
||||||
|
|
||||||
private File getLogDir() {
|
|
||||||
if (StringUtils.hasLength(this.jtaProperties.getLogDir())) {
|
|
||||||
return new File(this.jtaProperties.getLogDir());
|
|
||||||
}
|
|
||||||
File home = new ApplicationHome().getDir();
|
|
||||||
return new File(home, "transaction-logs");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@DependsOn("narayanaConfiguration")
|
|
||||||
@ConditionalOnMissingBean
|
|
||||||
public UserTransaction narayanaUserTransaction() {
|
|
||||||
return com.arjuna.ats.jta.UserTransaction.userTransaction();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@DependsOn("narayanaConfiguration")
|
|
||||||
@ConditionalOnMissingBean
|
|
||||||
public TransactionManager narayanaTransactionManager() {
|
|
||||||
return com.arjuna.ats.jta.TransactionManager.transactionManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@DependsOn("narayanaConfiguration")
|
|
||||||
public RecoveryManagerService narayanaRecoveryManagerService() {
|
|
||||||
RecoveryManager.delayRecoveryManagerThread();
|
|
||||||
return new RecoveryManagerService();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@ConditionalOnMissingBean
|
|
||||||
public NarayanaRecoveryManagerBean narayanaRecoveryManager(
|
|
||||||
RecoveryManagerService recoveryManagerService) {
|
|
||||||
return new NarayanaRecoveryManagerBean(recoveryManagerService);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public JtaTransactionManager transactionManager(UserTransaction userTransaction,
|
|
||||||
TransactionManager transactionManager) {
|
|
||||||
JtaTransactionManager jtaTransactionManager = new JtaTransactionManager(
|
|
||||||
userTransaction, transactionManager);
|
|
||||||
if (this.transactionManagerCustomizers != null) {
|
|
||||||
this.transactionManagerCustomizers.customize(jtaTransactionManager);
|
|
||||||
}
|
|
||||||
return jtaTransactionManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@ConditionalOnMissingBean
|
|
||||||
public XADataSourceWrapper xaDataSourceWrapper(
|
|
||||||
NarayanaRecoveryManagerBean narayanaRecoveryManagerBean,
|
|
||||||
NarayanaProperties narayanaProperties) {
|
|
||||||
return new NarayanaXADataSourceWrapper(narayanaRecoveryManagerBean,
|
|
||||||
narayanaProperties);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@ConditionalOnMissingBean
|
|
||||||
public static NarayanaBeanFactoryPostProcessor narayanaBeanFactoryPostProcessor() {
|
|
||||||
return new NarayanaBeanFactoryPostProcessor();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@ConditionalOnClass({ Message.class, TransactionHelper.class })
|
|
||||||
static class NarayanaJtaJmsConfiguration {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@ConditionalOnMissingBean(XAConnectionFactoryWrapper.class)
|
|
||||||
public NarayanaXAConnectionFactoryWrapper xaConnectionFactoryWrapper(
|
|
||||||
TransactionManager transactionManager,
|
|
||||||
NarayanaRecoveryManagerBean narayanaRecoveryManagerBean,
|
|
||||||
NarayanaProperties narayanaProperties) {
|
|
||||||
return new NarayanaXAConnectionFactoryWrapper(transactionManager,
|
|
||||||
narayanaRecoveryManagerBean, narayanaProperties);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,56 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
<parent>
|
|
||||||
<artifactId>spring-boot-starters</artifactId>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<version>${revision}</version>
|
|
||||||
</parent>
|
|
||||||
<artifactId>spring-boot-starter-jta-narayana</artifactId>
|
|
||||||
<name>Spring Boot Narayana JTA Starter</name>
|
|
||||||
<description>Starter for JTA transactions using Narayana</description>
|
|
||||||
<properties>
|
|
||||||
<main.basedir>${basedir}/../../..</main.basedir>
|
|
||||||
</properties>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.jboss</groupId>
|
|
||||||
<artifactId>jboss-transaction-spi</artifactId>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.jboss.spec.javax.transaction</groupId>
|
|
||||||
<artifactId>jboss-transaction-api_1.2_spec</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.jboss.spec.javax.transaction</groupId>
|
|
||||||
<artifactId>jboss-transaction-api_1.1_spec</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.jboss.narayana.jta</groupId>
|
|
||||||
<artifactId>jdbc</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.jboss.narayana.jta</groupId>
|
|
||||||
<artifactId>jms</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.jboss.narayana.jta</groupId>
|
|
||||||
<artifactId>jta</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.jboss.narayana.jts</groupId>
|
|
||||||
<artifactId>narayana-jts-integration</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>javax.transaction</groupId>
|
|
||||||
<artifactId>javax.transaction-api</artifactId>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</project>
|
|
@ -1,190 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-2017 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.narayana;
|
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
|
|
||||||
import javax.sql.XAConnection;
|
|
||||||
import javax.sql.XADataSource;
|
|
||||||
import javax.transaction.xa.XAException;
|
|
||||||
import javax.transaction.xa.XAResource;
|
|
||||||
import javax.transaction.xa.Xid;
|
|
||||||
|
|
||||||
import com.arjuna.ats.jta.recovery.XAResourceRecoveryHelper;
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* XAResourceRecoveryHelper implementation which gets XIDs, which needs to be recovered,
|
|
||||||
* from the database.
|
|
||||||
*
|
|
||||||
* @author Gytis Trikleris
|
|
||||||
* @since 1.4.0
|
|
||||||
*/
|
|
||||||
public class DataSourceXAResourceRecoveryHelper
|
|
||||||
implements XAResourceRecoveryHelper, XAResource {
|
|
||||||
|
|
||||||
private static final XAResource[] NO_XA_RESOURCES = {};
|
|
||||||
|
|
||||||
private static final Log logger = LogFactory
|
|
||||||
.getLog(DataSourceXAResourceRecoveryHelper.class);
|
|
||||||
|
|
||||||
private final XADataSource xaDataSource;
|
|
||||||
|
|
||||||
private final String user;
|
|
||||||
|
|
||||||
private final String password;
|
|
||||||
|
|
||||||
private XAConnection xaConnection;
|
|
||||||
|
|
||||||
private XAResource delegate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new {@link DataSourceXAResourceRecoveryHelper} instance.
|
|
||||||
* @param xaDataSource the XA data source
|
|
||||||
*/
|
|
||||||
public DataSourceXAResourceRecoveryHelper(XADataSource xaDataSource) {
|
|
||||||
this(xaDataSource, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new {@link DataSourceXAResourceRecoveryHelper} instance.
|
|
||||||
* @param xaDataSource the XA data source
|
|
||||||
* @param user the database user or {@code null}
|
|
||||||
* @param password the database password or {@code null}
|
|
||||||
*/
|
|
||||||
public DataSourceXAResourceRecoveryHelper(XADataSource xaDataSource, String user,
|
|
||||||
String password) {
|
|
||||||
Assert.notNull(xaDataSource, "XADataSource must not be null");
|
|
||||||
this.xaDataSource = xaDataSource;
|
|
||||||
this.user = user;
|
|
||||||
this.password = password;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean initialise(String properties) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public XAResource[] getXAResources() {
|
|
||||||
if (connect()) {
|
|
||||||
return new XAResource[] { this };
|
|
||||||
}
|
|
||||||
return NO_XA_RESOURCES;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean connect() {
|
|
||||||
if (this.delegate == null) {
|
|
||||||
try {
|
|
||||||
this.xaConnection = getXaConnection();
|
|
||||||
this.delegate = this.xaConnection.getXAResource();
|
|
||||||
}
|
|
||||||
catch (SQLException ex) {
|
|
||||||
logger.warn("Failed to create connection", ex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private XAConnection getXaConnection() throws SQLException {
|
|
||||||
if (this.user == null && this.password == null) {
|
|
||||||
return this.xaDataSource.getXAConnection();
|
|
||||||
}
|
|
||||||
return this.xaDataSource.getXAConnection(this.user, this.password);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Xid[] recover(int flag) throws XAException {
|
|
||||||
try {
|
|
||||||
return getDelegate(true).recover(flag);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
if (flag == XAResource.TMENDRSCAN) {
|
|
||||||
disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void disconnect() throws XAException {
|
|
||||||
try {
|
|
||||||
this.xaConnection.close();
|
|
||||||
}
|
|
||||||
catch (SQLException ex) {
|
|
||||||
logger.warn("Failed to close connection", ex);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
this.xaConnection = null;
|
|
||||||
this.delegate = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void start(Xid xid, int flags) throws XAException {
|
|
||||||
getDelegate(true).start(xid, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void end(Xid xid, int flags) throws XAException {
|
|
||||||
getDelegate(true).end(xid, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int prepare(Xid xid) throws XAException {
|
|
||||||
return getDelegate(true).prepare(xid);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void commit(Xid xid, boolean onePhase) throws XAException {
|
|
||||||
getDelegate(true).commit(xid, onePhase);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void rollback(Xid xid) throws XAException {
|
|
||||||
getDelegate(true).rollback(xid);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSameRM(XAResource xaResource) throws XAException {
|
|
||||||
return getDelegate(true).isSameRM(xaResource);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void forget(Xid xid) throws XAException {
|
|
||||||
getDelegate(true).forget(xid);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getTransactionTimeout() throws XAException {
|
|
||||||
return getDelegate(true).getTransactionTimeout();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean setTransactionTimeout(int seconds) throws XAException {
|
|
||||||
return getDelegate(true).setTransactionTimeout(seconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
private XAResource getDelegate(boolean required) {
|
|
||||||
Assert.state(this.delegate != null || !required,
|
|
||||||
"Connection has not been opened");
|
|
||||||
return this.delegate;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,84 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-2017 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.narayana;
|
|
||||||
|
|
||||||
import javax.transaction.TransactionManager;
|
|
||||||
|
|
||||||
import org.springframework.beans.BeansException;
|
|
||||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
|
||||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
|
||||||
import org.springframework.core.Ordered;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link BeanFactoryPostProcessor} to automatically setup correct beans ordering.
|
|
||||||
*
|
|
||||||
* @author Gytis Trikleris
|
|
||||||
* @since 1.4.0
|
|
||||||
*/
|
|
||||||
public class NarayanaBeanFactoryPostProcessor
|
|
||||||
implements BeanFactoryPostProcessor, Ordered {
|
|
||||||
|
|
||||||
private static final String[] NO_BEANS = {};
|
|
||||||
|
|
||||||
private static final int ORDER = Ordered.LOWEST_PRECEDENCE;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
|
|
||||||
throws BeansException {
|
|
||||||
String[] transactionManagers = beanFactory
|
|
||||||
.getBeanNamesForType(TransactionManager.class, true, false);
|
|
||||||
String[] recoveryManagers = beanFactory
|
|
||||||
.getBeanNamesForType(NarayanaRecoveryManagerBean.class, true, false);
|
|
||||||
addBeanDependencies(beanFactory, transactionManagers, "javax.sql.DataSource");
|
|
||||||
addBeanDependencies(beanFactory, recoveryManagers, "javax.sql.DataSource");
|
|
||||||
addBeanDependencies(beanFactory, transactionManagers,
|
|
||||||
"javax.jms.ConnectionFactory");
|
|
||||||
addBeanDependencies(beanFactory, recoveryManagers, "javax.jms.ConnectionFactory");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addBeanDependencies(ConfigurableListableBeanFactory beanFactory,
|
|
||||||
String[] beanNames, String dependencyType) {
|
|
||||||
for (String beanName : beanNames) {
|
|
||||||
addBeanDependencies(beanFactory, beanName, dependencyType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addBeanDependencies(ConfigurableListableBeanFactory beanFactory,
|
|
||||||
String beanName, String dependencyType) {
|
|
||||||
for (String dependentBeanName : getBeanNamesForType(beanFactory,
|
|
||||||
dependencyType)) {
|
|
||||||
beanFactory.registerDependentBean(beanName, dependentBeanName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String[] getBeanNamesForType(ConfigurableListableBeanFactory beanFactory,
|
|
||||||
String type) {
|
|
||||||
try {
|
|
||||||
return beanFactory.getBeanNamesForType(Class.forName(type), true, false);
|
|
||||||
}
|
|
||||||
catch (ClassNotFoundException | NoClassDefFoundError ex) {
|
|
||||||
// Ignore
|
|
||||||
}
|
|
||||||
return NO_BEANS;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getOrder() {
|
|
||||||
return ORDER;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,134 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-2017 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.narayana;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import com.arjuna.ats.arjuna.common.CoordinatorEnvironmentBean;
|
|
||||||
import com.arjuna.ats.arjuna.common.CoreEnvironmentBean;
|
|
||||||
import com.arjuna.ats.arjuna.common.CoreEnvironmentBeanException;
|
|
||||||
import com.arjuna.ats.arjuna.common.ObjectStoreEnvironmentBean;
|
|
||||||
import com.arjuna.ats.arjuna.common.RecoveryEnvironmentBean;
|
|
||||||
import com.arjuna.ats.jta.common.JTAEnvironmentBean;
|
|
||||||
import com.arjuna.common.internal.util.propertyservice.BeanPopulator;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bean that configures Narayana transaction manager.
|
|
||||||
*
|
|
||||||
* @author Gytis Trikleris
|
|
||||||
* @since 1.4.0
|
|
||||||
*/
|
|
||||||
public class NarayanaConfigurationBean implements InitializingBean {
|
|
||||||
|
|
||||||
private static final String JBOSSTS_PROPERTIES_FILE_NAME = "jbossts-properties.xml";
|
|
||||||
|
|
||||||
private final NarayanaProperties properties;
|
|
||||||
|
|
||||||
public NarayanaConfigurationBean(NarayanaProperties narayanaProperties) {
|
|
||||||
this.properties = narayanaProperties;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterPropertiesSet() throws Exception {
|
|
||||||
if (isPropertiesFileAvailable()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setNodeIdentifier(this.properties.getTransactionManagerId());
|
|
||||||
setObjectStoreDir(this.properties.getLogDir());
|
|
||||||
setCommitOnePhase(this.properties.isOnePhaseCommit());
|
|
||||||
if (this.properties.getDefaultTimeout() != null) {
|
|
||||||
setDefaultTimeout((int) this.properties.getDefaultTimeout().getSeconds());
|
|
||||||
}
|
|
||||||
if (this.properties.getPeriodicRecoveryPeriod() != null) {
|
|
||||||
setPeriodicRecoveryPeriod(
|
|
||||||
(int) this.properties.getPeriodicRecoveryPeriod().getSeconds());
|
|
||||||
}
|
|
||||||
if (this.properties.getRecoveryBackoffPeriod() != null) {
|
|
||||||
setRecoveryBackoffPeriod(
|
|
||||||
(int) this.properties.getRecoveryBackoffPeriod().getSeconds());
|
|
||||||
}
|
|
||||||
setXaResourceOrphanFilters(this.properties.getXaResourceOrphanFilters());
|
|
||||||
setRecoveryModules(this.properties.getRecoveryModules());
|
|
||||||
setExpiryScanners(this.properties.getExpiryScanners());
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isPropertiesFileAvailable() {
|
|
||||||
return Thread.currentThread().getContextClassLoader()
|
|
||||||
.getResource(JBOSSTS_PROPERTIES_FILE_NAME) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setNodeIdentifier(String nodeIdentifier)
|
|
||||||
throws CoreEnvironmentBeanException {
|
|
||||||
getPopulator(CoreEnvironmentBean.class).setNodeIdentifier(nodeIdentifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setObjectStoreDir(String objectStoreDir) {
|
|
||||||
if (objectStoreDir != null) {
|
|
||||||
getPopulator(ObjectStoreEnvironmentBean.class)
|
|
||||||
.setObjectStoreDir(objectStoreDir);
|
|
||||||
getPopulator(ObjectStoreEnvironmentBean.class, "communicationStore")
|
|
||||||
.setObjectStoreDir(objectStoreDir);
|
|
||||||
getPopulator(ObjectStoreEnvironmentBean.class, "stateStore")
|
|
||||||
.setObjectStoreDir(objectStoreDir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setCommitOnePhase(boolean isCommitOnePhase) {
|
|
||||||
getPopulator(CoordinatorEnvironmentBean.class)
|
|
||||||
.setCommitOnePhase(isCommitOnePhase);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setDefaultTimeout(int defaultTimeout) {
|
|
||||||
getPopulator(CoordinatorEnvironmentBean.class).setDefaultTimeout(defaultTimeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setPeriodicRecoveryPeriod(int periodicRecoveryPeriod) {
|
|
||||||
getPopulator(RecoveryEnvironmentBean.class)
|
|
||||||
.setPeriodicRecoveryPeriod(periodicRecoveryPeriod);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setRecoveryBackoffPeriod(int recoveryBackoffPeriod) {
|
|
||||||
getPopulator(RecoveryEnvironmentBean.class)
|
|
||||||
.setRecoveryBackoffPeriod(recoveryBackoffPeriod);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setXaResourceOrphanFilters(List<String> xaResourceOrphanFilters) {
|
|
||||||
getPopulator(JTAEnvironmentBean.class)
|
|
||||||
.setXaResourceOrphanFilterClassNames(xaResourceOrphanFilters);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setRecoveryModules(List<String> recoveryModules) {
|
|
||||||
getPopulator(RecoveryEnvironmentBean.class)
|
|
||||||
.setRecoveryModuleClassNames(recoveryModules);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setExpiryScanners(List<String> expiryScanners) {
|
|
||||||
getPopulator(RecoveryEnvironmentBean.class)
|
|
||||||
.setExpiryScannerClassNames(expiryScanners);
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T> T getPopulator(Class<T> beanClass) {
|
|
||||||
return BeanPopulator.getDefaultInstance(beanClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T> T getPopulator(Class<T> beanClass, String name) {
|
|
||||||
return BeanPopulator.getNamedInstance(beanClass, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,114 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-2017 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.narayana;
|
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.sql.SQLFeatureNotSupportedException;
|
|
||||||
import java.util.Properties;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import javax.sql.DataSource;
|
|
||||||
import javax.sql.XADataSource;
|
|
||||||
|
|
||||||
import com.arjuna.ats.internal.jdbc.ConnectionManager;
|
|
||||||
import com.arjuna.ats.jdbc.TransactionalDriver;
|
|
||||||
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
import org.springframework.util.ClassUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link DataSource} implementation wrapping {@link XADataSource} and using
|
|
||||||
* {@link ConnectionManager} to acquire connections.
|
|
||||||
*
|
|
||||||
* @author Gytis Trikleris
|
|
||||||
* @since 1.4.0
|
|
||||||
*/
|
|
||||||
public class NarayanaDataSourceBean implements DataSource {
|
|
||||||
|
|
||||||
private final XADataSource xaDataSource;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new {@link NarayanaDataSourceBean} instance.
|
|
||||||
* @param xaDataSource the XA DataSource
|
|
||||||
*/
|
|
||||||
public NarayanaDataSourceBean(XADataSource xaDataSource) {
|
|
||||||
Assert.notNull(xaDataSource, "XADataSource must not be null");
|
|
||||||
this.xaDataSource = xaDataSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Connection getConnection() throws SQLException {
|
|
||||||
Properties properties = new Properties();
|
|
||||||
properties.put(TransactionalDriver.XADataSource, this.xaDataSource);
|
|
||||||
return ConnectionManager.create(null, properties);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Connection getConnection(String username, String password)
|
|
||||||
throws SQLException {
|
|
||||||
Properties properties = new Properties();
|
|
||||||
properties.put(TransactionalDriver.XADataSource, this.xaDataSource);
|
|
||||||
properties.put(TransactionalDriver.userName, username);
|
|
||||||
properties.put(TransactionalDriver.password, password);
|
|
||||||
return ConnectionManager.create(null, properties);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PrintWriter getLogWriter() throws SQLException {
|
|
||||||
return this.xaDataSource.getLogWriter();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setLogWriter(PrintWriter out) throws SQLException {
|
|
||||||
this.xaDataSource.setLogWriter(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setLoginTimeout(int seconds) throws SQLException {
|
|
||||||
this.xaDataSource.setLoginTimeout(seconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getLoginTimeout() throws SQLException {
|
|
||||||
return this.xaDataSource.getLoginTimeout();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
|
|
||||||
throw new SQLFeatureNotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Override
|
|
||||||
public <T> T unwrap(Class<T> iface) throws SQLException {
|
|
||||||
if (isWrapperFor(iface)) {
|
|
||||||
return (T) this;
|
|
||||||
}
|
|
||||||
if (ClassUtils.isAssignableValue(iface, this.xaDataSource)) {
|
|
||||||
return (T) this.xaDataSource;
|
|
||||||
}
|
|
||||||
throw new SQLException(getClass() + " is not a wrapper for " + iface);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isWrapperFor(Class<?> iface) throws SQLException {
|
|
||||||
return iface.isAssignableFrom(getClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,223 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-2018 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.narayana;
|
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.time.temporal.ChronoUnit;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.boot.convert.DurationUnit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Subset of Narayana properties which can be configured via Spring configuration. Use
|
|
||||||
* jbossts-properties.xml for complete configuration.
|
|
||||||
*
|
|
||||||
* @author Gytis Trikleris
|
|
||||||
* @since 1.4.0
|
|
||||||
*/
|
|
||||||
@ConfigurationProperties(prefix = NarayanaProperties.PROPERTIES_PREFIX)
|
|
||||||
public class NarayanaProperties {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prefix for Narayana specific properties.
|
|
||||||
*/
|
|
||||||
public static final String PROPERTIES_PREFIX = "spring.jta.narayana";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Transaction object store directory.
|
|
||||||
*/
|
|
||||||
private String logDir;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unique transaction manager id.
|
|
||||||
*/
|
|
||||||
private String transactionManagerId = "1";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether to enable one phase commit optimization.
|
|
||||||
*/
|
|
||||||
private boolean onePhaseCommit = true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Transaction timeout. If a duration suffix is not specified, seconds will be used.
|
|
||||||
*/
|
|
||||||
@DurationUnit(ChronoUnit.SECONDS)
|
|
||||||
private Duration defaultTimeout = Duration.ofSeconds(60);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interval in which periodic recovery scans are performed. If a duration suffix is
|
|
||||||
* not specified, seconds will be used.
|
|
||||||
*/
|
|
||||||
@DurationUnit(ChronoUnit.SECONDS)
|
|
||||||
private Duration periodicRecoveryPeriod = Duration.ofSeconds(120);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Back off period between first and second phases of the recovery scan. If a duration
|
|
||||||
* suffix is not specified, seconds will be used.
|
|
||||||
*/
|
|
||||||
@DurationUnit(ChronoUnit.SECONDS)
|
|
||||||
private Duration recoveryBackoffPeriod = Duration.ofSeconds(10);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Database username to be used by the recovery manager.
|
|
||||||
*/
|
|
||||||
private String recoveryDbUser = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Database password to be used by the recovery manager.
|
|
||||||
*/
|
|
||||||
private String recoveryDbPass = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JMS username to be used by the recovery manager.
|
|
||||||
*/
|
|
||||||
private String recoveryJmsUser = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JMS password to be used by the recovery manager.
|
|
||||||
*/
|
|
||||||
private String recoveryJmsPass = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Comma-separated list of orphan filters.
|
|
||||||
*/
|
|
||||||
private List<String> xaResourceOrphanFilters = new ArrayList<>(Arrays.asList(
|
|
||||||
"com.arjuna.ats.internal.jta.recovery.arjunacore.JTATransactionLogXAResourceOrphanFilter",
|
|
||||||
"com.arjuna.ats.internal.jta.recovery.arjunacore.JTANodeNameXAResourceOrphanFilter"));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Comma-separated list of recovery modules.
|
|
||||||
*/
|
|
||||||
private List<String> recoveryModules = new ArrayList<>(Arrays.asList(
|
|
||||||
"com.arjuna.ats.internal.arjuna.recovery.AtomicActionRecoveryModule",
|
|
||||||
"com.arjuna.ats.internal.jta.recovery.arjunacore.XARecoveryModule"));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Comma-separated list of expiry scanners.
|
|
||||||
*/
|
|
||||||
private List<String> expiryScanners = new ArrayList<>(Collections.singletonList(
|
|
||||||
"com.arjuna.ats.internal.arjuna.recovery.ExpiredTransactionStatusManagerScanner"));
|
|
||||||
|
|
||||||
public String getLogDir() {
|
|
||||||
return this.logDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLogDir(String logDir) {
|
|
||||||
this.logDir = logDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTransactionManagerId() {
|
|
||||||
return this.transactionManagerId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTransactionManagerId(String transactionManagerId) {
|
|
||||||
this.transactionManagerId = transactionManagerId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isOnePhaseCommit() {
|
|
||||||
return this.onePhaseCommit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOnePhaseCommit(boolean onePhaseCommit) {
|
|
||||||
this.onePhaseCommit = onePhaseCommit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Duration getDefaultTimeout() {
|
|
||||||
return this.defaultTimeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDefaultTimeout(Duration defaultTimeout) {
|
|
||||||
this.defaultTimeout = defaultTimeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Duration getPeriodicRecoveryPeriod() {
|
|
||||||
return this.periodicRecoveryPeriod;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPeriodicRecoveryPeriod(Duration periodicRecoveryPeriod) {
|
|
||||||
this.periodicRecoveryPeriod = periodicRecoveryPeriod;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Duration getRecoveryBackoffPeriod() {
|
|
||||||
return this.recoveryBackoffPeriod;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRecoveryBackoffPeriod(Duration recoveryBackoffPeriod) {
|
|
||||||
this.recoveryBackoffPeriod = recoveryBackoffPeriod;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getXaResourceOrphanFilters() {
|
|
||||||
return this.xaResourceOrphanFilters;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setXaResourceOrphanFilters(List<String> xaResourceOrphanFilters) {
|
|
||||||
this.xaResourceOrphanFilters = xaResourceOrphanFilters;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getRecoveryModules() {
|
|
||||||
return this.recoveryModules;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRecoveryModules(List<String> recoveryModules) {
|
|
||||||
this.recoveryModules = recoveryModules;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getExpiryScanners() {
|
|
||||||
return this.expiryScanners;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setExpiryScanners(List<String> expiryScanners) {
|
|
||||||
this.expiryScanners = expiryScanners;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getRecoveryDbUser() {
|
|
||||||
return this.recoveryDbUser;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRecoveryDbUser(String recoveryDbUser) {
|
|
||||||
this.recoveryDbUser = recoveryDbUser;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getRecoveryDbPass() {
|
|
||||||
return this.recoveryDbPass;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRecoveryDbPass(String recoveryDbPass) {
|
|
||||||
this.recoveryDbPass = recoveryDbPass;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getRecoveryJmsUser() {
|
|
||||||
return this.recoveryJmsUser;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRecoveryJmsUser(String recoveryJmsUser) {
|
|
||||||
this.recoveryJmsUser = recoveryJmsUser;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getRecoveryJmsPass() {
|
|
||||||
return this.recoveryJmsPass;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRecoveryJmsPass(String recoveryJmsPass) {
|
|
||||||
this.recoveryJmsPass = recoveryJmsPass;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,69 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-2017 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.narayana;
|
|
||||||
|
|
||||||
import com.arjuna.ats.internal.jta.recovery.arjunacore.XARecoveryModule;
|
|
||||||
import com.arjuna.ats.jbossatx.jta.RecoveryManagerService;
|
|
||||||
import com.arjuna.ats.jta.recovery.XAResourceRecoveryHelper;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.DisposableBean;
|
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bean to set up Narayana recovery manager.
|
|
||||||
*
|
|
||||||
* @author Gytis Trikleris
|
|
||||||
* @since 1.4.0
|
|
||||||
*/
|
|
||||||
public class NarayanaRecoveryManagerBean implements InitializingBean, DisposableBean {
|
|
||||||
|
|
||||||
private final RecoveryManagerService recoveryManagerService;
|
|
||||||
|
|
||||||
public NarayanaRecoveryManagerBean(RecoveryManagerService recoveryManagerService) {
|
|
||||||
Assert.notNull(recoveryManagerService, "RecoveryManagerService must not be null");
|
|
||||||
this.recoveryManagerService = recoveryManagerService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterPropertiesSet() throws Exception {
|
|
||||||
this.recoveryManagerService.create();
|
|
||||||
this.recoveryManagerService.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void destroy() throws Exception {
|
|
||||||
this.recoveryManagerService.stop();
|
|
||||||
this.recoveryManagerService.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
void registerXAResourceRecoveryHelper(
|
|
||||||
XAResourceRecoveryHelper xaResourceRecoveryHelper) {
|
|
||||||
getXARecoveryModule().addXAResourceRecoveryHelper(xaResourceRecoveryHelper);
|
|
||||||
}
|
|
||||||
|
|
||||||
private XARecoveryModule getXARecoveryModule() {
|
|
||||||
XARecoveryModule xaRecoveryModule = XARecoveryModule
|
|
||||||
.getRegisteredXARecoveryModule();
|
|
||||||
if (xaRecoveryModule != null) {
|
|
||||||
return xaRecoveryModule;
|
|
||||||
}
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"XARecoveryModule is not registered with recovery manager");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,82 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-2018 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.narayana;
|
|
||||||
|
|
||||||
import javax.jms.ConnectionFactory;
|
|
||||||
import javax.jms.XAConnectionFactory;
|
|
||||||
import javax.transaction.TransactionManager;
|
|
||||||
|
|
||||||
import com.arjuna.ats.jta.recovery.XAResourceRecoveryHelper;
|
|
||||||
import org.jboss.narayana.jta.jms.ConnectionFactoryProxy;
|
|
||||||
import org.jboss.narayana.jta.jms.JmsXAResourceRecoveryHelper;
|
|
||||||
import org.jboss.narayana.jta.jms.TransactionHelperImpl;
|
|
||||||
|
|
||||||
import org.springframework.boot.jms.XAConnectionFactoryWrapper;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link XAConnectionFactoryWrapper} that uses {@link ConnectionFactoryProxy} to wrap an
|
|
||||||
* {@link XAConnectionFactory}.
|
|
||||||
*
|
|
||||||
* @author Gytis Trikleris
|
|
||||||
* @since 1.4.0
|
|
||||||
*/
|
|
||||||
public class NarayanaXAConnectionFactoryWrapper implements XAConnectionFactoryWrapper {
|
|
||||||
|
|
||||||
private final TransactionManager transactionManager;
|
|
||||||
|
|
||||||
private final NarayanaRecoveryManagerBean recoveryManager;
|
|
||||||
|
|
||||||
private final NarayanaProperties properties;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new {@link NarayanaXAConnectionFactoryWrapper} instance.
|
|
||||||
* @param transactionManager the underlying transaction manager
|
|
||||||
* @param recoveryManager the underlying recovery manager
|
|
||||||
* @param properties the Narayana properties
|
|
||||||
*/
|
|
||||||
public NarayanaXAConnectionFactoryWrapper(TransactionManager transactionManager,
|
|
||||||
NarayanaRecoveryManagerBean recoveryManager, NarayanaProperties properties) {
|
|
||||||
Assert.notNull(transactionManager, "TransactionManager must not be null");
|
|
||||||
Assert.notNull(recoveryManager, "RecoveryManager must not be null");
|
|
||||||
Assert.notNull(properties, "Properties must not be null");
|
|
||||||
this.transactionManager = transactionManager;
|
|
||||||
this.recoveryManager = recoveryManager;
|
|
||||||
this.properties = properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ConnectionFactory wrapConnectionFactory(
|
|
||||||
XAConnectionFactory xaConnectionFactory) {
|
|
||||||
XAResourceRecoveryHelper recoveryHelper = getRecoveryHelper(xaConnectionFactory);
|
|
||||||
this.recoveryManager.registerXAResourceRecoveryHelper(recoveryHelper);
|
|
||||||
return new ConnectionFactoryProxy(xaConnectionFactory,
|
|
||||||
new TransactionHelperImpl(this.transactionManager));
|
|
||||||
}
|
|
||||||
|
|
||||||
private XAResourceRecoveryHelper getRecoveryHelper(
|
|
||||||
XAConnectionFactory xaConnectionFactory) {
|
|
||||||
if (this.properties.getRecoveryJmsUser() == null
|
|
||||||
&& this.properties.getRecoveryJmsPass() == null) {
|
|
||||||
return new JmsXAResourceRecoveryHelper(xaConnectionFactory);
|
|
||||||
}
|
|
||||||
return new JmsXAResourceRecoveryHelper(xaConnectionFactory,
|
|
||||||
this.properties.getRecoveryJmsUser(),
|
|
||||||
this.properties.getRecoveryJmsPass());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,69 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-2018 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.narayana;
|
|
||||||
|
|
||||||
import javax.sql.DataSource;
|
|
||||||
import javax.sql.XADataSource;
|
|
||||||
|
|
||||||
import com.arjuna.ats.jta.recovery.XAResourceRecoveryHelper;
|
|
||||||
|
|
||||||
import org.springframework.boot.jdbc.XADataSourceWrapper;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link XADataSourceWrapper} that uses {@link NarayanaDataSourceBean} to wrap an
|
|
||||||
* {@link XADataSource}.
|
|
||||||
*
|
|
||||||
* @author Gytis Trikleris
|
|
||||||
* @since 1.4.0
|
|
||||||
*/
|
|
||||||
public class NarayanaXADataSourceWrapper implements XADataSourceWrapper {
|
|
||||||
|
|
||||||
private final NarayanaRecoveryManagerBean recoveryManager;
|
|
||||||
|
|
||||||
private final NarayanaProperties properties;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new {@link NarayanaXADataSourceWrapper} instance.
|
|
||||||
* @param recoveryManager the underlying recovery manager
|
|
||||||
* @param properties the Narayana properties
|
|
||||||
*/
|
|
||||||
public NarayanaXADataSourceWrapper(NarayanaRecoveryManagerBean recoveryManager,
|
|
||||||
NarayanaProperties properties) {
|
|
||||||
Assert.notNull(recoveryManager, "RecoveryManager must not be null");
|
|
||||||
Assert.notNull(properties, "Properties must not be null");
|
|
||||||
this.recoveryManager = recoveryManager;
|
|
||||||
this.properties = properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DataSource wrapDataSource(XADataSource dataSource) {
|
|
||||||
XAResourceRecoveryHelper recoveryHelper = getRecoveryHelper(dataSource);
|
|
||||||
this.recoveryManager.registerXAResourceRecoveryHelper(recoveryHelper);
|
|
||||||
return new NarayanaDataSourceBean(dataSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
private XAResourceRecoveryHelper getRecoveryHelper(XADataSource dataSource) {
|
|
||||||
if (this.properties.getRecoveryDbUser() == null
|
|
||||||
&& this.properties.getRecoveryDbPass() == null) {
|
|
||||||
return new DataSourceXAResourceRecoveryHelper(dataSource);
|
|
||||||
}
|
|
||||||
return new DataSourceXAResourceRecoveryHelper(dataSource,
|
|
||||||
this.properties.getRecoveryDbUser(), this.properties.getRecoveryDbPass());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-2017 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 classes for Narayana JTA.
|
|
||||||
*/
|
|
||||||
package org.springframework.boot.jta.narayana;
|
|
@ -1,175 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-2018 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.narayana;
|
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
|
|
||||||
import javax.sql.XAConnection;
|
|
||||||
import javax.sql.XADataSource;
|
|
||||||
import javax.transaction.xa.XAException;
|
|
||||||
import javax.transaction.xa.XAResource;
|
|
||||||
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
|
||||||
import static org.mockito.BDDMockito.given;
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.never;
|
|
||||||
import static org.mockito.Mockito.times;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for {@link DataSourceXAResourceRecoveryHelper}.
|
|
||||||
*
|
|
||||||
* @author Gytis Trikleris
|
|
||||||
*/
|
|
||||||
public class DataSourceXAResourceRecoveryHelperTests {
|
|
||||||
|
|
||||||
private XADataSource xaDataSource;
|
|
||||||
|
|
||||||
private XAConnection xaConnection;
|
|
||||||
|
|
||||||
private XAResource xaResource;
|
|
||||||
|
|
||||||
private DataSourceXAResourceRecoveryHelper recoveryHelper;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void before() throws SQLException {
|
|
||||||
this.xaDataSource = mock(XADataSource.class);
|
|
||||||
this.xaConnection = mock(XAConnection.class);
|
|
||||||
this.xaResource = mock(XAResource.class);
|
|
||||||
this.recoveryHelper = new DataSourceXAResourceRecoveryHelper(this.xaDataSource);
|
|
||||||
|
|
||||||
given(this.xaDataSource.getXAConnection()).willReturn(this.xaConnection);
|
|
||||||
given(this.xaConnection.getXAResource()).willReturn(this.xaResource);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldCreateConnectionAndGetXAResource() throws SQLException {
|
|
||||||
XAResource[] xaResources = this.recoveryHelper.getXAResources();
|
|
||||||
assertThat(xaResources.length).isEqualTo(1);
|
|
||||||
assertThat(xaResources[0]).isSameAs(this.recoveryHelper);
|
|
||||||
verify(this.xaDataSource, times(1)).getXAConnection();
|
|
||||||
verify(this.xaConnection, times(1)).getXAResource();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldCreateConnectionWithCredentialsAndGetXAResource()
|
|
||||||
throws SQLException {
|
|
||||||
given(this.xaDataSource.getXAConnection(anyString(), anyString()))
|
|
||||||
.willReturn(this.xaConnection);
|
|
||||||
this.recoveryHelper = new DataSourceXAResourceRecoveryHelper(this.xaDataSource,
|
|
||||||
"username", "password");
|
|
||||||
XAResource[] xaResources = this.recoveryHelper.getXAResources();
|
|
||||||
assertThat(xaResources.length).isEqualTo(1);
|
|
||||||
assertThat(xaResources[0]).isSameAs(this.recoveryHelper);
|
|
||||||
verify(this.xaDataSource, times(1)).getXAConnection("username", "password");
|
|
||||||
verify(this.xaConnection, times(1)).getXAResource();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldFailToCreateConnectionAndNotGetXAResource() throws SQLException {
|
|
||||||
given(this.xaDataSource.getXAConnection())
|
|
||||||
.willThrow(new SQLException("Test exception"));
|
|
||||||
XAResource[] xaResources = this.recoveryHelper.getXAResources();
|
|
||||||
assertThat(xaResources.length).isEqualTo(0);
|
|
||||||
verify(this.xaDataSource, times(1)).getXAConnection();
|
|
||||||
verify(this.xaConnection, never()).getXAResource();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldDelegateRecoverCall() throws XAException {
|
|
||||||
this.recoveryHelper.getXAResources();
|
|
||||||
this.recoveryHelper.recover(XAResource.TMSTARTRSCAN);
|
|
||||||
verify(this.xaResource, times(1)).recover(XAResource.TMSTARTRSCAN);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldDelegateRecoverCallAndCloseConnection()
|
|
||||||
throws XAException, SQLException {
|
|
||||||
this.recoveryHelper.getXAResources();
|
|
||||||
this.recoveryHelper.recover(XAResource.TMENDRSCAN);
|
|
||||||
verify(this.xaResource, times(1)).recover(XAResource.TMENDRSCAN);
|
|
||||||
verify(this.xaConnection, times(1)).close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldDelegateStartCall() throws XAException {
|
|
||||||
this.recoveryHelper.getXAResources();
|
|
||||||
this.recoveryHelper.start(null, 0);
|
|
||||||
verify(this.xaResource, times(1)).start(null, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldDelegateEndCall() throws XAException {
|
|
||||||
this.recoveryHelper.getXAResources();
|
|
||||||
this.recoveryHelper.end(null, 0);
|
|
||||||
verify(this.xaResource, times(1)).end(null, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldDelegatePrepareCall() throws XAException {
|
|
||||||
this.recoveryHelper.getXAResources();
|
|
||||||
this.recoveryHelper.prepare(null);
|
|
||||||
verify(this.xaResource, times(1)).prepare(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldDelegateCommitCall() throws XAException {
|
|
||||||
this.recoveryHelper.getXAResources();
|
|
||||||
this.recoveryHelper.commit(null, true);
|
|
||||||
verify(this.xaResource, times(1)).commit(null, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldDelegateRollbackCall() throws XAException {
|
|
||||||
this.recoveryHelper.getXAResources();
|
|
||||||
this.recoveryHelper.rollback(null);
|
|
||||||
verify(this.xaResource, times(1)).rollback(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldDelegateIsSameRMCall() throws XAException {
|
|
||||||
this.recoveryHelper.getXAResources();
|
|
||||||
this.recoveryHelper.isSameRM(null);
|
|
||||||
verify(this.xaResource, times(1)).isSameRM(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldDelegateForgetCall() throws XAException {
|
|
||||||
this.recoveryHelper.getXAResources();
|
|
||||||
this.recoveryHelper.forget(null);
|
|
||||||
verify(this.xaResource, times(1)).forget(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldDelegateGetTransactionTimeoutCall() throws XAException {
|
|
||||||
this.recoveryHelper.getXAResources();
|
|
||||||
this.recoveryHelper.getTransactionTimeout();
|
|
||||||
verify(this.xaResource, times(1)).getTransactionTimeout();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldDelegateSetTransactionTimeoutCall() throws XAException {
|
|
||||||
this.recoveryHelper.getXAResources();
|
|
||||||
this.recoveryHelper.setTransactionTimeout(0);
|
|
||||||
verify(this.xaResource, times(1)).setTransactionTimeout(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,90 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-2017 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.narayana;
|
|
||||||
|
|
||||||
import javax.jms.ConnectionFactory;
|
|
||||||
import javax.sql.DataSource;
|
|
||||||
import javax.transaction.TransactionManager;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
|
||||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.spy;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for {@link NarayanaBeanFactoryPostProcessor}.
|
|
||||||
*
|
|
||||||
* @author Gytis Trikleris
|
|
||||||
*/
|
|
||||||
public class NarayanaBeanFactoryPostProcessorTests {
|
|
||||||
|
|
||||||
private AnnotationConfigApplicationContext context;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void setsDependsOn() {
|
|
||||||
DefaultListableBeanFactory beanFactory = spy(new DefaultListableBeanFactory());
|
|
||||||
this.context = new AnnotationConfigApplicationContext(beanFactory);
|
|
||||||
this.context.register(Config.class);
|
|
||||||
this.context.refresh();
|
|
||||||
verify(beanFactory).registerDependentBean("narayanaTransactionManager",
|
|
||||||
"dataSource");
|
|
||||||
verify(beanFactory).registerDependentBean("narayanaTransactionManager",
|
|
||||||
"connectionFactory");
|
|
||||||
verify(beanFactory).registerDependentBean("narayanaRecoveryManagerBean",
|
|
||||||
"dataSource");
|
|
||||||
verify(beanFactory).registerDependentBean("narayanaRecoveryManagerBean",
|
|
||||||
"connectionFactory");
|
|
||||||
this.context.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
static class Config {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public DataSource dataSource() {
|
|
||||||
return mock(DataSource.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public ConnectionFactory connectionFactory() {
|
|
||||||
return mock(ConnectionFactory.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public TransactionManager narayanaTransactionManager() {
|
|
||||||
return mock(TransactionManager.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public NarayanaRecoveryManagerBean narayanaRecoveryManagerBean() {
|
|
||||||
return mock(NarayanaRecoveryManagerBean.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public static NarayanaBeanFactoryPostProcessor narayanaPostProcessor() {
|
|
||||||
return new NarayanaBeanFactoryPostProcessor();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,148 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-2017 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.narayana;
|
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import com.arjuna.ats.arjuna.common.CoordinatorEnvironmentBean;
|
|
||||||
import com.arjuna.ats.arjuna.common.CoreEnvironmentBean;
|
|
||||||
import com.arjuna.ats.arjuna.common.ObjectStoreEnvironmentBean;
|
|
||||||
import com.arjuna.ats.arjuna.common.RecoveryEnvironmentBean;
|
|
||||||
import com.arjuna.ats.jta.common.JTAEnvironmentBean;
|
|
||||||
import com.arjuna.common.internal.util.propertyservice.BeanPopulator;
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import org.springframework.test.util.ReflectionTestUtils;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for {@link NarayanaConfigurationBean}.
|
|
||||||
*
|
|
||||||
* @author Gytis Trikleris
|
|
||||||
*/
|
|
||||||
public class NarayanaConfigurationBeanTests {
|
|
||||||
|
|
||||||
@After
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void cleanup() {
|
|
||||||
((Map<String, Object>) ReflectionTestUtils.getField(BeanPopulator.class,
|
|
||||||
"beanInstances")).clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldSetDefaultProperties() throws Exception {
|
|
||||||
NarayanaProperties narayanaProperties = new NarayanaProperties();
|
|
||||||
NarayanaConfigurationBean narayanaConfigurationBean = new NarayanaConfigurationBean(
|
|
||||||
narayanaProperties);
|
|
||||||
narayanaConfigurationBean.afterPropertiesSet();
|
|
||||||
|
|
||||||
assertThat(BeanPopulator.getDefaultInstance(CoreEnvironmentBean.class)
|
|
||||||
.getNodeIdentifier()).isEqualTo("1");
|
|
||||||
assertThat(BeanPopulator.getDefaultInstance(ObjectStoreEnvironmentBean.class)
|
|
||||||
.getObjectStoreDir()).endsWith("ObjectStore");
|
|
||||||
assertThat(BeanPopulator
|
|
||||||
.getNamedInstance(ObjectStoreEnvironmentBean.class, "communicationStore")
|
|
||||||
.getObjectStoreDir()).endsWith("ObjectStore");
|
|
||||||
assertThat(BeanPopulator
|
|
||||||
.getNamedInstance(ObjectStoreEnvironmentBean.class, "stateStore")
|
|
||||||
.getObjectStoreDir()).endsWith("ObjectStore");
|
|
||||||
assertThat(BeanPopulator.getDefaultInstance(CoordinatorEnvironmentBean.class)
|
|
||||||
.isCommitOnePhase()).isTrue();
|
|
||||||
assertThat(BeanPopulator.getDefaultInstance(CoordinatorEnvironmentBean.class)
|
|
||||||
.getDefaultTimeout()).isEqualTo(60);
|
|
||||||
assertThat(BeanPopulator.getDefaultInstance(RecoveryEnvironmentBean.class)
|
|
||||||
.getPeriodicRecoveryPeriod()).isEqualTo(120);
|
|
||||||
assertThat(BeanPopulator.getDefaultInstance(RecoveryEnvironmentBean.class)
|
|
||||||
.getRecoveryBackoffPeriod()).isEqualTo(10);
|
|
||||||
|
|
||||||
List<String> xaResourceOrphanFilters = Arrays.asList(
|
|
||||||
"com.arjuna.ats.internal.jta.recovery.arjunacore.JTATransactionLogXAResourceOrphanFilter",
|
|
||||||
"com.arjuna.ats.internal.jta.recovery.arjunacore.JTANodeNameXAResourceOrphanFilter");
|
|
||||||
assertThat(BeanPopulator.getDefaultInstance(JTAEnvironmentBean.class)
|
|
||||||
.getXaResourceOrphanFilterClassNames())
|
|
||||||
.isEqualTo(xaResourceOrphanFilters);
|
|
||||||
|
|
||||||
List<String> recoveryModules = Arrays.asList(
|
|
||||||
"com.arjuna.ats.internal.arjuna.recovery.AtomicActionRecoveryModule",
|
|
||||||
"com.arjuna.ats.internal.jta.recovery.arjunacore.XARecoveryModule");
|
|
||||||
assertThat(BeanPopulator.getDefaultInstance(RecoveryEnvironmentBean.class)
|
|
||||||
.getRecoveryModuleClassNames()).isEqualTo(recoveryModules);
|
|
||||||
|
|
||||||
List<String> expiryScanners = Arrays.asList(
|
|
||||||
"com.arjuna.ats.internal.arjuna.recovery.ExpiredTransactionStatusManagerScanner");
|
|
||||||
assertThat(BeanPopulator.getDefaultInstance(RecoveryEnvironmentBean.class)
|
|
||||||
.getExpiryScannerClassNames()).isEqualTo(expiryScanners);
|
|
||||||
|
|
||||||
assertThat(BeanPopulator.getDefaultInstance(JTAEnvironmentBean.class)
|
|
||||||
.getXaResourceRecoveryClassNames()).isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldSetModifiedProperties() throws Exception {
|
|
||||||
NarayanaProperties narayanaProperties = new NarayanaProperties();
|
|
||||||
narayanaProperties.setTransactionManagerId("test-id");
|
|
||||||
narayanaProperties.setLogDir("test-dir");
|
|
||||||
narayanaProperties.setDefaultTimeout(Duration.ofSeconds(1));
|
|
||||||
narayanaProperties.setPeriodicRecoveryPeriod(Duration.ofSeconds(2));
|
|
||||||
narayanaProperties.setRecoveryBackoffPeriod(Duration.ofSeconds(3));
|
|
||||||
narayanaProperties.setOnePhaseCommit(false);
|
|
||||||
narayanaProperties.setXaResourceOrphanFilters(
|
|
||||||
Arrays.asList("test-filter-1", "test-filter-2"));
|
|
||||||
narayanaProperties
|
|
||||||
.setRecoveryModules(Arrays.asList("test-module-1", "test-module-2"));
|
|
||||||
narayanaProperties
|
|
||||||
.setExpiryScanners(Arrays.asList("test-scanner-1", "test-scanner-2"));
|
|
||||||
|
|
||||||
NarayanaConfigurationBean narayanaConfigurationBean = new NarayanaConfigurationBean(
|
|
||||||
narayanaProperties);
|
|
||||||
narayanaConfigurationBean.afterPropertiesSet();
|
|
||||||
|
|
||||||
assertThat(BeanPopulator.getDefaultInstance(CoreEnvironmentBean.class)
|
|
||||||
.getNodeIdentifier()).isEqualTo("test-id");
|
|
||||||
assertThat(BeanPopulator.getDefaultInstance(ObjectStoreEnvironmentBean.class)
|
|
||||||
.getObjectStoreDir()).isEqualTo("test-dir");
|
|
||||||
assertThat(BeanPopulator
|
|
||||||
.getNamedInstance(ObjectStoreEnvironmentBean.class, "communicationStore")
|
|
||||||
.getObjectStoreDir()).isEqualTo("test-dir");
|
|
||||||
assertThat(BeanPopulator
|
|
||||||
.getNamedInstance(ObjectStoreEnvironmentBean.class, "stateStore")
|
|
||||||
.getObjectStoreDir()).isEqualTo("test-dir");
|
|
||||||
assertThat(BeanPopulator.getDefaultInstance(CoordinatorEnvironmentBean.class)
|
|
||||||
.isCommitOnePhase()).isFalse();
|
|
||||||
assertThat(BeanPopulator.getDefaultInstance(CoordinatorEnvironmentBean.class)
|
|
||||||
.getDefaultTimeout()).isEqualTo(1);
|
|
||||||
assertThat(BeanPopulator.getDefaultInstance(RecoveryEnvironmentBean.class)
|
|
||||||
.getPeriodicRecoveryPeriod()).isEqualTo(2);
|
|
||||||
assertThat(BeanPopulator.getDefaultInstance(RecoveryEnvironmentBean.class)
|
|
||||||
.getRecoveryBackoffPeriod()).isEqualTo(3);
|
|
||||||
assertThat(BeanPopulator.getDefaultInstance(JTAEnvironmentBean.class)
|
|
||||||
.getXaResourceOrphanFilterClassNames())
|
|
||||||
.isEqualTo(Arrays.asList("test-filter-1", "test-filter-2"));
|
|
||||||
assertThat(BeanPopulator.getDefaultInstance(RecoveryEnvironmentBean.class)
|
|
||||||
.getRecoveryModuleClassNames())
|
|
||||||
.isEqualTo(Arrays.asList("test-module-1", "test-module-2"));
|
|
||||||
assertThat(BeanPopulator.getDefaultInstance(RecoveryEnvironmentBean.class)
|
|
||||||
.getExpiryScannerClassNames())
|
|
||||||
.isEqualTo(Arrays.asList("test-scanner-1", "test-scanner-2"));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,126 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-2017 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.narayana;
|
|
||||||
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
import javax.sql.DataSource;
|
|
||||||
import javax.sql.XAConnection;
|
|
||||||
import javax.sql.XADataSource;
|
|
||||||
|
|
||||||
import com.arjuna.ats.internal.jdbc.ConnectionImple;
|
|
||||||
import com.arjuna.ats.jdbc.TransactionalDriver;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
import static org.mockito.BDDMockito.given;
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.times;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for {@link NarayanaDataSourceBean}.
|
|
||||||
*
|
|
||||||
* @author Gytis Trikleris
|
|
||||||
*/
|
|
||||||
public class NarayanaDataSourceBeanTests {
|
|
||||||
|
|
||||||
private XADataSource dataSource;
|
|
||||||
|
|
||||||
private NarayanaDataSourceBean dataSourceBean;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void before() {
|
|
||||||
this.dataSource = mock(XADataSource.class);
|
|
||||||
this.dataSourceBean = new NarayanaDataSourceBean(this.dataSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldBeAWrapper() throws SQLException {
|
|
||||||
assertThat(this.dataSourceBean.isWrapperFor(DataSource.class)).isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldNotBeAWrapper() throws SQLException {
|
|
||||||
assertThat(this.dataSourceBean.isWrapperFor(XADataSource.class)).isFalse();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldUnwrapDataSource() throws SQLException {
|
|
||||||
assertThat(this.dataSourceBean.unwrap(DataSource.class))
|
|
||||||
.isInstanceOf(DataSource.class);
|
|
||||||
assertThat(this.dataSourceBean.unwrap(DataSource.class))
|
|
||||||
.isSameAs(this.dataSourceBean);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldUnwrapXaDataSource() throws SQLException {
|
|
||||||
assertThat(this.dataSourceBean.unwrap(XADataSource.class))
|
|
||||||
.isInstanceOf(XADataSource.class);
|
|
||||||
assertThat(this.dataSourceBean.unwrap(XADataSource.class))
|
|
||||||
.isSameAs(this.dataSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldGetConnectionAndCommit() throws SQLException {
|
|
||||||
Connection mockConnection = mock(Connection.class);
|
|
||||||
XAConnection mockXaConnection = mock(XAConnection.class);
|
|
||||||
given(mockXaConnection.getConnection()).willReturn(mockConnection);
|
|
||||||
given(this.dataSource.getXAConnection()).willReturn(mockXaConnection);
|
|
||||||
|
|
||||||
Properties properties = new Properties();
|
|
||||||
properties.put(TransactionalDriver.XADataSource, this.dataSource);
|
|
||||||
|
|
||||||
Connection connection = this.dataSourceBean.getConnection();
|
|
||||||
assertThat(connection).isInstanceOf(ConnectionImple.class);
|
|
||||||
|
|
||||||
connection.commit();
|
|
||||||
|
|
||||||
verify(this.dataSource, times(1)).getXAConnection();
|
|
||||||
verify(mockXaConnection, times(1)).getConnection();
|
|
||||||
verify(mockConnection, times(1)).commit();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldGetConnectionAndCommitWithCredentials() throws SQLException {
|
|
||||||
String username = "testUsername";
|
|
||||||
String password = "testPassword";
|
|
||||||
Connection mockConnection = mock(Connection.class);
|
|
||||||
XAConnection mockXaConnection = mock(XAConnection.class);
|
|
||||||
given(mockXaConnection.getConnection()).willReturn(mockConnection);
|
|
||||||
given(this.dataSource.getXAConnection(username, password))
|
|
||||||
.willReturn(mockXaConnection);
|
|
||||||
|
|
||||||
Properties properties = new Properties();
|
|
||||||
properties.put(TransactionalDriver.XADataSource, this.dataSource);
|
|
||||||
properties.put(TransactionalDriver.userName, username);
|
|
||||||
properties.put(TransactionalDriver.password, password);
|
|
||||||
|
|
||||||
Connection connection = this.dataSourceBean.getConnection(username, password);
|
|
||||||
assertThat(connection).isInstanceOf(ConnectionImple.class);
|
|
||||||
|
|
||||||
connection.commit();
|
|
||||||
|
|
||||||
verify(this.dataSource, times(1)).getXAConnection(username, password);
|
|
||||||
verify(mockXaConnection, times(1)).getConnection();
|
|
||||||
verify(mockConnection, times(1)).commit();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-2017 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.narayana;
|
|
||||||
|
|
||||||
import com.arjuna.ats.jbossatx.jta.RecoveryManagerService;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.times;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for {@link NarayanaRecoveryManagerBean}.
|
|
||||||
*
|
|
||||||
* @author Gytis Trikleris
|
|
||||||
*/
|
|
||||||
public class NarayanaRecoveryManagerBeanTests {
|
|
||||||
|
|
||||||
private RecoveryManagerService service;
|
|
||||||
|
|
||||||
private NarayanaRecoveryManagerBean recoveryManager;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void before() {
|
|
||||||
this.service = mock(RecoveryManagerService.class);
|
|
||||||
this.recoveryManager = new NarayanaRecoveryManagerBean(this.service);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldCreateAndStartRecoveryManagerService() throws Exception {
|
|
||||||
this.recoveryManager.afterPropertiesSet();
|
|
||||||
verify(this.service, times(1)).create();
|
|
||||||
verify(this.service, times(1)).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void shouldStopAndDestroyRecoveryManagerService() throws Exception {
|
|
||||||
this.recoveryManager.destroy();
|
|
||||||
verify(this.service, times(1)).stop();
|
|
||||||
verify(this.service, times(1)).destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,77 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-2017 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.narayana;
|
|
||||||
|
|
||||||
import javax.jms.ConnectionFactory;
|
|
||||||
import javax.jms.XAConnectionFactory;
|
|
||||||
import javax.transaction.TransactionManager;
|
|
||||||
|
|
||||||
import org.jboss.narayana.jta.jms.ConnectionFactoryProxy;
|
|
||||||
import org.jboss.narayana.jta.jms.JmsXAResourceRecoveryHelper;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
|
||||||
import static org.mockito.BDDMockito.given;
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.times;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for {@link NarayanaXAConnectionFactoryWrapper}.
|
|
||||||
*
|
|
||||||
* @author Gytis Trikleris
|
|
||||||
*/
|
|
||||||
public class NarayanaXAConnectionFactoryWrapperTests {
|
|
||||||
|
|
||||||
private XAConnectionFactory connectionFactory = mock(XAConnectionFactory.class);
|
|
||||||
|
|
||||||
private TransactionManager transactionManager = mock(TransactionManager.class);
|
|
||||||
|
|
||||||
private NarayanaRecoveryManagerBean recoveryManager = mock(
|
|
||||||
NarayanaRecoveryManagerBean.class);
|
|
||||||
|
|
||||||
private NarayanaProperties properties = mock(NarayanaProperties.class);
|
|
||||||
|
|
||||||
private NarayanaXAConnectionFactoryWrapper wrapper = new NarayanaXAConnectionFactoryWrapper(
|
|
||||||
this.transactionManager, this.recoveryManager, this.properties);
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void wrap() {
|
|
||||||
ConnectionFactory wrapped = this.wrapper
|
|
||||||
.wrapConnectionFactory(this.connectionFactory);
|
|
||||||
assertThat(wrapped).isInstanceOf(ConnectionFactoryProxy.class);
|
|
||||||
verify(this.recoveryManager, times(1))
|
|
||||||
.registerXAResourceRecoveryHelper(any(JmsXAResourceRecoveryHelper.class));
|
|
||||||
verify(this.properties, times(1)).getRecoveryJmsUser();
|
|
||||||
verify(this.properties, times(1)).getRecoveryJmsPass();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void wrapWithCredentials() {
|
|
||||||
given(this.properties.getRecoveryJmsUser()).willReturn("userName");
|
|
||||||
given(this.properties.getRecoveryJmsPass()).willReturn("password");
|
|
||||||
ConnectionFactory wrapped = this.wrapper
|
|
||||||
.wrapConnectionFactory(this.connectionFactory);
|
|
||||||
assertThat(wrapped).isInstanceOf(ConnectionFactoryProxy.class);
|
|
||||||
verify(this.recoveryManager, times(1))
|
|
||||||
.registerXAResourceRecoveryHelper(any(JmsXAResourceRecoveryHelper.class));
|
|
||||||
verify(this.properties, times(2)).getRecoveryJmsUser();
|
|
||||||
verify(this.properties, times(1)).getRecoveryJmsPass();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,70 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-2017 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.narayana;
|
|
||||||
|
|
||||||
import javax.sql.DataSource;
|
|
||||||
import javax.sql.XADataSource;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
|
||||||
import static org.mockito.BDDMockito.given;
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.times;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for {@link NarayanaXADataSourceWrapper}.
|
|
||||||
*
|
|
||||||
* @author Gytis Trikleris
|
|
||||||
*/
|
|
||||||
public class NarayanaXADataSourceWrapperTests {
|
|
||||||
|
|
||||||
private XADataSource dataSource = mock(XADataSource.class);
|
|
||||||
|
|
||||||
private NarayanaRecoveryManagerBean recoveryManager = mock(
|
|
||||||
NarayanaRecoveryManagerBean.class);
|
|
||||||
|
|
||||||
private NarayanaProperties properties = mock(NarayanaProperties.class);
|
|
||||||
|
|
||||||
private NarayanaXADataSourceWrapper wrapper = new NarayanaXADataSourceWrapper(
|
|
||||||
this.recoveryManager, this.properties);
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void wrap() {
|
|
||||||
DataSource wrapped = this.wrapper.wrapDataSource(this.dataSource);
|
|
||||||
assertThat(wrapped).isInstanceOf(NarayanaDataSourceBean.class);
|
|
||||||
verify(this.recoveryManager, times(1)).registerXAResourceRecoveryHelper(
|
|
||||||
any(DataSourceXAResourceRecoveryHelper.class));
|
|
||||||
verify(this.properties, times(1)).getRecoveryDbUser();
|
|
||||||
verify(this.properties, times(1)).getRecoveryDbPass();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void wrapWithCredentials() {
|
|
||||||
given(this.properties.getRecoveryDbUser()).willReturn("userName");
|
|
||||||
given(this.properties.getRecoveryDbPass()).willReturn("password");
|
|
||||||
DataSource wrapped = this.wrapper.wrapDataSource(this.dataSource);
|
|
||||||
assertThat(wrapped).isInstanceOf(NarayanaDataSourceBean.class);
|
|
||||||
verify(this.recoveryManager, times(1)).registerXAResourceRecoveryHelper(
|
|
||||||
any(DataSourceXAResourceRecoveryHelper.class));
|
|
||||||
verify(this.properties, times(2)).getRecoveryDbUser();
|
|
||||||
verify(this.properties, times(1)).getRecoveryDbPass();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,89 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
<parent>
|
|
||||||
<artifactId>spring-boot-samples</artifactId>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<version>${revision}</version>
|
|
||||||
</parent>
|
|
||||||
<artifactId>spring-boot-sample-jta-narayana</artifactId>
|
|
||||||
<name>Spring Boot Narayana JTA Sample</name>
|
|
||||||
<description>Spring Boot Narayana JTA Sample</description>
|
|
||||||
<properties>
|
|
||||||
<main.basedir>${basedir}/../..</main.basedir>
|
|
||||||
</properties>
|
|
||||||
<dependencies>
|
|
||||||
<!-- Compile -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework</groupId>
|
|
||||||
<artifactId>spring-jms</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-jta-narayana</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-artemis</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.activemq</groupId>
|
|
||||||
<artifactId>artemis-jms-server</artifactId>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<artifactId>geronimo-jms_2.0_spec</artifactId>
|
|
||||||
<groupId>org.apache.geronimo.specs</groupId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.h2database</groupId>
|
|
||||||
<artifactId>h2</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<!-- Test -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
<profiles>
|
|
||||||
<profile>
|
|
||||||
<id>java9</id>
|
|
||||||
<activation>
|
|
||||||
<jdk>[9,)</jdk>
|
|
||||||
</activation>
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>javax.xml.bind</groupId>
|
|
||||||
<artifactId>jaxb-api</artifactId>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
<!-- workaround for SUREFIRE-1424 -->
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<argLine>--add-modules java.base</argLine>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
</profile>
|
|
||||||
</profiles>
|
|
||||||
</project>
|
|
@ -1,43 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-2016 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 sample.narayana;
|
|
||||||
|
|
||||||
import javax.persistence.Entity;
|
|
||||||
import javax.persistence.GeneratedValue;
|
|
||||||
import javax.persistence.Id;
|
|
||||||
|
|
||||||
@Entity
|
|
||||||
public class Account {
|
|
||||||
|
|
||||||
@Id
|
|
||||||
@GeneratedValue
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
private String username;
|
|
||||||
|
|
||||||
Account() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public Account(String username) {
|
|
||||||
this.username = username;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUsername() {
|
|
||||||
return this.username;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-2016 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 sample.narayana;
|
|
||||||
|
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
|
||||||
|
|
||||||
public interface AccountRepository extends JpaRepository<Account, Long> {
|
|
||||||
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-2017 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 sample.narayana;
|
|
||||||
|
|
||||||
import javax.transaction.Transactional;
|
|
||||||
|
|
||||||
import org.springframework.jms.core.JmsTemplate;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
@Service
|
|
||||||
@Transactional
|
|
||||||
public class AccountService {
|
|
||||||
|
|
||||||
private final JmsTemplate jmsTemplate;
|
|
||||||
|
|
||||||
private final AccountRepository accountRepository;
|
|
||||||
|
|
||||||
public AccountService(JmsTemplate jmsTemplate, AccountRepository accountRepository) {
|
|
||||||
this.jmsTemplate = jmsTemplate;
|
|
||||||
this.accountRepository = accountRepository;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void createAccountAndNotify(String username) {
|
|
||||||
this.jmsTemplate.convertAndSend("accounts", username);
|
|
||||||
this.accountRepository.save(new Account(username));
|
|
||||||
if ("error".equals(username)) {
|
|
||||||
throw new SampleRuntimeException("Simulated error");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-2016 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 sample.narayana;
|
|
||||||
|
|
||||||
import org.springframework.jms.annotation.JmsListener;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
public class Messages {
|
|
||||||
|
|
||||||
@JmsListener(destination = "accounts")
|
|
||||||
public void onMessage(String content) {
|
|
||||||
System.out.println("----> " + content);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-2016 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 sample.narayana;
|
|
||||||
|
|
||||||
import java.io.Closeable;
|
|
||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|
||||||
import org.springframework.context.ApplicationContext;
|
|
||||||
|
|
||||||
@SpringBootApplication
|
|
||||||
public class SampleNarayanaApplication {
|
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
|
||||||
ApplicationContext context = SpringApplication
|
|
||||||
.run(SampleNarayanaApplication.class, args);
|
|
||||||
AccountService service = context.getBean(AccountService.class);
|
|
||||||
AccountRepository repository = context.getBean(AccountRepository.class);
|
|
||||||
service.createAccountAndNotify("josh");
|
|
||||||
System.out.println("Count is " + repository.count());
|
|
||||||
try {
|
|
||||||
// Using username "error" will cause service to throw SampleRuntimeException
|
|
||||||
service.createAccountAndNotify("error");
|
|
||||||
}
|
|
||||||
catch (SampleRuntimeException ex) {
|
|
||||||
// Log message to let test case know that exception was thrown
|
|
||||||
System.out.println(ex.getMessage());
|
|
||||||
}
|
|
||||||
System.out.println("Count is " + repository.count());
|
|
||||||
((Closeable) context).close();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-2016 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 sample.narayana;
|
|
||||||
|
|
||||||
public class SampleRuntimeException extends RuntimeException {
|
|
||||||
|
|
||||||
public SampleRuntimeException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
logging.level.com.arjuna=INFO
|
|
||||||
spring.artemis.embedded.queues=accounts
|
|
||||||
spring.jpa.open-in-view=true
|
|
@ -1,65 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-2016 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 sample.narayana;
|
|
||||||
|
|
||||||
import org.assertj.core.api.Condition;
|
|
||||||
import org.junit.Rule;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import org.springframework.boot.test.rule.OutputCapture;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Basic integration tests for demo application.
|
|
||||||
*
|
|
||||||
* @author Gytis Trikleris
|
|
||||||
*/
|
|
||||||
public class SampleNarayanaApplicationTests {
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public OutputCapture outputCapture = new OutputCapture();
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testTransactionRollback() throws Exception {
|
|
||||||
SampleNarayanaApplication.main(new String[] {});
|
|
||||||
String output = this.outputCapture.toString();
|
|
||||||
assertThat(output).has(substring(1, "---->"));
|
|
||||||
assertThat(output).has(substring(1, "----> josh"));
|
|
||||||
assertThat(output).has(substring(2, "Count is 1"));
|
|
||||||
assertThat(output).has(substring(1, "Simulated error"));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Condition<String> substring(int times, String substring) {
|
|
||||||
return new Condition<String>(
|
|
||||||
"containing '" + substring + "' " + times + " times") {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean matches(String value) {
|
|
||||||
int i = 0;
|
|
||||||
while (value.contains(substring)) {
|
|
||||||
int beginIndex = value.indexOf(substring) + substring.length();
|
|
||||||
value = value.substring(beginIndex);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
return i == times;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in New Issue