package org.limewire.listener;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.limewire.listener.EventListenerList.EventListenerListContext;
/** A default implementation of {@link SourcedEventMulticaster}. */
public class SourcedEventMulticasterImpl<E extends SourcedEvent<S>, S> implements
SourcedEventMulticaster<E, S> {
/** The context all listeners will use. */
private final EventListenerListContext listenerContext;
/** The list of listeners for every change event. */
private final EventListenerList<E> listenersForAll;
/** A Map of listeners for each source. */
private final Map<S, EventListenerList<E>> sourceListeners;
public SourcedEventMulticasterImpl() {
this(new EventListenerListContext());
}
public SourcedEventMulticasterImpl(EventListenerListContext context) {
this.listenerContext = context;
this.listenersForAll = new EventListenerList<E>(listenerContext);
this.sourceListeners = new ConcurrentHashMap<S, EventListenerList<E>>();
}
@Override
public void handleEvent(E event) {
broadcast(event);
}
@Override
public void broadcast(E event) {
listenersForAll.broadcast(event);
// No lock is necessary here, because a ConcurrentHashMap is used,
// so it is thread-safe as far as retrieval goes.
EventListenerList<E> list = sourceListeners.get(event.getSource());
if(list != null) {
list.broadcast(event);
}
}
@Override
public void addListener(EventListener<E> listener) {
listenersForAll.addListener(listener);
}
@Override
public void addListener(S source, EventListener<E> listener) {
// This is locked on sourceListeners to prevent race conditions
// where #removeListener(S, EventListener<E>) removes
// the list between getting & inserting.
synchronized(sourceListeners) {
EventListenerList<E> list = sourceListeners.get(source);
if(list == null) {
list = new EventListenerList<E>(listenerContext);
sourceListeners.put(source, list);
}
list.addListener(listener);
}
}
@Override
public boolean removeListener(EventListener<E> listener) {
return listenersForAll.removeListener(listener);
}
@Override
public boolean removeListener(S source, EventListener<E> listener) {
// This is locked on sourceListeners to prevent race conditions
// where #addListener(S, EventListener<E>) adds a listener
// between checking for the size & removal.
synchronized(sourceListeners) {
EventListenerList<E> list = sourceListeners.get(source);
if(list == null) {
return false;
} else {
boolean removed = list.removeListener(listener);
if(list.size() == 0) {
sourceListeners.remove(source);
}
return removed;
}
}
}
@Override
public boolean removeListeners(S source) {
synchronized(sourceListeners) {
return sourceListeners.remove(source) != null;
}
}
}