de.team33.patterns.notes.eris.Audience Maven / Gradle / Ivy
package de.team33.patterns.notes.eris;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
/**
* Implementation of a registry with the additional option to send messages to the registered listeners.
*/
public class Audience implements Registry {
private final Object monitor = new Object();
private final Map, List>> backing = new HashMap<>(0);
private final Executor executor;
/**
* Initializes a new instance that synchronously {@linkplain #send(Channel, Object) sends} messages to the
* {@linkplain #add(Channel, Consumer) registered} listeners.
*/
public Audience() {
this(Runnable::run);
}
/**
* Initializes a new instance that {@linkplain #send(Channel, Object) sends} messages to the
* {@linkplain #add(Channel, Consumer) registered} listeners using a given {@link Executor}.
*/
public Audience(final Executor executor) {
this.executor = executor;
}
@SuppressWarnings({"rawtypes", "unchecked"})
private List> getListeners(final Channel channel) {
final List list = backing.get(channel);
return (null == list) ? Collections.emptyList() : list;
}
@SuppressWarnings({"rawtypes", "unchecked"})
private void putListeners(final Channel channel, final List newList) {
backing.put(channel, newList);
}
@Override
public final void add(final Channel channel, final Consumer super M> listener) {
synchronized (monitor) {
final List> oldList = getListeners(channel);
final List> newList = new ArrayList<>(oldList.size() + 1);
newList.addAll(oldList);
newList.add(listener);
putListeners(channel, newList);
}
}
private static Optional> emitter(final Collection extends Consumer super M>> listeners) {
return listeners.isEmpty()
? Optional.empty()
: Optional.of(message -> listeners.forEach(listener -> listener.accept(message)));
}
private Optional> emitter(final Channel super M> channel) {
synchronized (monitor) {
return emitter(getListeners(channel));
}
}
/**
* Sends a given message to all listeners that have {@linkplain #add(Channel, Consumer) registered}
* for the given {@link Channel}.
*
* @param The message type.
*/
public final void send(final Channel channel, final M message) {
emitter(channel).ifPresent(emitter -> executor.execute(() -> emitter.accept(message)));
}
}