/*
* Copyright 2014 Atteo.
*
* 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.atteo.moonshine.btm;
import java.lang.management.ManagementFactory;
import javax.inject.Singleton;
import javax.jms.ConnectionFactory;
import javax.jms.XAConnectionFactory;
import javax.sql.DataSource;
import javax.sql.XADataSource;
import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import org.atteo.config.XmlDefaultValue;
import org.atteo.moonshine.jta.JtaConnectionFactoryWrapper;
import org.atteo.moonshine.jta.JtaDataSourceWrapper;
import org.atteo.moonshine.jta.JtaService;
import org.atteo.moonshine.jta.PoolOptions;
import com.google.inject.AbstractModule;
import com.google.inject.Module;
import bitronix.tm.BitronixTransactionManager;
import bitronix.tm.Configuration;
import bitronix.tm.TransactionManagerServices;
import bitronix.tm.resource.jdbc.PoolingDataSource;
import bitronix.tm.resource.jms.PoolingConnectionFactory;
/**
* Bitronix JTA transaction manager.
*/
@XmlRootElement(name = "btm")
public class BTM extends JtaService {
@XmlElement
@XmlDefaultValue("${dataHome}/jta/logs/btm1.log")
private String logPart1FileName;
@XmlElement
@XmlDefaultValue("${dataHome}/jta/logs/btm2.log")
private String logPart2FileName;
/**
* The default timeout (in seconds) that is set for transactions when no timeout is specified.
*/
@XmlElement
@XmlDefaultValue("60")
private Integer transactionTimeout;
private BitronixTransactionManager transactionManager;
private static class BitronixDataSourceWrapper implements JtaDataSourceWrapper {
@Override
public DataSource wrap(String name, XADataSource xaDataSource, PoolOptions poolOptions, String testQuery) {
PoolingDataSource dataSource = new PoolingDataSource();
dataSource.setUniqueName(name);
dataSource.setXaDataSource(xaDataSource);
if (poolOptions == null) {
poolOptions = new PoolOptions();
}
if (poolOptions.getMinPoolSize() != null) {
dataSource.setMinPoolSize(poolOptions.getMinPoolSize());
}
if (poolOptions.getMaxPoolSize() != null) {
dataSource.setMaxPoolSize(poolOptions.getMaxPoolSize());
}
if (poolOptions.getMaxIdleTime() != null) {
dataSource.setMaxIdleTime(poolOptions.getMaxIdleTime());
}
if (poolOptions.getMaxLifeTime() != null) {
dataSource.setMaxLifeTime(poolOptions.getMaxLifeTime());
}
// TODO: poolOptions.getReapTimeout();
dataSource.setTestQuery(testQuery);
// DDL statement cannot be executed within XA transaction
// So we need to allow non-XA statements during
dataSource.setAllowLocalTransactions(true);
return dataSource;
}
@Override
public void close(DataSource dataSource) {
((PoolingDataSource)dataSource).close();
}
}
private static class BitronixFactoryConnectionWrapper implements JtaConnectionFactoryWrapper {
@Override
public ConnectionFactory wrap(String name, XAConnectionFactory xaFactory, PoolOptions poolOptions) {
PoolingConnectionFactory connectionFactory = new PoolingConnectionFactory();
connectionFactory.setUniqueName(name);
connectionFactory.setXaConnectionFactory(xaFactory);
if (poolOptions == null) {
poolOptions = new PoolOptions();
}
if (poolOptions.getMinPoolSize() != null) {
connectionFactory.setMinPoolSize(poolOptions.getMinPoolSize());
}
if (poolOptions.getMaxPoolSize() != null) {
connectionFactory.setMaxPoolSize(poolOptions.getMaxPoolSize());
}
if (poolOptions.getMaxIdleTime() != null) {
connectionFactory.setMaxIdleTime(poolOptions.getMaxIdleTime());
}
if (poolOptions.getMaxLifeTime() != null) {
connectionFactory.setMaxLifeTime(poolOptions.getMaxLifeTime());
}
// TODO: poolOptions.getReapTimeout();
return connectionFactory;
}
@Override
public void close(ConnectionFactory connectionFactory) {
((PoolingConnectionFactory)connectionFactory).close();
}
}
@Override
public Module configure() {
return new AbstractModule() {
@Override
protected void configure() {
configureCommon(binder());
LocalBitronixContext.initNewContext();
Configuration configuration = TransactionManagerServices.getConfiguration();
configuration.setLogPart1Filename(logPart1FileName);
configuration.setLogPart2Filename(logPart2FileName);
configuration.setDisableJmx(true);
configuration.setServerId(ManagementFactory.getRuntimeMXBean().getName());
configuration.setDefaultTransactionTimeout(transactionTimeout);
transactionManager = TransactionManagerServices.getTransactionManager();
bind(TransactionManager.class).toInstance(transactionManager);
bind(UserTransaction.class).toInstance(transactionManager);
bind(JtaDataSourceWrapper.class).to(BitronixDataSourceWrapper.class).in(Singleton.class);
bind(JtaConnectionFactoryWrapper.class).to(BitronixFactoryConnectionWrapper.class).in(Singleton.class);
}
};
}
@Override
public void close() {
transactionManager.shutdown();
transactionManager = null;
}
}