package org.radargun.service; import java.util.Arrays; import java.util.Collection; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.infinispan.notifications.Listener; import org.infinispan.notifications.cachelistener.annotation.CacheEntriesEvicted; import org.infinispan.notifications.cachelistener.annotation.CacheEntryCreated; import org.infinispan.notifications.cachelistener.annotation.CacheEntryModified; import org.infinispan.notifications.cachelistener.annotation.CacheEntryRemoved; import org.infinispan.notifications.cachelistener.event.CacheEntriesEvictedEvent; import org.infinispan.notifications.cachelistener.event.CacheEntryCreatedEvent; import org.infinispan.notifications.cachelistener.event.CacheEntryModifiedEvent; import org.infinispan.notifications.cachelistener.event.CacheEntryRemovedEvent; import org.infinispan.notifications.cachemanagerlistener.annotation.CacheStarted; import org.infinispan.notifications.cachemanagerlistener.annotation.CacheStopped; import org.infinispan.notifications.cachemanagerlistener.event.CacheStartedEvent; import org.infinispan.notifications.cachemanagerlistener.event.CacheStoppedEvent; import org.radargun.logging.Log; import org.radargun.logging.LogFactory; /** * Generic listener is registered only once for each cache, then it multiplexes the events to the * RadarGun listeners. The listener registration is not expected to survive cache manager restarts. * * @author Radim Vansa <rvansa@redhat.com> */ public class InfinispanCacheListeners extends AbstractInfinispanListeners { protected static final Log log = LogFactory.getLog(InfinispanCacheListeners.class); protected final ConcurrentMap<String, GenericCacheListener> syncListeners = new ConcurrentHashMap<String, GenericCacheListener>(); protected final ConcurrentMap<String, GenericCacheListener> asyncListeners = new ConcurrentHashMap<String, GenericCacheListener>(); protected final Infinispan60EmbeddedService service; private InfinispanCacheListeners.CacheManagerListener cacheManagerListener = new CacheManagerListener(); public InfinispanCacheListeners(Infinispan60EmbeddedService service) { this.service = service; } @Override protected GenericCacheListener getOrCreateListener(String cacheName, boolean sync) { if (cacheName == null) { cacheName = service.getCache(null).getName(); } GenericCacheListener generic = sync ? syncListeners.get(cacheName) : asyncListeners.get(cacheName); if (generic == null) { // make sure the cacheManagerListener is registered log.trace("Adding cache manager listener"); service.cacheManager.addListener(cacheManagerListener); if (sync) { generic = new SyncCacheListener(); syncListeners.put(cacheName, generic); } else { generic = new AsyncCacheListener(); asyncListeners.put(cacheName, generic); } service.getCache(cacheName).getAdvancedCache().addListener(generic); } return generic; } @Override protected GenericCacheListener getListenerOrThrow(String cacheName, boolean sync) { if (cacheName == null) { cacheName = service.getCache(null).getName(); } GenericCacheListener generic; if (sync) generic = syncListeners.get(cacheName); else generic = asyncListeners.get(cacheName); if (generic == null) throw new IllegalArgumentException("No listener was registered on cache " + cacheName); return generic; } @Override public Collection<Type> getSupportedListeners() { return Arrays.asList(Type.CREATED, Type.UPDATED, Type.REMOVED, Type.EVICTED); } @Override public void addExpiredListener(String cacheName, ExpiredListener listener, boolean sync) { throw new UnsupportedOperationException(); } @Override public void removeExpiredListener(String cacheName, ExpiredListener listener, boolean sync) { throw new UnsupportedOperationException(); } @Override public void removeListener(String cacheName, boolean sync) { GenericCacheListener listener = getListenerOrThrow(cacheName, sync); if (listener.isEmpty()) service.getCache(cacheName).getAdvancedCache().removeListener(listener); } protected abstract static class GenericCacheListener extends AbstractInfinispanListeners.GenericListener { @CacheEntryCreated public void created(CacheEntryCreatedEvent e) { if (e.isPre()) return; for (CreatedListener listener : created) { try { listener.created(e.getKey(), e.getValue()); } catch (Throwable t) { log.error("Listener " + listener + " has thrown an exception", t); } } } @CacheEntryModified public void updated(CacheEntryModifiedEvent e) { if (e.isPre()) return; for (UpdatedListener listener : updated) { try { listener.updated(e.getKey(), e.getValue()); } catch (Throwable t) { log.error("Listener " + listener + " has thrown an exception", t); } } } @CacheEntryRemoved public void updated(CacheEntryRemovedEvent e) { if (e.isPre()) return; for (RemovedListener listener : removed) { try { listener.removed(e.getKey(), e.getOldValue()); } catch (Throwable t) { log.error("Listener " + listener + " has thrown an exception", t); } } } @CacheEntriesEvicted public void evicted(CacheEntriesEvictedEvent e) { if (e.isPre()) return; for (EvictedListener listener : evicted) { for (Map.Entry entry : ((Map<?, ?>) e.getEntries()).entrySet()) { try { listener.evicted(entry.getKey(), entry.getValue()); } catch (Throwable t) { log.error("Listener " + listener + " has thrown an exception", t); } } } } public abstract boolean sync(); } @Listener(clustered = true, sync = true) protected static class SyncCacheListener extends GenericCacheListener { @Override public boolean sync() { return true; } } @Listener(clustered = true, sync = false) protected static class AsyncCacheListener extends GenericCacheListener { @Override public boolean sync() { return false; } } @Listener private class CacheManagerListener { @CacheStarted public void cacheStarted(CacheStartedEvent e) { log.trace("Cache " + e.getCacheName() + " has started"); } @CacheStopped public void cacheStopped(CacheStoppedEvent e) { log.trace("Cache " + e.getCacheName() + " has stopped"); syncListeners.remove(e.getCacheName()); asyncListeners.remove(e.getCacheName()); } } }