package org.itscool.commons.connection;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.itscool.commons.bean.BeanFactory;
import org.itscool.commons.logging.AbstractLog;
import org.itscool.commons.logging.SimpleLog;

/**
 * トランザクション制御用フィルタ<BR>
 * コネクションプールの初期化及びデータアクセス層で実行されたトランザクション
 * の実行結果よりコミット/ロールバック処理を行うフィルタです。
 *
 * @author kanou
 *
 */
public class TransactionFilter implements Filter{
    private AbstractLog log;
    private boolean initFlag = false;
    
    /**
     * コネクションプールの初期化を行います<BR>
     * BeanFactoryインスタンスを使って、web.xmlのコンテキストパラメータ「di-config-framework」
     * に指定されたBean定義ファイルからConnectionMangaerインスタンスを取得します。
     * BeanFactoryインスタンスはStartupFilterであらかじめ初期化されている必要があります。
     *
     * @param filterConfig FilterConfigインスタンス
     */
    public void init(FilterConfig filterConfig) throws ServletException {
        BeanFactory factory = BeanFactory.getInstance();
        if( !factory.isInit() ){
            try{
                factory.createForUrl("di-config.xml");
            }catch(Exception ex){
                ex.printStackTrace();
                throw new ServletException(ex.getMessage());
            }
        }
        
        try{
            if( factory.isDefined("Log") ){
                log = (AbstractLog)factory.getInstance("Log");
                if(!log.isInit()){
                    log = (AbstractLog)factory.createInstance("Log");
                }
            }else{
                log = SimpleLog.getInstance();
            }
        }catch(Exception ioe){
            throw new ServletException(ioe.getMessage());
        }
        
        try{
            ConnectionManager manager = (ConnectionManager)factory.createInstance("ConnectionManager");
            manager.init();
            log.info("completed initialize instance='" + manager.getClass().getName() + "'" );
            log.info("ConnectionManager Info="+manager.toString());
            initFlag = true;
        }catch(Exception ex){
            log.error("ConnectionManager is not initialized (" + ex.getMessage() + ")");
        }
    }
    
    /**
     * chain.doFilter()実行後にトランザクションのコミット/ロールバック処理を行います<BR>
     * トランザクション制御は以下の流れで行われます<BR>
     * (1) chain.doFilter()の呼び出し<BR>
     * (2) TransactionUtil.getTransaction()よりThreadLocalにセットされているTransaction
     * インスタンスを取得<BR>
     * (3) Transactionインスタンスのステータスを取得<BR>
     * (4) ステータスがPLEASE_COMMITの場合はコミット処理を行います<BR>
     * (4)' ステータスがPLEASE_ROLLBACKの場合はロールバック処理を行います<BR>
     * (4)'' Exceptionが発生した場合もロールバック処理を行います<BR>
     * (4)''' それ以外の場合は何も行いません<BR>
     * (5) ThreadLocalにセットされたトランザクションをコネクションプールに戻します<BR>
     *
     * @param request ServletRequestインスタンス
     * @param response ServletResponseインスタンス
     */
    public void doFilter(ServletRequest request, ServletResponse response,
        FilterChain chain)
        throws IOException, ServletException {
        
        try {
            if( initFlag == true ){
                //トランザクションを開始します。
                TransactionUtil.beginTransaction();
                //業務ロジックを実行します。
                chain.doFilter(request, response);
                //トランザクションステータスがPLEASE_COMMITならコミットを行う
                if(TransactionUtil.getTransaction().getTranStatus() == Transaction.PLEASE_COMMIT ){
                    TransactionUtil.commitTransaction();
                    log.trace("COMMIT TRANSACTION");
                }else if(TransactionUtil.getTransaction().getTranStatus() == Transaction.PLEASE_ROLLBACK){
                    TransactionUtil.rollbackTransaction();
                    log.trace("ROLLBACK TRANSACTION");
                }
            }else{
                //業務ロジックを実行します。
                chain.doFilter(request, response);
            }
        }catch(TransactionException e){
            try{
                if(TransactionUtil.getTransaction().getTranStatus() == Transaction.PLEASE_ROLLBACK){
                    TransactionUtil.rollbackTransaction();
                    log.trace("ROLLBACK TRANSACTION");
                }
            }catch(TransactionException te){}
            throw e;
        } finally {
            try{
                if(TransactionUtil.getTransaction().getTranStatus() == Transaction.PLEASE_ROLLBACK){
                    TransactionUtil.rollbackTransaction();
                    log.trace("ROLLBACK TRANSACTION");
                }
            }catch(TransactionException te){}
            log.trace("RELEASE TRANSACTION");
            //トランザクションを終了します。
            TransactionUtil.returnTransaction();
        }
    }
    
    /**
     * 全てのコネクションを閉じた後、コネクションプールを開放します
     */
    public void destroy() {
        BeanFactory factory = BeanFactory.getInstance();
        ConnectionManager manager = (ConnectionManager)factory.createInstance("ConnectionManager");
        manager.destroy();
    }
}
