/*
 * $Id$
 * Copyright (c) 2006 LOGICAL-PARADOX.ORG
 */
package org.logical_paradox.rss.rcm.accessor.mysql.validator;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * データベース接続確認ツール．
 * @author satoshi akabane@logical-paradox.org
 * @versiop $Revision$
 */
public class ConnectionValidator extends Thread {
	/** 検証対象接続セットのリスト */
	private final List<ConnectionValidation> validations = new ArrayList<ConnectionValidation>();
	/** ping間隔 */
	private final long interval;

	/**
	 * コンストラクタ．
	 * この検証ツールはdaemonスレッドとして動作する．
	 * @param msec ping間隔(単位:msec.)
	 */
	public ConnectionValidator(long msec) {
		interval = msec;
		setDaemon(true);
	}
	/**
	 * 接続検証オブジェクトを追加する．
	 * @param validation 接続検証オブジェクト
	 */
	public void add(ConnectionValidation validation) {
		validations.add(validation);
	}
	/**
	 * 接続検証オブジェクトを全てクローズする．
	 * 普通このメソッドは使用しなくても良いはず．
	 */
	public void closeAll() {
		for(ConnectionValidation validation : validations) {
			try {
				validation.close();
			} catch(SQLException e) {
				// ほっとくしかないので無視する
			}
		}

		// 検証オブジェクトを全削除
		validations.clear();
	}
	/**
	 * スレッドメイン．
	 */
	@Override
	public void run() {
		try {
			while(true) {
				Thread.sleep(interval);
				// pingを打つ
				List<ConnectionValidation> closedConnections = new ArrayList<ConnectionValidation>();
				for(ConnectionValidation validation : validations) {
					try {
						validation.ping();
					} catch (SQLException e) {
						// pingが失敗したので，この接続は恐らく継続できない
						closedConnections.add(validation);
					}
				}

				// 既に無効になってしまったと思われる接続検証オブジェクトを破棄する
				// とりあえず，クローズする努力ぐらいしてみる
				for(ConnectionValidation validation : closedConnections) {
					try {
						validation.close();
					} catch(SQLException e) {
						// 無視
					}
				}
				// 無効接続全削除
				validations.removeAll(closedConnections);
			}
		} catch(InterruptedException e) {
			// バリデータを停止する．
			close();
		}
	}
	/**
	 * スレッドを停止する．
	 */
	public void shutdown() {
		interrupt();
	}
	/**
	 * このバリデーターを終了する．
	 */
	protected void close() {
		closeAll();
	}
}
