package org.maachang.dao.dbms.pool;

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

/**
 * PoolConnection実体. <BR>
 * <BR>
 * PoolConnection実体を表すオブジェクト.
 * 
 * @version 2007/10/18
 * @author masahito suzuki
 * @since MaachangDao 1.00
 */
class PoolConnection {
    /**
     * DBコネクション.
     */
    private java.sql.Connection connection = null;

    /**
     * コネクション生成チェックSQL.
     */
    private String chkSQL = null;

    /**
     * 利用状況フラグ.<BR>
     * コネクションがオープンされた時に[true].<BR>
     * コネクションがクローズされた時に[false].<BR>
     * いずれも、オープン=[open()],クローズ=[close()]で、メソッドが 呼び出された場合に適応.
     */
    private boolean useFlag = false;

    /**
     * 最終アクティブ時間.
     */
    private long active = -1L;

    /**
     * 最終アクセス時間.
     */
    private long lastAccess = -1L;

    /**
     * コミット/ロールバックフラグ.
     */
    private boolean commitRollbackFlag = false;

    /**
     * クローズコミットフラグ.
     */
    private boolean closeByCommitFlag = false;

    /**
     * 同期オブジェクト.
     */
    private Object sync = new Object();

    /**
     * コンストラクタ.
     */
    protected PoolConnection() {

    }

    /**
     * ファイナライズ処理定義. <BR>
     * <BR>
     * ファイナライズ処理定義. <BR>
     * 
     * @exception Exception
     *                例外処理が返されます.
     */
    protected final void finalize() throws Exception {
        try {
            this.destroyObject();
        } catch (Exception e) {
        }
    }

    /**
     * オブジェクトを生成. <BR>
     * <BR>
     * オブジェクトを生成します. <BR>
     * 
     * @param connection
     *            対象のコネクションオブジェクトを設定します.
     * @param closeByCommit
     *            クローズ時コミット処理を行うか設定します.<BR>
     *            [true]を設定した場合、クローズ時コミットします.<BR>
     *            [false]を設定した場合、クローズ時ロールバックします.
     * @exception Exception
     *                例外.
     */
    protected void createObject(Connection connection, boolean closeByCommit)
            throws Exception {
        this.createObject(connection, null, closeByCommit);
    }

    /**
     * オブジェクトを生成. <BR>
     * <BR>
     * オブジェクトを生成します. <BR>
     * 
     * @param connection
     *            対象のコネクションオブジェクトを設定します.
     * @param sql
     *            コネクションチェック用SQLを設定します.
     * @param closeByCommit
     *            クローズ時コミット処理を行うか設定します.<BR>
     *            [true]を設定した場合、クローズ時コミットします.<BR>
     *            [false]を設定した場合、クローズ時ロールバックします.
     * @exception Exception
     *                例外.
     */
    protected void createObject(Connection connection, String sql,
            boolean closeByCommit) throws Exception {
        if (connection == null) {
            throw new IllegalArgumentException("引数は不正です");
        }

        try {
            if (connection.isClosed() == true) {
                throw new IllegalArgumentException("指定コネクションは、既にクローズされています");
            }

            this.destroyObject();

            synchronized (sync) {
                this.connection = connection;
                this.chkSQL = (sql == null || (sql = sql.trim()).length() <= 0) ? null
                        : sql;
                this.useFlag = false;
                this.active = -1L;
                this.lastAccess = System.currentTimeMillis();
                this.commitRollbackFlag = false;
                this.closeByCommitFlag = closeByCommit;
            }

        } catch (IllegalArgumentException in) {
            this.destroyObject();
            throw in;
        } catch (Exception e) {
            this.destroyObject();
            throw e;
        }
    }

    /**
     * オブジェクト破棄. <BR>
     * <BR>
     * オブジェクトを破棄します.
     */
    protected void destroyObject() {
        try {
            synchronized (sync) {
                try {
                    if (this.connection != null) {
                        this.connection.close();
                    }
                } catch (Exception ee) {
                }

                this.connection = null;
                this.chkSQL = null;
                this.useFlag = false;
                this.active = -1L;
                this.lastAccess = System.currentTimeMillis();
                this.commitRollbackFlag = false;
                // this.closeByCommitFlag = false ;
            }

        } catch (Exception e) {
        }

        this.connection = null;
        this.chkSQL = null;
        this.useFlag = false;
        this.active = -1L;
        this.commitRollbackFlag = false;
        // this.closeByCommitFlag = false ;

    }

    /**
     * オープン処理を実施. <BR>
     * <BR>
     * オープン処理を実施します. <BR>
     * 
     * @return boolean オープン処理が成功した場合に[true], 失敗した場合に[false]が返されます.
     */
    public boolean open() {
        boolean ret = false;

        try {

            synchronized (sync) {

                if (this.connection != null && this.useFlag == false) {
                    // コネクションが接続を確立している場合.
                    if (this.isCuttingConnection() == false) {

                        // コネクションを利用可能に設定.
                        this.useFlag = true;
                        this.active = System.currentTimeMillis();
                        this.lastAccess = System.currentTimeMillis();
                        this.commitRollbackFlag = false;
                        ret = true;

                    }
                }

            }

        } catch (Exception e) {
            ret = false;
        }

        return ret;
    }

    /**
     * オブジェクトクローズ. <BR>
     * <BR>
     * オブジェクトをクローズします. <BR>
     * 
     * @exception SQLException
     *                SQL例外.
     */
    public void close() throws SQLException {
        try {

            synchronized (sync) {

                // クローズ処理が可能で、
                // コミットロールバックが
                // 行われていない場合.
                if (this.connection != null && this.commitRollbackFlag == false
                        && this.useFlag == true) {

                    // クローズ時コミットの場合.
                    if (this.closeByCommitFlag == true) {
                        try {
                            this.connection.commit();
                        } catch (SQLException sse) {
                            this.destroyObject();
                            throw sse;
                        }
                    }
                    // クローズ時ロールバックの場合.
                    else {
                        try {
                            this.connection.rollback();
                        } catch (SQLException sse) {
                            this.destroyObject();
                            throw sse;
                        }
                    }

                }

                // ワーニングを削除.
                if (this.connection != null) {
                    try {
                        this.connection.clearWarnings();
                    } catch (Exception ee) {
                    }
                }

                this.useFlag = false;
                this.commitRollbackFlag = false;
                this.active = -1L;
                this.lastAccess = System.currentTimeMillis();

            }

        } catch (NullPointerException nue) {
        } catch (SQLException se) {
            throw se;
        } catch (Exception e) {
            throw new SQLException(e.getMessage());
        }

    }

    /**
     * アクティブに設定された時間を取得. <BR>
     * <BR>
     * アクティブに設定された時間を取得します. <BR>
     * 
     * @return long 最終アクティブ時間が返されます.
     */
    public long getActiveTime() {
        long ret;

        try {
            synchronized (sync) {
                ret = this.active;
            }
        } catch (Exception e) {
            ret = -1L;
        }

        return ret;
    }

    /**
     * 最終利用時間を取得. <BR>
     * <BR>
     * 最終利用時間を取得します. <BR>
     * 
     * @return long 最終利用時間を取得します.
     */
    public long getLastAccessTime() {
        long ret;

        try {
            synchronized (sync) {
                ret = this.lastAccess;
            }
        } catch (Exception e) {
            ret = -1L;
        }

        return ret;
    }

    /**
     * コネクションチェック用SQLを取得. <BR>
     * <BR>
     * 設定されているコネクションチェック用SQLを取得します. <BR>
     * 
     * @return String 設定されているコネクションチェック用SQLが返されます.
     */
    public String getCheckSQL() {
        String ret = null;

        try {
            synchronized (sync) {
                ret = this.chkSQL;
            }
        } catch (Exception e) {
            ret = null;
        }

        return ret;
    }

    /**
     * クローズ時のコミット/ロールバック処理指定を取得. <BR>
     * <BR>
     * クローズ処理時に、コミット／ロールバックしていない場合の、 処理条件を取得します. <BR>
     * 
     * @return boolean 処理条件が返されます.<BR>
     *         [true]が返された場合、クローズ時にコミット処理が呼ばれます.<BR>
     *         [false]が返された場合、クローズ時にロールバック処理が呼ばれます.
     */
    public boolean isClosedByIf() {
        boolean ret;

        try {
            synchronized (sync) {
                ret = this.closeByCommitFlag;
            }
        } catch (Exception e) {
            ret = this.closeByCommitFlag;
        }

        return ret;
    }

    /**
     * コミット/ロールバック処理が呼び出されたかチェック. <BR>
     * <BR>
     * コミット/ロールバック処理が呼び出されたかチェックします. <BR>
     * 
     * @return boolean コミット/ロールバック処理が呼び出されたかチェックします.<BR>
     *         [true]が返された場合、コミット/ロールバック処理は呼び出されました.<BR>
     *         [false]が返された場合、コミット/ロールバック処理は呼び出されていません.
     */
    public boolean isCommitRoolback() {
        boolean ret;

        try {
            synchronized (sync) {
                ret = this.commitRollbackFlag;
            }
        } catch (Exception e) {
            ret = false;
        }

        return ret;
    }

    /**
     * 利用状況を取得. <BR>
     * <BR>
     * コネクション利用状況を取得します.<BR>
     * <BR>
     * 
     * @return boolean コネクション利用状況を取得します.<BR>
     *         [true]が返された場合、コネクションは利用(Active)です.<BR>
     *         [false]が返された場合、コネクションは利用されていません.
     */
    public boolean isUse() {
        boolean ret;

        try {
            synchronized (sync) {
                ret = this.useFlag;
            }
        } catch (Exception e) {
            ret = false;
        }

        return ret;
    }

    /**
     * コネクションオブジェクトを取得.
     */
    protected final Connection getConnection() throws SQLException {
        Connection ret = null;

        try {
            synchronized (sync) {

                this.checkOpen();
                this.lastAccess = System.currentTimeMillis();
                ret = this.connection;

            }
        } catch (SQLException se) {
            throw se;
        } catch (Exception e) {
            throw new SQLException(e.getMessage());
        }

        return ret;
    }

    /**
     * コネクションが物理的に切断されているかチェック.
     */
    protected final boolean isCuttingConnection() {
        boolean ret;

        Statement tmp = null;

        ret = false;

        synchronized (sync) {

            try {

                // 接続チェック.
                ret = this.connection.isClosed();
                tmp = this.connection.createStatement();

                // 接続確認用SQLを発行.
                if (this.chkSQL != null) {
                    tmp.execute(this.chkSQL);
                }

            } catch (Exception e) {

                ret = true;

            } finally {

                // 生成されたステートメントをクリア.
                try {
                    tmp.close();
                } catch (Exception ee) {
                }

                tmp = null;

            }

        }

        return ret;
    }

    /**
     * オープンチェック.
     */
    protected final void checkOpen() throws SQLException {
        try {
            synchronized (sync) {
                if (this.useFlag == false) {
                    throw new SQLException("オープンされていません");
                }
            }
        } catch (SQLException se) {
            throw se;
        } catch (Exception e) {
            throw new SQLException("オープンされていません");
        }
    }

    /**
     * コミット、ロールバックフラグをONに設定.
     */
    protected final void commitRollbackON() {
        try {
            synchronized (sync) {
                this.commitRollbackFlag = true;
            }
        } catch (Exception e) {
        }
    }

    /**
     * 同期オブジェクトを取得.
     */
    protected final Object getSync() {
        return sync;
    }

}
