package jp.sf.amateras.mirage.integration.seasar;

import java.sql.Connection;
import java.sql.SQLException;

import javax.sql.XADataSource;
import javax.transaction.Synchronization;
import javax.transaction.TransactionSynchronizationRegistry;

import jp.sf.amateras.mirage.provider.ConnectionProvider;
import jp.sf.amateras.mirage.provider.DefaultConnectionProvider;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * {@link ConnectionProvider} implementation which gets a connection from javax.sql.XADataSource.
 *
 * @author Naoki Takezoe
 */
public class SeasarConnectionProvider extends DefaultConnectionProvider {

	private static final Logger logger = LoggerFactory.getLogger(SeasarConnectionProvider.class);

	private XADataSource xaDataSource;
	private ThreadLocal<Boolean> registered= new ThreadLocal<Boolean>();
	private TransactionSynchronizationRegistry syncRegistry;

	public void setXADataSource(XADataSource xaDataSource) {
		this.xaDataSource = xaDataSource;
	}

	public void setTransactionSynchronizationRegistry(TransactionSynchronizationRegistry syncRegistry) {
		this.syncRegistry = syncRegistry;
	}

	@Override
	public Connection getConnection() throws SQLException {
		// If TransactionSynchronizationRegistry exists,
		// register Synchronization to release connection automatically
		// at the first invocation of this method in the current thread.
		if(syncRegistry != null && registered.get() == null){
			syncRegistry.registerInterposedSynchronization(new Synchronization() {
				@Override
				public void beforeCompletion() {
				}

				@Override
				public void afterCompletion(int status) {
					releaseConnection();
					registered.remove();
				}
			});
			registered.set(true);
		}

		Connection conn = super.getConnection();
		if(conn == null){
			if(logger.isDebugEnabled()){
				logger.debug("Get connection from XADataSource.");
			}
			conn = xaDataSource.getXAConnection().getConnection();
			conn.setAutoCommit(false);
			setConnection(conn);
		}

		return conn;
	}

}
