package org.radargun.service;
import java.io.IOException;
import java.io.Serializable;
import java.util.Iterator;
import java.util.Map;
import org.infinispan.AdvancedCache;
import org.infinispan.commons.logging.Log;
import org.infinispan.commons.logging.LogFactory;
import org.infinispan.commons.util.CloseableIterable;
import org.infinispan.container.entries.CacheEntry;
import org.infinispan.filter.KeyValueFilter;
import org.infinispan.iteration.EntryIterable;
import org.infinispan.metadata.Metadata;
import org.radargun.filters.AllFilter;
import org.radargun.traits.Iterable;
/**
* Implements iteration through all entries in cache.
*
* @author Radim Vansa <rvansa@redhat.com>
*/
public class InfinispanIterable implements Iterable {
protected static final Log log = LogFactory.getLog(Iterable.class);
protected static final boolean trace = log.isTraceEnabled();
protected final InfinispanEmbeddedService service;
public InfinispanIterable(InfinispanEmbeddedService service) {
this.service = service;
}
@Override
public <K, V> CloseableIterator<Map.Entry<K, V>> getIterator(String cacheName, Filter<K, V> filter) {
if (trace) log.tracef("Retrieving iterator for cache %s using filter %s", cacheName, filter);
AdvancedCache<K, V> cache = (AdvancedCache<K, V>) service.getCache(cacheName).getAdvancedCache();
EntryIterable<K, V> iterable = cache.filterEntries(wrap(filter));
return new CloseableIteratorImpl(iterable, new EntryOutConverter<K, V>());
}
@Override
public <K, V, T> CloseableIterator<T> getIterator(String cacheName, Filter<K, V> filter, Converter<K, V, T> converter) {
if (trace)
log.tracef("Retrieving iterator for cache %s using filter %s and converter %s", cacheName, filter, converter);
AdvancedCache<K, V> cache = (AdvancedCache<K, V>) service.getCache(cacheName).getAdvancedCache();
EntryIterable<K, V> iterable = cache.filterEntries(wrap(filter));
return new CloseableIteratorImpl(iterable.converter(wrap(converter)), new ValueOutConverter<K, T>());
}
protected <K, V, T> org.infinispan.filter.Converter<K, V, T> wrap(Converter<K, V, T> converter) {
return new ConverterWrapper<>(converter);
}
protected <K, V> KeyValueFilter<K, V> wrap(Filter<K, V> filter) {
if (filter == null) {
return AllFilter.INSTANCE;
} else {
return new KeyValueFilterWrapper<K, V>(filter);
}
}
/**
* Adapts RadarGun filter to Infinispan filter
*/
private static class KeyValueFilterWrapper<K, V> implements KeyValueFilter<K, V>, Serializable {
private final Filter<K, V> filter;
private KeyValueFilterWrapper(Filter<K, V> filter) {
this.filter = filter;
}
@Override
public boolean accept(K key, V value, Metadata metadata) {
return filter.accept(key, value);
}
}
/**
* Adapts RadarGun converter to Infinispan converter
*/
private static class ConverterWrapper<K, V, T> implements org.infinispan.filter.Converter<K, V, T>, Serializable {
private final Converter<K, V, T> converter;
public ConverterWrapper(Converter<K, V, T> converter) {
this.converter = converter;
}
@Override
public T convert(K key, V value, Metadata metadata) {
return converter.convert(key, value);
}
}
/**
* Adapts Infinispan iteration output to RadarGun iteration output
*/
private interface OutConverter<K, V, T> {
T convert(CacheEntry<K, V> entry);
}
private static class EntryOutConverter<K, V> implements OutConverter<K, V, Map.Entry<K, V>> {
@Override
public Map.Entry<K, V> convert(CacheEntry<K, V> entry) {
return entry;
}
}
private static class ValueOutConverter<K, T> implements OutConverter<K, T, T> {
@Override
public T convert(CacheEntry<K, T> entry) {
return entry.getValue();
}
}
/**
* Implements the iterator
*/
private static class CloseableIteratorImpl<K, V, T> implements CloseableIterator<T> {
private final CloseableIterable<CacheEntry<K, V>> iterable;
private final Iterator<CacheEntry<K, V>> iterator;
private final OutConverter<K, V, T> outConverter;
public CloseableIteratorImpl(CloseableIterable<CacheEntry<K, V>> iterable, OutConverter<K, V, T> outConverter) {
this.iterable = iterable;
this.outConverter = outConverter;
this.iterator = iterable.iterator();
}
@Override
public void close() throws IOException {
iterable.close();
}
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public T next() {
return outConverter.convert(iterator.next());
}
@Override
public void remove() {
iterator.remove();
}
}
}