org.infinispan.jcache.JCacheNotifier Maven / Gradle / Ivy
package org.infinispan.jcache;
import org.infinispan.AdvancedCache;
import org.infinispan.commons.util.CollectionFactory;
import org.infinispan.jcache.logging.Log;
import org.infinispan.util.logging.LogFactory;
import javax.cache.Cache;
import javax.cache.configuration.CacheEntryListenerConfiguration;
import javax.cache.configuration.Factory;
import javax.cache.event.CacheEntryCreatedListener;
import javax.cache.event.CacheEntryEvent;
import javax.cache.event.CacheEntryEventFilter;
import javax.cache.event.CacheEntryExpiredListener;
import javax.cache.event.CacheEntryListener;
import javax.cache.event.CacheEntryRemovedListener;
import javax.cache.event.CacheEntryUpdatedListener;
import javax.cache.event.EventType;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* JCache notifications dispatcher.
*
* TODO: Deal with asynchronous listeners...
*
* @author Galder Zamarreño
* @since 5.3
*/
public class JCacheNotifier {
private static final Log log =
LogFactory.getLog(JCacheNotifier.class, Log.class);
private static final boolean isTrace = log.isTraceEnabled();
// Traversals are a not more common than mutations when it comes to
// keeping track of registered listeners, so use copy-on-write lists.
private final List> createdListeners =
new CopyOnWriteArrayList>();
private final List> updatedListeners =
new CopyOnWriteArrayList>();
private final List> removedListeners =
new CopyOnWriteArrayList>();
private final List> expiredListeners =
new CopyOnWriteArrayList>();
private final ConcurrentMap, CacheEntryListenerConfiguration> listenerCfgs =
CollectionFactory.makeConcurrentMap();
private JCacheListenerAdapter listenerAdapter;
public void addListener(CacheEntryListenerConfiguration reg,
Cache jcache, JCacheNotifier notifier, AdvancedCache cache) {
boolean addListenerAdapter = listenerCfgs.isEmpty();
addListener(reg, false);
if (addListenerAdapter) {
listenerAdapter = new JCacheListenerAdapter(jcache, notifier);
cache.addListener(listenerAdapter);
}
}
public void removeListener(CacheEntryListenerConfiguration reg,
AdvancedCache cache) {
removeListener(reg);
if (listenerCfgs.isEmpty())
cache.removeListener(listenerAdapter);
}
public void notifyEntryCreated(Cache cache, K key, V value) {
if (!createdListeners.isEmpty()) {
List> events =
createEvent(cache, key, value, EventType.CREATED);
for (CacheEntryCreatedListener listener : createdListeners)
listener.onCreated(getEntryIterable(events, listenerCfgs.get(listener)));
}
}
public void notifyEntryUpdated(Cache cache, K key, V value) {
if (!updatedListeners.isEmpty()) {
List> events =
createEvent(cache, key, value, EventType.UPDATED);
for (CacheEntryUpdatedListener listener : updatedListeners)
listener.onUpdated(getEntryIterable(events, listenerCfgs.get(listener)));
}
}
public void notifyEntryRemoved(Cache cache, K key, V value) {
if (!removedListeners.isEmpty()) {
List> events =
createEvent(cache, key, value, EventType.REMOVED);
for (CacheEntryRemovedListener listener : removedListeners) {
listener.onRemoved(getEntryIterable(events, listenerCfgs.get(listener)));
}
}
}
public void notifyEntryExpired(Cache cache, K key, V value) {
if (!expiredListeners.isEmpty()) {
List> events =
createEvent(cache, key, value, EventType.EXPIRED);
for (CacheEntryExpiredListener listener : expiredListeners) {
listener.onExpired(getEntryIterable(events, listenerCfgs.get(listener)));
}
}
}
private Iterable> getEntryIterable(
List> events,
CacheEntryListenerConfiguration listenerCfg) {
Factory> factory = listenerCfg.getCacheEntryEventFilterFactory();
if (factory != null) {
CacheEntryEventFilter super K, ? super V> filter = factory.create();
return filter == null ? events
: new JCacheEventFilteringIterable(events, filter);
}
return events;
}
@SuppressWarnings("unchecked")
private boolean addListener(CacheEntryListenerConfiguration listenerCfg, boolean addIfAbsent) {
boolean added = false;
CacheEntryListener super K, ? super V> listener =
listenerCfg.getCacheEntryListenerFactory().create();
if (listener instanceof CacheEntryCreatedListener)
added = !containsListener(addIfAbsent, listener, createdListeners)
&& createdListeners.add((CacheEntryCreatedListener) listener);
if (listener instanceof CacheEntryUpdatedListener)
added = !containsListener(addIfAbsent, listener, updatedListeners)
&& updatedListeners.add((CacheEntryUpdatedListener) listener);
if (listener instanceof CacheEntryRemovedListener)
added = !containsListener(addIfAbsent, listener, removedListeners)
&& removedListeners.add((CacheEntryRemovedListener) listener);
if (listener instanceof CacheEntryExpiredListener)
added = !containsListener(addIfAbsent, listener, expiredListeners)
&& expiredListeners.add((CacheEntryExpiredListener) listener);
if (added)
listenerCfgs.put(listener, listenerCfg);
return added;
}
private boolean containsListener(boolean addIfAbsent,
CacheEntryListener super K, ? super V> listenerToAdd,
List extends CacheEntryListener super K, ? super V>> listeners) {
// If add only if no listener present, check the listeners collection
if (addIfAbsent) {
for (CacheEntryListener super K, ? super V> listener : listeners) {
if (listener.equals(listenerToAdd))
return true;
}
}
return false;
}
@SuppressWarnings("unchecked")
private void removeListener(CacheEntryListenerConfiguration listenerCfg) {
for (Map.Entry, CacheEntryListenerConfiguration> entry : listenerCfgs.entrySet()) {
CacheEntryListenerConfiguration cfg = entry.getValue();
if (cfg.equals(listenerCfg)) {
CacheEntryListener super K, ? super V> listener = entry.getKey();
if (listener instanceof CacheEntryCreatedListener)
createdListeners.remove(listener);
if (listener instanceof CacheEntryUpdatedListener)
updatedListeners.remove(listener);
if (listener instanceof CacheEntryRemovedListener)
removedListeners.remove(listener);
if (listener instanceof CacheEntryExpiredListener)
expiredListeners.remove(listener);
}
}
}
private List> createEvent(
Cache cache, K key, V value, EventType eventType) {
List> events =
Collections.>singletonList(
new RICacheEntryEvent(cache, key, value, eventType));
if (isTrace) log.tracef("Received event: %s", events);
return events;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy