/*
* Copyrights (C) 2008 Bearice (Bearice@Gmail.com)
* Release under GNU/GPL Version 2.
*/
package cn.bearice.java.util.listener;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.EventListener;
import java.util.List;
import java.util.TreeSet;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 监听器支持。
* 同于扩展特定的监听器支持类。
* <p>提供监听器的添加,获取和移除服务。提供多监听器的全同步、全异步、顺序同步,顺序异步调用。</p>
* <p>调用侦听器时不保证侦听器的调用顺序。</p>
* <p>除非特别说明,传人任何等于null的参数都将引发NullPointerException</p>
* @author Bearice
*/
public abstract class ListenerSupport<T extends EventListener> {
protected static final ExecutorService tp = Executors.newCachedThreadPool();
protected static final ExecutorService stp = Executors.newSingleThreadExecutor();
protected Collection<T> listeners = new TreeSet<T>();
private static class ListenerCaller implements Callable<Object> {
private Method method;
private Object[] args;
private EventListener listener;
public ListenerCaller(Method method, EventListener listener, Object[] args) {
this.method = method;
this.args = args;
this.listener = listener;
}
public Object call() throws Exception {
return method.invoke(tp, args);
}
}
/**
* 添加一个侦听器。
* <p>如果侦听器已经存在,则忽略。</p>
* @param listener 要添加的侦听器
* @throws NullPointerException listener等于null
*/
public void addListener(T listener) {
if (listener == null) {
throw new NullPointerException();
}
if (!listeners.contains(listener)) {
listeners.add(listener);
}
}
/**
* 移除一个侦听器。
* <p>如果侦听器不存在,则忽略。</p>
* @param listener 要移除的侦听器
* @throws NullPointerException listener等于null
*/
public void removeListener(T listener) {
if (listener == null) {
throw new NullPointerException();
}
if (listeners.contains(listener)) {
listeners.remove(listener);
}
}
/**
* 获取所有侦听器。
* 返回一个包含所有侦听器的<b>不可修改的</b>侦听器集合副本。
* 任何针对该副本的修改操作将引发异常
* @return 侦听器集合副本。
*/
public Collection<T> getAllListeners() {
return Collections.unmodifiableCollection(listeners);
}
/**
* 全异步调用所有侦听器。
* <p>所有侦听器将在不同的线程中同时调用,该方法不会阻塞当前线程。</p>
* <p><b>异常处理:</b>侦听器可以抛出任何异常,但异常将被忽略</p>
* @param method 要调用的方法对象
* @param args 参数
*/
protected void fireEventAsync(Method method, Object... args) {
for (EventListener eventListener : listeners) {
tp.submit(new ListenerCaller(method, eventListener, args));
}
}
/**
* 全同步调用所有侦听器。
* <p>所有侦听器将在不同的线程中同时调用,该方法会阻塞当前线程并等待所有监听器调用全部返回之后才返回</p>
* <p><b>异常处理:</b>侦听器可以抛出任何异常,但异常将被忽略</p>
* @param method 要调用的方法对象
* @param args 参数
*/
protected void fireEventSync(Method method, Object... args) throws InterruptedException {
List<Callable> allCallable = new ArrayList<Callable>(listeners.size());
for (EventListener eventListener : listeners) {
allCallable.add(new ListenerCaller(method, eventListener, args));
}
tp.invokeAll((Collection) allCallable);
}
/**
* 顺序异步调用所有侦听器。
* <p>所有侦听器将在相同同的线程中顺序调用,该方法不会阻塞当前线程。</p>
* <p><b>异常处理:</b>侦听器可以抛出任何异常,但异常将被忽略</p>
* <p><b>调用顺序:</b>不确定调用侦听器的顺序</p>
* @param method 要调用的方法对象
* @param args 参数
*/
protected void fireEventAsyncSeq(Method method, Object... args) {
for (EventListener eventListener : listeners) {
stp.submit(new ListenerCaller(method, eventListener, args));
}
}
/**
* 顺序同步调用所有侦听器。
* <p>所有侦听器将在相同的线程中顺序调用,该方法会阻塞当前线程并等待所有监听器调用全部返回之后才返回</p>
* <p><b>异常处理:</b>侦听器可以抛出任何异常,但异常将被忽略</p>
* <p><b>调用顺序:</b>不确定调用侦听器的顺序</p>
* @param method 要调用的方法对象
* @param args 参数
*/
protected void fireEventSyncSeq(Method method, Object... args) throws InterruptedException {
List<Callable> allCallable = new ArrayList<Callable>(listeners.size());
for (EventListener eventListener : listeners) {
allCallable.add(new ListenerCaller(method, eventListener, args));
}
stp.invokeAll((Collection) allCallable);
}
}
如何防止切开的苹果“生锈”?
5 年前
0 人次吐槽:
发表评论