/*
 * $Id: RNodeDSyncMngr.java,v 1.2 2005/10/22 16:27:27 rampil Exp $
 * Copyright (c) 2005 LOGICAL-PARADOX.ORG
 */
package org.logical_paradox.rss.router;

import java.util.Vector;

import org.logical_paradox.common.net.IPAddressRangeSet;
import org.logical_paradox.rss.dsync.RSSSyncConfig;
import org.logical_paradox.rss.dsync.RSSSyncDaemon;
import org.logical_paradox.rss.dsync.RSSSyncInterface;
import org.logical_paradox.rss.dsync.SyncCommand;
import org.logical_paradox.rss.dsync.SyncQueueException;
import org.logical_paradox.rss.http.URLPool;

/**
 * 経路決定ノード/RSSWebNavigatorにおける遅延同期データ回送のユーティリティ．
 * このクラスを使うと，ロック情報の差分管理などができる．
 * @author satoshi akabane@logical-paradox.org
 * @version $Revision: 1.2 $
 */
public class RNodeDSyncMngr extends RSSSyncDaemon {
	/** 探索ロック管理オブジェクト */
	private final SiteLockMgr lockMgr;
	/** URLプール */
	private final URLPool pool;

	/**
	 * コンストラクタ．
	 * IPアドレス範囲セットが指定されている場合，その範囲内で探索ロックを発行する．
	 * IPアドレス範囲設定が指定されていない場合，全てのIPアドレスが探索の対象となる．
	 * @param daemonConfig コンフィグレーション
	 * @param dsi 同期インターフェース
	 * @param expire 探索ロックの有効期限
	 * @param p URLプール
	 * @param rs IPアドレス範囲セット(null:範囲制限なし)
	 * @throws Exception インスタンスの生成に失敗した
	 */
	public RNodeDSyncMngr(RSSSyncConfig daemonConfig, RSSSyncInterface dsi, long expire, URLPool p, IPAddressRangeSet rs) throws Exception {
		super(daemonConfig, dsi);

		if(rs != null) {
			lockMgr = new RestrictedSiteLockMgr(expire, rs);
		} else {
			lockMgr = new SiteLockMgr(expire);
		}
		pool = p;
	}

	/**
	 * ロック情報を追加する．
	 * ロックを追加することができた場合はtrue，失敗した場合はfalseが返る．<br>
	 * IPアドレス範囲設定による制限がある場合，その範囲内でなければロック取得に失敗する．<br>
	 * また，保有しているロックが多すぎる場合も拒否される．<br>
	 * IPアドレス範囲設定の範囲内のサイトか，あるいはIPアドレス範囲セットが設定されていない場合，<br>
	 * ロックの取得に成功する(はず)．
	 * @param l ロックしようとしている探索ロックオブジェクト
	 * @return true:ロック取得成功 / false:ロック取得失敗
	 * @throws SynQueueException 何らかの理由で処理に失敗した
	 */
	public boolean lock(SiteLock l) throws SyncQueueException {
		boolean rc = lockMgr.lock(l);
		if(rc == true) {
			// ロックが追加できたので，差分情報を書き込む
			add(new SyncCommand(l, SyncCommand.COMMAND_LOCK, null, null));
		}
		return rc;
	}

	/**
	 * 指定されたロックを取得する
	 * 指定され探索ノードのIDで取得できなかった場合はnull
	 */
	public SiteLock findLock(String dn, String rid) {
		return lockMgr.findLock(dn, rid);
	}

	/**
	 * サイトロックのゴミを回収する
	 * 回収したゴミのリストを配列で返す
	 */
	public SiteLock[] gc() {
		SiteLock[] removedObjLocal = lockMgr.gc();			// ローカルでGCする
		Vector removedObjRemote = new Vector();				// キューに載せられたアンロック情報

		// 期限切れで削除された探索ロックをUNLOCK情報として他のノードへも転送する
		try {
			for(int i = 0; i < removedObjLocal.length; i++) {
				unlock(removedObjLocal[i]);
				removedObjRemote.addElement(removedObjLocal[i]);
			}
		} catch(SyncQueueException se) {
			// キューがいっぱいになってるくさいので，終了
			// 残りは次回に回してみる
		}

		return (SiteLock[])removedObjRemote.toArray(new SiteLock[1]);
	}

	/**
	 * 指定IDの探索ノードが保有しているロックの数を返す
	 */
	public int numOfMyLocks(String robotId) {
		return lockMgr.numOfMyLocks(robotId);
	}

	/**
	 * URLプールを返す
	 */
	public URLPool getPool() {
		return pool;
	}

	/**
	 * ロックを解除する
	 */
	public void unlock(SiteLock l) throws SyncQueueException {
		lockMgr.unlock(l);
		add(new SyncCommand(l, SyncCommand.COMMAND_UNLOCK, null, null));
	}

	/**
	 * 未処理URLを追加する
	 */
	public void poolURL(String url) throws SyncQueueException {
		add(new SyncCommand(url, SyncCommand.COMMAND_FORWARD_URL, null, null));
	}

	/**
	 * 未処理URLを削除する
	 */
	public void dropURL(String url) throws SyncQueueException {
		add(new SyncCommand(url, SyncCommand.COMMAND_UNFORWARD_URL, null, null));
	}

	/**
	 * 遅延同期デーモンの終了処理
	 *このメソッドょ呼び出すと，遅延同期デーモンのバッファをフラッシュしながら安全に終了する
	 */
	public void done() {
		interrupt();
	}
}

// end of RNodeDSyncMngr.java
