package org.itscool.commons.connection;

import java.sql.PreparedStatement;
import org.itscool.commons.bean.BeanFactory;
import org.itscool.commons.dao.PreparedStatementWrapper;
import org.itscool.commons.logging.AbstractLog;
import org.itscool.commons.logging.SimpleLog;

/**
 * TransactionインスタンスをThreadLocal（スレッド単位で一意となる変数）で
 * 管理するクラスです<br/>
 * サーブレットで使用する場合、サーブレットの1リクエスト/レスポンスが、1スレッド
 * に割り当てられます<br/>
 * このクラスを使ってコネクションのOpenSessionInViewパターンを利用することができます
 * @author kano
 */
public class TransactionUtil {
    
    private static final ThreadLocal threadTransaction = new ThreadLocal();
    
    /**
     * トランザクションを開始します。
     */
    public static void beginTransaction(){
        getTransaction();
    }
    
    /**
     * トランザクションインスタンスを取得し、スレッドローカルインスタンスにセットします<BR>
     * トランザクションが初期化されていない場合は、トランザクションの初期化を行います。
     * @return Transactionインスタンスを返します。
     */
    public static Transaction getTransaction() {
        Transaction tx = (Transaction) threadTransaction.get();
        if (tx == null) {
            BeanFactory factory = BeanFactory.getInstance();
            ConnectionManager mgr = (ConnectionManager)factory.createInstance("ConnectionManager");
            tx = mgr.getTransaction();
            threadTransaction.set(tx);
        }
        return tx;
    }
    
    /**
     * PreparedStatementを取得します
     * @param sql SQL文字列
     * @return PreparedStatementを返します
     */
    public static PreparedStatement getPreparedStatement(String sql){
        Transaction trn = getTransaction();
        PreparedStatement pstmt = trn.getPrepareStatement(sql);
        return pstmt;
    }
    /**
     * PrepareStatementWrapperを取得します
     * @param sql SQL文字列
     * @return PrepareStatementWrapperを返します
     */
    public static PreparedStatementWrapper getPreparedStatementWrapper(String sql){
        AbstractLog log = SimpleLog.getInstance();
        Transaction trn = getTransaction();
        PreparedStatement pstmt = trn.getPrepareStatement(sql);
        PreparedStatementWrapper wrapper = new PreparedStatementWrapper(pstmt);
        if( trn.getShowSql()){
            log.info(sql);
        }
        return wrapper;
    }
    /**
     * コミットを行います
     */
    public static void commitTransaction() {
        // Would be written as a no-op in an EJB container with CMT
        Transaction tx = (Transaction) threadTransaction.get();
        try {
            if ( tx != null ) {
                tx.commit();
            }
            //threadTransaction.set(null);
        } catch (TransactionException ex) {
            rollbackTransaction();
            throw ex;
        }
    }
    
    /**
     * ロールバックを行います
     */
    public static void rollbackTransaction() {
        // Would be written as a no-op in an EJB container with CMT (maybe setRollBackOnly...)
        Transaction tx = (Transaction) threadTransaction.get();
        try {
            //threadTransaction.set(null);
            if ( tx != null ) {
                tx.rollback();
            }
        } catch (TransactionException ex) {
            throw ex;
        }
    }
    
    /**
     * Transactionインスタンスをコネクションプールに返します
     */
    public static void returnTransaction(){
        Transaction tx = (Transaction) threadTransaction.get();
        if( tx != null ){
            BeanFactory factory = BeanFactory.getInstance();
            ConnectionManager mgr = (ConnectionManager)factory.createInstance("ConnectionManager");
            mgr.returnTransaction(tx);
        }
        threadTransaction.set(null);
    }
}
