package org.maachang.dao.dbms.pool;

import java.io.IOException;

/**
 * 未使用コネクション破棄監視. <BR>
 * <BR>
 * 未使用のコネクションを破棄するためのスレッド.
 * 
 * @version 2007/10/18
 * @author masahito suzuki
 * @since MaachangDao 1.00
 */
class PoolThread extends Thread {
    /**
     * スレッド待機時間.
     */
    private static final long SLEEP_TIME = 5000L;

    /**
     * 未使用コネクション破棄時間 : 最小時間. 1分.
     */
    private static final long MIN_TIME = 60000L;

    /**
     * 未使用コネクション破棄時間 : 最大時間. 30分.
     */
    private static final long MAX_TIME = 1800000L;

    /**
     * 未使用コネクション破棄時間 : デフォルト時間. 5分.
     */
    private static final long DEF_TIME = 300000L;

    /**
     * 未使用コネクション破棄時間.
     */
    private long deleteTime = -1L;

    /**
     * Factoryオブジェクト.
     */
    private OnePoolManager factory = null;

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

    /**
     * スレッド停止フラグ.
     */
    private volatile boolean exitFlag = false;

    /**
     * コンストラクタ.
     */
    private PoolThread() {

    }

    /**
     * コンストラクタ. <BR>
     * <BR>
     * 指定引数でオブジェクトを生成します. <BR>
     * 
     * @param factory
     *            対象のPoolFactoryを設定します.
     * @exception IllegalArgumentException
     *                入力例外.
     * @exception IOException
     *                アクセス例外.
     */
    public PoolThread(OnePoolManager factory) throws IllegalArgumentException,
            IOException {
        this(DEF_TIME, factory);
    }

    /**
     * コンストラクタ. <BR>
     * <BR>
     * 指定引数でオブジェクトを生成します. <BR>
     * 
     * @param time
     *            コネクション未使用時の破棄時間を設定します.<BR>
     *            指定可能な最小時間は[60000L]です.<BR>
     *            指定可能な最大時間は[1800000L]です.
     * @param factory
     *            対象のPoolFactoryを設定します.
     * @exception IllegalArgumentException
     *                入力例外.
     */
    public PoolThread(long time, OnePoolManager factory)
            throws IllegalArgumentException {
        if (factory == null) {
            throw new IllegalArgumentException("引数は不正です");
        }

        if (time <= MIN_TIME) {
            time = MIN_TIME;
        } else if (time >= MAX_TIME) {
            time = MAX_TIME;
        }

        this.deleteTime = time;
        this.factory = factory;
        this.exitFlag = false;
        sync = factory.getSync();
        this.start();
    }

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

    /**
     * オブジェクト破棄. <BR>
     * <BR>
     * オブジェクトを破棄します.
     */
    public void destroy() {
        synchronized (sync) {
            exitFlag = true;
        }

        this.deleteTime = -1L;
        this.factory = null;
        sync = null;
    }

    /**
     * 未使用コネクション破棄時間を取得. <BR>
     * <BR>
     * 設定されている未使用コネクション破棄時間を取得します. <BR>
     * 
     * @return long 未使用コネクション破棄時間が返されます.
     */
    public long getDeleteTime() {
        return this.deleteTime;
    }

    /**
     * スレッド動作チェック. <BR>
     * <BR>
     * 対象オブジェクトのスレッドが動作しているかチェックします. <BR>
     * 
     * @return boolean チェック結果が返されます.<BR>
     *         [true]が返された場合、スレッドは動作しています.<BR>
     *         [false]が返された場合、スレッドは動作していません.
     */
    public boolean isThread() {
        return this.isAlive();
    }

    /**
     * スレッド実行. <BR>
     * <BR>
     * スレッド実行を行います.
     */
    public void run() {
        boolean stopFlag = false;
        for (; stopFlag == false;) {
            this.execution();
            synchronized (sync) {
                if (exitFlag == true) {
                    stopFlag = true;
                }
            }
        }
    }

    /**
     * 実行処理をサポートします。 <BR>
     * <BR>
     * 実行処理をサポートします。<BR>
     * この処理は、スレッドでの実行処理に対して呼び出し実行されます.
     */
    private final void execution() {
        int i;
        int len;

        long tm;
        PoolConnection[] cons = null;
        PoolConnection con = null;

        try {

            Thread.sleep(SLEEP_TIME);

            synchronized (sync) {
                tm = this.deleteTime;
                cons = this.factory.getArrays();
            }

            len = cons.length;
            for (i = 0; i < len; i++) {

                Thread.sleep(30L);

                synchronized (sync) {

                    if ((con = cons[i]) == null) {

                        continue;

                    }

                    synchronized (con.getSync()) {

                        if (con.isUse() == false
                                && con.getLastAccessTime() + tm < System
                                        .currentTimeMillis()) {
                            con = null;
                            cons[i] = null;

                        }

                    }

                    con = null;

                }

            }

        } catch (InterruptedException ie) {
            synchronized (sync) {
                exitFlag = true;
            }
        } catch (Exception e) {
        }
    }
}
