package se.l4.vibe.internal; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import se.l4.vibe.event.EventListener; import se.l4.vibe.event.EventSeverity; import se.l4.vibe.event.Events; import se.l4.vibe.probes.AbstractSampledProbe; import se.l4.vibe.probes.Probe; import se.l4.vibe.probes.SampledProbe; /** * Implementation of {@link Events}. * * @author Andreas Holstenson * * @param <T> */ public class EventsImpl<T> implements Events<T> { private static final EventListener[] EMPTY = new EventListener[0]; private final EventSeverity severity; private final Lock listenerLock; protected volatile EventListener<T>[] listeners; private final AtomicLong totalEvents; public EventsImpl(EventSeverity severity) { this.severity = severity; listenerLock = new ReentrantLock(); listeners = EMPTY; totalEvents = new AtomicLong(); } public void register(T event) { register(severity, event); } public void register(EventSeverity severity, T event) { EventListener<T>[] listeners = this.listeners; for(EventListener<T> listener : listeners) { listener.eventRegistered(this, severity, event); } totalEvents.incrementAndGet(); } @Override public EventSeverity getDefaultSeverity() { return severity; } @Override public void addListener(EventListener<T> listener) { listenerLock.lock(); try { EventListener<T>[] listeners = this.listeners; EventListener<T>[] newListeners = new EventListener[listeners.length + 1]; System.arraycopy(listeners, 0, newListeners, 0, listeners.length); newListeners[listeners.length] = listener; this.listeners = newListeners; } finally { listenerLock.unlock(); } } @Override public void removeListener(EventListener<T> listener) { listenerLock.lock(); try { EventListener<T>[] listeners = this.listeners; int index = -1; for(int i=0, n=listeners.length; i<n; i++) { if(listeners[i] == listener) { index = i; break; } } if(index == -1) { // No such listener, just return return; } EventListener<T>[] newListeners = new EventListener[listeners.length - 1]; System.arraycopy(listeners, 0, newListeners, 0, index); if(index < listeners.length - 1) { System.arraycopy(listeners, index + 1, newListeners, index, listeners.length- index - 1); } this.listeners = newListeners; } finally { listenerLock.unlock(); } } @Override public Probe<Long> getTotalEventsProbe() { return new Probe<Long>() { @Override public Long read() { return totalEvents.longValue(); } }; } @Override public SampledProbe<Long> getEventsProbe() { return new AbstractSampledProbe<Long>() { private long lastValue; @Override public Long peek() { return totalEvents.longValue() - lastValue; } @Override protected Long sample0() { long current = totalEvents.longValue(); long sinceLastSample = current - lastValue; lastValue = current; return sinceLastSample; } }; } }