package org.infinispan.jcache.remote; import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import javax.cache.Cache; import javax.cache.event.CacheEntryListenerException; import org.infinispan.client.hotrod.RemoteCache; import org.infinispan.commons.logging.LogFactory; import org.infinispan.jcache.AbstractJCacheNotifier; import org.infinispan.jcache.remote.logging.Log; public class RemoteCacheWithSyncListeners<K, V> extends RemoteCacheWrapper<K, V> { private static final boolean DONT_EXPECT_EVENT_ON_NULL_RESULT = false; private static final Log log = LogFactory.getLog(RemoteCacheWithSyncListeners.class, Log.class); private final AbstractJCacheNotifier<K, V> notifier; private final Cache<K, V> cache; private final int timeout; public RemoteCacheWithSyncListeners(RemoteCache<K, V> delegate, AbstractJCacheNotifier<K, V> notifier, Cache<K, V> cache) { super(delegate); this.notifier = notifier; this.cache = cache; this.timeout = delegate.getRemoteCacheManager().getConfiguration().socketTimeout(); } @Override public V put(final K key, final V value) { return withSyncListeners(notifier.hasSyncCreatedListener(), key, value, new Callable<V>() { @Override public V call() throws Exception { return delegate.put(key, value); } }); } @Override public V putIfAbsent(final K key, final V value) { return withSyncListeners(notifier.hasSyncCreatedListener(), key, value, new Callable<V>() { @Override public V call() throws Exception { return delegate.putIfAbsent(key, value); } }); } public V remove(final Object key) { return withSyncListeners(notifier.hasSyncRemovedListener(), DONT_EXPECT_EVENT_ON_NULL_RESULT, (K) key, null, new Callable<V>() { @Override public V call() throws Exception { return delegate.remove(key); } }); } @Override public V replace(final K key, final V value) { return withSyncListeners(notifier.hasSyncUpdatedListener(), key, value, new Callable<V>() { @Override public V call() throws Exception { return delegate.replace(key, value); } }); } @Override public boolean replaceWithVersion(final K key, final V newValue, final long version) { return withSyncListeners(notifier.hasSyncUpdatedListener(), key, newValue, new Callable<Boolean>() { @Override public Boolean call() throws Exception { return delegate.replaceWithVersion(key, newValue, version); } }); } private <R> R withSyncListeners(boolean hasListeners, K key, V value, Callable<R> callable) { return withSyncListeners(hasListeners, true, key, value, callable); } private <R> R withSyncListeners(boolean hasListeners, boolean expectEventOnNull, K key, V value, Callable<R> callable) { try { if (!hasListeners) { return callable.call(); } CountDownLatch latch = new CountDownLatch(1); notifier.addSyncNotificationLatch(cache, key, value, latch); try { R ret = callable.call(); if ((ret == null) && !expectEventOnNull) { return ret; } boolean wasClosed = latch.await(timeout, TimeUnit.MILLISECONDS); if (!wasClosed) { log.timeoutWaitingEvent(); } return ret; } finally { notifier.removeSyncNotificationLatch(cache, key, value, latch); } } catch (CacheEntryListenerException ex) { throw ex; } catch (Exception e) { throw new CacheEntryListenerException(e); } } }