package com.interpress_project.modernshare.client.events;

import java.util.Enumeration;
import java.util.Vector;

/**
 * イベントソース・オブジェクト イベントソースをロックしたままイベントリスナを呼び出すと、
 * イベントリスナの処理によってはデッドロックが発生してしまう。これらの問題は
 * 以下の点を考慮した実装で解決する。
 * - イベントリスナの登録・削除はsynchronized状態で行う。
 * - イベントリスナに対する呼び出しはsynchronizedでない状態で行う。
 * - イベントリスナを管理しているlistenersにアクセスする時だけsynchronizedを使用して
 *   オブジェクトをロックすることと
 * - イベントの送信はlistenersを複製したものに対して行うこと。
 *
 * この実装ならイベントリスナが長時間スレッドを占有しても、他のスレッドがこのオブジェクトを
 * 使用すること(オブジェクトの登録削除処理も含めて)がブロックされることはなくなる。
 *
 * @stereotype Event source
 */
public class LogEventSource {
	/**
	 * @stereotype uses
	 */
	/*#com.interpress_project.modernshare.client.events.LogEvent Dependency20*/

	private static Vector<ILogEventListener> listeners = new Vector<ILogEventListener>(3);
	/**
	 * Holds singleton instance
	 */
	private static LogEventSource instance;

	/**
	 * CommandEventSource
	 */
	private LogEventSource() {
	}

	/**
	 * addEventListener
	 * @param listener
	 */
	public void addEventListener(ILogEventListener listener) {
		if (listeners.contains(listener)) {
			return;
		}
		listeners.addElement(listener);
	}

	/**
	 * removeEventListener
	 * @param listener
	 */
	public void removeEventListener(ILogEventListener listener) {
		listeners.removeElement(listener);
	}

	/**
	 * fireEvent イベントリスナを管理しているlisteners_にアクセスする時だけ synchronizedを使用して
	 * オブジェクトをロックすることと、イベントの送信はlistenersを複製したものに対して行うこと。
	 * リスナを管理しているVectorのaddElementメソッドとremoveElementメソッド、さらに
	 * cloneメソッドはsynchronizedになっているため、排他制御を行う必要がない。
	 *
	 * @param eventName String
	 */
	public void fireEvent(LogEvent event) {
		Vector vector = (Vector) listeners.clone();
		Enumeration enumeration = vector.elements();
		while (enumeration.hasMoreElements()) {
			ILogEventListener l = (ILogEventListener) enumeration.nextElement();
			l.EventArrived(event);
		}
	}

	/**
	 * Returns the singleton instance.
	 @return	the singleton instance
	 */
	static public LogEventSource getInstance() {
		if (instance == null) {
			instance = new LogEventSource();
		}
		return instance;
	}
}
