package roboguice.event;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import roboguice.event.eventListener.ObserverMethodListener;
import roboguice.inject.ContextSingleton;
import com.google.inject.Inject;
import android.content.Context;
/**
* Manager class handling the following:
*
* Registration of event observing methods:
* registerObserver()
* unregisterObserver()
* clear()
* Raising Events:
* fire()
*
* @author Adam Tybor
* @author John Ericksen
*/
@ContextSingleton
public class EventManager {
@Inject protected Context context;
protected Map<Class<?>, Set<EventListener<?>>> registrations = new HashMap<Class<?>, Set<EventListener<?>>>(); // synchronized set
/**
* Register the given EventListener to the contest and event class.
*
* @param event observed
* @param listener to be triggered
* @param <T> event type
*/
public <T> void registerObserver( Class<T> event, EventListener<?> listener ) {
Set<EventListener<?>> observers = registrations.get(event);
if (observers == null) {
observers = new CopyOnWriteArraySet<EventListener<?>>();
registrations.put(event, observers);
}
observers.add(listener);
}
/**
* Registers given method with provided context and event.
*
* @param instance to be called
* @param method to be called
* @param event observed
*/
public <T> void registerObserver(Object instance, Method method, Class<T> event) {
registerObserver(event, new ObserverMethodListener<T>(instance, method));
}
/**
* Unregisters the provided event listener from the given event
*
* @param event observed
* @param listener to be unregistered
* @param <T> event type
*/
public <T> void unregisterObserver(Class<T> event, EventListener<T> listener ) {
final Set<EventListener<?>> observers = registrations.get(event);
if (observers == null) return;
observers.remove(listener);
}
/**
* Unregister all methods observing the given event from the provided context.
*
* @param instance to be unregistered
* @param event observed
*/
public <T> void unregisterObserver(Object instance, Class<T> event) {
final Set<EventListener<?>> observers = registrations.get(event);
if (observers == null) return;
// As documented in http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Collections.html#synchronizedSet(java.util.Set)
//noinspection SynchronizationOnLocalVariableOrMethodParameter
ObserverMethodListener<?> toRemove = null;
for (Iterator<EventListener<?>> iterator = observers.iterator(); iterator.hasNext();) {
final EventListener<?> listener = iterator.next();
if( listener instanceof ObserverMethodListener ) {
final ObserverMethodListener<?> observer = ((ObserverMethodListener<?>)listener);
if (observer.getInstance() == instance) {
toRemove = observer;
break;
}
}
}
if( toRemove != null ) {
observers.remove(toRemove);
}
}
/**
* Raises the event's class' event on the given context. This event object is passed (if configured) to the
* registered observer's method.
*
* @param event observed
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public void fire(Object event) {
final Set<EventListener<?>> observers = registrations.get(event.getClass());
if (observers == null) return;
for (EventListener observer : observers)
//noinspection unchecked
observer.onEvent(event);
}
protected Set<EventListener<?>> copyObservers(Set<EventListener<?>> observers) {
// As documented in http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Collections.html#synchronizedSet(java.util.Set)
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (observers) {
return new LinkedHashSet<EventListener<?>>(observers);
}
}
public void destroy() {
for( Entry<Class<?>, Set<EventListener<?>>> e : registrations.entrySet() )
e.getValue().clear();
registrations.clear();
}
}