package proton.inject.observer;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import proton.inject.InvocationException;
import proton.inject.util.SparseClassArray;
public class ObserverManager {
private SparseClassArray<List<Observer>> mObservers = new SparseClassArray<List<Observer>>();
public void registerIfObserver(Object obj) {
for (Class<?> clazz = obj.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) {
for (Method method : clazz.getDeclaredMethods()) {
Class<?> eventClass = findObserveEvent(method);
if (eventClass != null)
register(eventClass, new Observer(obj, method));
}
}
}
private void register(Class<?> eventClass, Observer observer) {
synchronized (this) {
List<Observer> list = mObservers.get(eventClass);
if (list == null) {
list = new ArrayList<Observer>();
mObservers.put(eventClass, list);
}
list.add(observer);
}
}
public void fire(Object event) {
synchronized (this) {
List<Observer> list = mObservers.get(event.getClass());
if (list == null)
return;
for (Observer observer : list) {
try {
observer.method.invoke(observer.receiver, event);
} catch (IllegalArgumentException exp) {
throw new InvocationException(exp);
} catch (IllegalAccessException exp) {
throw new InvocationException(exp);
} catch (InvocationTargetException exp) {
throw new InvocationException(exp);
}
}
}
}
public void destroy() {
synchronized (this) {
mObservers.clear();
}
}
private Class<?> findObserveEvent(Method method) {
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
for (int i = 0; i < parameterAnnotations.length; ++i) {
Annotation[] annotations = parameterAnnotations[i];
Class<?> type = method.getParameterTypes()[i];
for (Annotation ann : annotations) {
if (ann.annotationType() == Observes.class)
return type;
}
}
return null;
}
private static class Observer {
private Object receiver;
private Method method;
private Observer(Object receiver, Method method) {
this.receiver = receiver;
this.method = method;
}
}
}