package org.infinispan.notifications.cachelistener;
import java.util.Iterator;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import org.infinispan.container.InternalEntryFactory;
import org.infinispan.container.entries.CacheEntry;
import org.infinispan.notifications.cachelistener.event.CacheEntryEvent;
import org.infinispan.notifications.cachelistener.event.Event;
import org.infinispan.notifications.impl.ListenerInvocation;
import org.infinispan.util.KeyValuePair;
/**
* This handler is to be used when all the events must be queued until the iteration process is complete.
* This is required for any local listener or non distributed caches. The local is required since we
* could have other events that are interrelated such as tx start/stop that all must be queued together in
* the order they were provided.
*
* @author wburns
* @since 7.0
*/
class QueueingAllSegmentListener<K, V> extends BaseQueueingSegmentListener<K, V, Event<K, V>> {
protected final Queue<KeyValuePair<Event<K, V>, ListenerInvocation<Event<K, V>>>> queue =
new ConcurrentLinkedQueue<>();
protected final InternalEntryFactory entryFactory;
QueueingAllSegmentListener(InternalEntryFactory entryFactory) {
this.entryFactory = entryFactory;
}
@Override
public boolean handleEvent(EventWrapper<K, V, Event<K, V>> wrapper, ListenerInvocation<Event<K, V>> invocation) {
boolean queued = !completed.get();
if (queued) {
boolean continueQueueing = true;
Event<K, V> event = wrapper.getEvent();
if (event instanceof CacheEntryEvent) {
CacheEntryEvent<K, V> cacheEvent = (CacheEntryEvent<K, V>) event;
CacheEntry<K, V> cacheEntry = entryFactory.create(cacheEvent.getKey(), cacheEvent.getValue(),
cacheEvent.getMetadata());
if (addEvent(wrapper.getKey(), cacheEntry.getValue() != null ? cacheEntry : REMOVED)) {
continueQueueing = false;
}
}
if (continueQueueing) {
KeyValuePair<Event<K, V>, ListenerInvocation<Event<K, V>>> eventPair =
new KeyValuePair<Event<K, V>, ListenerInvocation<Event<K, V>>>(event, invocation);
queue.add(eventPair);
// If it completed since we last added and ours is in the queue, we have to run the event
if (completed.get() && queue.remove(eventPair)) {
invocation.invoke(event);
}
}
}
return queued;
}
@Override
public void transferComplete() {
Iterator<KeyValuePair<Event<K, V>, ListenerInvocation<Event<K, V>>>> iterator = queue.iterator();
while (iterator.hasNext()) {
KeyValuePair<Event<K, V>, ListenerInvocation<Event<K, V>>> eventPair = iterator.next();
eventPair.getValue().invoke(eventPair.getKey());
iterator.remove();
}
completed.set(true);
}
}