package org.infinispan.counter.impl.listener;
import org.infinispan.commons.logging.LogFactory;
import org.infinispan.counter.api.CounterEvent;
import org.infinispan.counter.api.CounterListener;
import org.infinispan.counter.api.Handle;
import org.infinispan.counter.logging.Log;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* A notification manager for {@link CounterListener}.
* <p>
* It allows to register (and remove) {@link CounterListener} and it triggers the notification via {@link
* #notify(CounterEvent)}.
*
* @author Pedro Ruivo
* @since 9.0
*/
public class NotificationManager {
private static final Log log = LogFactory.getLog(NotificationManager.class, Log.class);
private final List<CounterListenerResponse> listenerList;
public NotificationManager() {
listenerList = new CopyOnWriteArrayList<>();
}
/**
* It adds a {@link CounterListener}.
* <p>
* Duplicated value are <b>not</b> added.
*
* @param listener The listener to add.
* @param <T> The type of the listener.
* @return The {@link Handle} that allows the listener to be removed.
*/
public <T extends CounterListener> Handle<T> addListener(T listener) {
CounterListenerResponse<T> wrapper = new CounterListenerResponse<>(Objects.requireNonNull(listener), listenerList);
for (Handle<?> clc : listenerList) {
if (wrapper.equals(clc)) {
//noinspection unchecked
return (Handle<T>) clc;
}
}
listenerList.add(wrapper);
return wrapper;
}
/**
* It notifies all the registered listeners with the {@link CounterEvent}.
*
* @param event The {@link CounterEvent} to trigger.
*/
public void notify(CounterEvent event) {
listenerList.forEach(l -> l.onUpdate(event));
}
private static class CounterListenerResponse<T extends CounterListener> implements Handle<T>, CounterListener {
private final T listener;
private final List<CounterListenerResponse> list;
private CounterListenerResponse(T listener, List<CounterListenerResponse> list) {
this.listener = listener;
this.list = list;
}
@Override
public T getCounterListener() {
return listener;
}
@Override
public void remove() {
list.remove(this);
}
@Override
public void onUpdate(CounterEvent event) {
try {
listener.onUpdate(event);
} catch (Throwable t) {
log.warnf(t, "Exception while invoking listener %s", listener);
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CounterListenerResponse<?> that = (CounterListenerResponse<?>) o;
return listener.equals(that.listener);
}
@Override
public int hashCode() {
return listener.hashCode();
}
}
}