org.infinispan.cache.impl.EncoderCache Maven / Gradle / Ivy
package org.infinispan.cache.impl;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.security.auth.Subject;
import org.infinispan.AdvancedCache;
import org.infinispan.Cache;
import org.infinispan.CacheCollection;
import org.infinispan.CacheSet;
import org.infinispan.CacheStream;
import org.infinispan.commands.read.AbstractCloseableIteratorCollection;
import org.infinispan.commons.dataconversion.Encoder;
import org.infinispan.commons.dataconversion.Wrapper;
import org.infinispan.commons.util.CloseableIterator;
import org.infinispan.commons.util.CloseableIteratorMapper;
import org.infinispan.commons.util.CloseableSpliterator;
import org.infinispan.commons.util.CloseableSpliteratorMapper;
import org.infinispan.compat.BiFunctionMapper;
import org.infinispan.compat.FunctionMapper;
import org.infinispan.container.InternalEntryFactory;
import org.infinispan.container.entries.CacheEntry;
import org.infinispan.container.entries.ForwardingCacheEntry;
import org.infinispan.container.entries.InternalCacheEntry;
import org.infinispan.context.Flag;
import org.infinispan.encoding.DataConversion;
import org.infinispan.factories.ComponentRegistry;
import org.infinispan.factories.annotations.Inject;
import org.infinispan.lifecycle.ComponentStatus;
import org.infinispan.metadata.Metadata;
import org.infinispan.notifications.cachelistener.ListenerHolder;
import org.infinispan.notifications.cachelistener.filter.CacheEventConverter;
import org.infinispan.notifications.cachelistener.filter.CacheEventFilter;
import org.infinispan.util.AbstractDelegatingCacheStream;
import org.infinispan.util.logging.Log;
import org.infinispan.util.logging.LogFactory;
/**
* Cache decoration that makes use of the {@link Encoder} and {@link Wrapper} to convert between storage value and
* read/write value.
*
* @since 9.1
*/
public class EncoderCache extends AbstractDelegatingAdvancedCache {
private static Log log = LogFactory.getLog(EncoderCache.class);
private final DataConversion keyDataConversion;
private final DataConversion valueDataConversion;
private InternalEntryFactory entryFactory;
private ComponentRegistry componentRegistry;
private final Function decodedValueForRead = this::valueFromStorage;
public EncoderCache(AdvancedCache cache, DataConversion keyDataConversion, DataConversion valueDataConversion) {
super(cache, c -> new EncoderCache<>(c, keyDataConversion, valueDataConversion));
this.keyDataConversion = keyDataConversion;
this.valueDataConversion = valueDataConversion;
}
private Set> encodeKeysForWrite(Set> keys) {
if (needsEncoding(keys)) {
return keys.stream().map(this::keyToStorage).collect(Collectors.toCollection(LinkedHashSet::new));
}
return keys;
}
private boolean needsEncoding(Collection> keys) {
return keys.stream().anyMatch(k -> !k.equals(keyToStorage(k)));
}
private Collection extends K> encodeKeysForWrite(Collection extends K> keys) {
if (needsEncoding(keys)) {
return keys.stream().map(this::keyToStorage).collect(Collectors.toCollection(ArrayList::new));
}
return keys;
}
public K keyToStorage(Object key) {
return (K) keyDataConversion.toStorage(key);
}
public V valueToStorage(Object value) {
return (V) valueDataConversion.toStorage(value);
}
public K keyFromStorage(Object key) {
return (K) keyDataConversion.fromStorage(key);
}
public V valueFromStorage(Object value) {
return (V) valueDataConversion.fromStorage(value);
}
@Inject
public void wireRealCache(ComponentRegistry registry, InternalEntryFactory entryFactory) {
this.entryFactory = entryFactory;
this.componentRegistry = registry;
registry.wireDependencies(keyDataConversion);
registry.wireDependencies(valueDataConversion);
registry.wireDependencies(cache);
}
private Map encodeMapForWrite(Map extends K, ? extends V> map) {
Map newMap = new HashMap<>(map.size());
map.forEach((k, v) -> newMap.put(keyToStorage(k), valueToStorage(v)));
return newMap;
}
private Map decodeMapForRead(Map extends K, ? extends V> map) {
Map newMap = new LinkedHashMap<>(map.size());
map.forEach((k, v) -> newMap.put(keyFromStorage(k), valueFromStorage(v)));
return newMap;
}
private CacheEntry convertEntry(K newKey, V newValue, CacheEntry entry) {
if (entry instanceof InternalCacheEntry) {
return entryFactory.create(newKey, newValue, (InternalCacheEntry) entry);
} else {
return entryFactory.create(newKey, newValue, entry.getMetadata().version(), entry.getCreated(),
entry.getLifespan(), entry.getLastUsed(), entry.getMaxIdle());
}
}
private BiFunction super K, ? super V, ? extends V> convertFunction(
BiFunction super K, ? super V, ? extends V> remappingFunction) {
return (k, v) -> valueToStorage(remappingFunction.apply(keyFromStorage(k), valueFromStorage(v)));
}
private Map> decodeEntryMapForRead(Map> map) {
Map> entryMap = new HashMap<>(map.size());
map.values().forEach(v -> {
K originalKey = v.getKey();
K unwrappedKey = keyFromStorage(originalKey);
V originalValue = v.getValue();
V unwrappedValue = valueFromStorage(originalValue);
CacheEntry entryToPut;
if (unwrappedKey != originalKey || unwrappedValue != originalValue) {
entryToPut = convertEntry(unwrappedKey, unwrappedValue, v);
} else {
entryToPut = v;
}
entryMap.put(unwrappedKey, entryToPut);
});
return entryMap;
}
private class EncodedCacheStream extends AbstractDelegatingCacheStream {
public EncodedCacheStream(CacheStream stream) {
super(stream);
}
@Override
public AbstractDelegatingCacheStream filterKeys(Set> keys) {
return super.filterKeys(encodeKeysForWrite(keys));
}
}
private class EncodedKeySet extends AbstractCloseableIteratorCollection implements CacheSet {
private final CacheSet actualCollection;
private final EncoderKeyMapper keyMapper = new EncoderKeyMapper(keyDataConversion);
EncodedKeySet(Cache cache, CacheSet actualCollection) {
super(cache);
this.actualCollection = actualCollection;
}
@Override
public CacheStream stream() {
return new EncodedCacheStream<>(actualCollection.stream().map(keyMapper));
}
@Override
public CacheStream parallelStream() {
return new EncodedCacheStream<>(actualCollection.parallelStream().map(keyMapper));
}
@Override
public CloseableIterator iterator() {
return new CloseableIteratorMapper<>(actualCollection.iterator(), EncoderCache.this::keyFromStorage);
}
@Override
public CloseableSpliterator spliterator() {
return new CloseableSpliteratorMapper<>(actualCollection.spliterator(), EncoderCache.this::keyFromStorage);
}
@Override
public boolean contains(Object o) {
return actualCollection.contains(keyToStorage(o));
}
@Override
public boolean remove(Object o) {
return actualCollection.remove(keyToStorage(o));
}
}
@Override
public void putForExternalRead(K key, V value) {
super.putForExternalRead(keyToStorage(key), valueToStorage(value));
}
@Override
public void putForExternalRead(K key, V value, long lifespan, TimeUnit unit) {
super.putForExternalRead(keyToStorage(key), valueToStorage(value), lifespan, unit);
}
@Override
public void putForExternalRead(K key, V value, long lifespan, TimeUnit lifespanUnit, long maxIdle, TimeUnit maxIdleUnit) {
super.putForExternalRead(key, value, lifespan, lifespanUnit, maxIdle, maxIdleUnit);
}
@Override
public void evict(K key) {
super.evict(keyToStorage(key));
}
@Override
public V put(K key, V value, long lifespan, TimeUnit unit) {
V ret = super.put(keyToStorage(key), valueToStorage(value), lifespan, unit);
return valueFromStorage(ret);
}
@Override
public DataConversion getKeyDataConversion() {
return keyDataConversion;
}
@Override
public DataConversion getValueDataConversion() {
return valueDataConversion;
}
@Override
protected void set(K key, V value) {
super.set(keyToStorage(key), valueToStorage(value));
}
@Override
public V putIfAbsent(K key, V value, long lifespan, TimeUnit unit) {
V v = super.putIfAbsent(keyToStorage(key), valueToStorage(value), lifespan, unit);
return valueFromStorage(v);
}
@Override
public void putAll(Map extends K, ? extends V> map, long lifespan, TimeUnit unit) {
super.putAll(encodeMapForWrite(map), lifespan, unit);
}
@Override
public V replace(K key, V value, long lifespan, TimeUnit unit) {
V ret = super.replace(keyToStorage(key), valueToStorage(value), lifespan, unit);
return valueFromStorage(ret);
}
@Override
public boolean replace(K key, V oldValue, V value, long lifespan, TimeUnit unit) {
return super.replace(keyToStorage(key), valueToStorage(oldValue), valueToStorage(value), lifespan, unit);
}
@Override
public V put(K key, V value, long lifespan, TimeUnit lifespanUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit) {
V ret = super.put(keyToStorage(key), valueToStorage(value), lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit);
return valueFromStorage(ret);
}
@Override
public V putIfAbsent(K key, V value, long lifespan, TimeUnit lifespanUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit) {
V ret = super.putIfAbsent(keyToStorage(key), valueToStorage(value), lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit);
return valueFromStorage(ret);
}
@Override
public void putAll(Map extends K, ? extends V> map, long lifespan, TimeUnit lifespanUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit) {
super.putAll(encodeMapForWrite(map), lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit);
}
@Override
public V replace(K key, V value, long lifespan, TimeUnit lifespanUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit) {
V ret = super.replace(keyToStorage(key), valueToStorage(value), lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit);
return valueFromStorage(ret);
}
@Override
public boolean replace(K key, V oldValue, V value, long lifespan, TimeUnit lifespanUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit) {
return super.replace(keyToStorage(key), valueToStorage(oldValue), valueToStorage(value), lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit);
}
@Override
public void replaceAll(BiFunction super K, ? super V, ? extends V> function) {
super.replaceAll(convertFunction(function));
}
@Override
public CompletableFuture putAsync(K key, V value) {
return super.putAsync(keyToStorage(key), valueToStorage(value)).thenApply(decodedValueForRead);
}
@Override
public CompletableFuture putAsync(K key, V value, long lifespan, TimeUnit unit) {
return super.putAsync(keyToStorage(key), valueToStorage(value), lifespan, unit).thenApply(decodedValueForRead);
}
@Override
public CompletableFuture putAsync(K key, V value, long lifespan, TimeUnit lifespanUnit, long maxIdle, TimeUnit maxIdleUnit) {
return super.putAsync(keyToStorage(key), valueToStorage(value), lifespan, lifespanUnit, maxIdle, maxIdleUnit).thenApply(decodedValueForRead);
}
@Override
public CompletableFuture putAllAsync(Map extends K, ? extends V> data) {
return super.putAllAsync(encodeMapForWrite(data));
}
@Override
public CompletableFuture putAllAsync(Map extends K, ? extends V> data, long lifespan, TimeUnit unit) {
return super.putAllAsync(encodeMapForWrite(data), lifespan, unit);
}
@Override
public CompletableFuture putAllAsync(Map extends K, ? extends V> data, long lifespan, TimeUnit lifespanUnit, long maxIdle, TimeUnit maxIdleUnit) {
return super.putAllAsync(encodeMapForWrite(data), lifespan, lifespanUnit, maxIdle, maxIdleUnit);
}
@Override
public CompletableFuture putIfAbsentAsync(K key, V value) {
return super.putIfAbsentAsync(keyToStorage(key), valueToStorage(value)).thenApply(decodedValueForRead);
}
@Override
public CompletableFuture putIfAbsentAsync(K key, V value, long lifespan, TimeUnit unit) {
return super.putIfAbsentAsync(keyToStorage(key), valueToStorage(value), lifespan, unit).thenApply(decodedValueForRead);
}
@Override
public boolean lock(K... keys) {
K[] encoded = (K[]) Arrays.stream(keys).map(this::keyToStorage).toArray();
return super.lock(encoded);
}
@Override
public boolean lock(Collection extends K> keys) {
return super.lock(encodeKeysForWrite(keys));
}
@Override
public CompletableFuture putIfAbsentAsync(K key, V value, long lifespan, TimeUnit lifespanUnit, long maxIdle, TimeUnit maxIdleUnit) {
return super.putIfAbsentAsync(keyToStorage(key), valueToStorage(value), lifespan, lifespanUnit, maxIdle, maxIdleUnit).thenApply(decodedValueForRead);
}
@Override
public CompletableFuture removeAsync(Object key) {
return super.removeAsync(keyToStorage(key)).thenApply(decodedValueForRead);
}
@Override
public CompletableFuture removeAsync(Object key, Object value) {
return super.removeAsync(keyToStorage(key), valueToStorage(value));
}
@Override
public CompletableFuture replaceAsync(K key, V value) {
return super.replaceAsync(keyToStorage(key), valueToStorage(value)).thenApply(decodedValueForRead);
}
@Override
public CompletableFuture replaceAsync(K key, V value, long lifespan, TimeUnit unit) {
return super.replaceAsync(keyToStorage(key), valueToStorage(value), lifespan, unit).thenApply(decodedValueForRead);
}
@Override
public Map getAll(Set> keys) {
Map ret = super.getAll(encodeKeysForWrite(keys));
return decodeMapForRead(ret);
}
@Override
public CacheEntry getCacheEntry(Object key) {
K keyToStorage = keyToStorage(key);
CacheEntry returned = super.getCacheEntry(keyToStorage);
if (returned != null) {
V originalValue = returned.getValue();
V valueFromStorage = valueFromStorage(originalValue);
if (keyToStorage != key || valueFromStorage != originalValue) {
return convertEntry((K) key, valueFromStorage, returned);
}
}
return returned;
}
@Override
public CompletableFuture replaceAsync(K key, V value, long lifespan, TimeUnit lifespanUnit, long maxIdle, TimeUnit maxIdleUnit) {
return super.replaceAsync(keyToStorage(key), valueToStorage(value), lifespan, lifespanUnit, maxIdle, maxIdleUnit)
.thenApply(decodedValueForRead);
}
@Override
public Map> getAllCacheEntries(Set> keys) {
Map> returned = super.getAllCacheEntries(encodeKeysForWrite(keys));
return decodeEntryMapForRead(returned);
}
@Override
public Map getGroup(String groupName) {
Map ret = super.getGroup(groupName);
return decodeMapForRead(ret);
}
@Override
public CompletableFuture replaceAsync(K key, V oldValue, V newValue) {
return super.replaceAsync(keyToStorage(key), valueToStorage(oldValue), valueToStorage(newValue));
}
@Override
public CompletableFuture replaceAsync(K key, V oldValue, V newValue, long lifespan, TimeUnit unit) {
return super.replaceAsync(keyToStorage(key), valueToStorage(oldValue), valueToStorage(newValue), lifespan, unit);
}
@Override
public V put(K key, V value, Metadata metadata) {
V ret = super.put(keyToStorage(key), valueToStorage(value), metadata);
return valueFromStorage(ret);
}
@Override
public V replace(K key, V value, Metadata metadata) {
V ret = super.replace(keyToStorage(key), valueToStorage(value), metadata);
return valueFromStorage(ret);
}
@Override
public CompletableFuture replaceAsync(K key, V oldValue, V newValue, long lifespan, TimeUnit lifespanUnit, long maxIdle, TimeUnit maxIdleUnit) {
return super.replaceAsync(keyToStorage(key), valueToStorage(oldValue), valueToStorage(newValue), lifespan, lifespanUnit, maxIdle, maxIdleUnit);
}
@Override
public boolean replace(K key, V oldValue, V value, Metadata metadata) {
return super.replace(keyToStorage(key), valueToStorage(oldValue), valueToStorage(value), metadata);
}
@Override
public V putIfAbsent(K key, V value, Metadata metadata) {
V ret = super.putIfAbsent(keyToStorage(key), valueToStorage(value), metadata);
return valueFromStorage(ret);
}
@Override
public CompletableFuture putAsync(K key, V value, Metadata metadata) {
return super.putAsync(keyToStorage(key), valueToStorage(value), metadata).thenApply(decodedValueForRead);
}
@Override
public void putForExternalRead(K key, V value, Metadata metadata) {
super.putForExternalRead(keyToStorage(key), valueToStorage(value), metadata);
}
@Override
public void putAll(Map extends K, ? extends V> map, Metadata metadata) {
super.putAll(encodeMapForWrite(map), metadata);
}
@Override
public CacheSet> cacheEntrySet() {
return new EncoderEntrySet(this, super.cacheEntrySet());
}
@Override
public void removeExpired(K key, V value, Long lifespan) {
super.removeExpired(keyToStorage(key), valueToStorage(value), lifespan);
}
@Override
public V putIfAbsent(K key, V value) {
V ret = super.putIfAbsent(keyToStorage(key), valueToStorage(value));
return valueFromStorage(ret);
}
private void lookupEncoderWrapper() {
ComponentStatus status = cache.getAdvancedCache().getComponentRegistry().getStatus();
if (!status.equals(ComponentStatus.STOPPING) && !status.equals(ComponentStatus.TERMINATED)) {
componentRegistry.wireDependencies(keyDataConversion);
componentRegistry.wireDependencies(valueDataConversion);
}
}
private void initState(EncoderCache encoderCache, EncoderCache template) {
encoderCache.entryFactory = template.entryFactory;
encoderCache.componentRegistry = template.componentRegistry;
encoderCache.lookupEncoderWrapper();
}
@Override
public AdvancedCache lockAs(Object lockOwner) {
AdvancedCache returned = super.lockAs(lockOwner);
if (returned != this && returned instanceof EncoderCache) {
initState((EncoderCache) returned, this);
}
return returned;
}
@Override
public AdvancedCache withEncoding(Class extends Encoder> keyEncoderClass, Class extends Encoder> valueEncoderClass) {
checkSubclass(keyEncoderClass, Encoder.class);
checkSubclass(valueEncoderClass, Encoder.class);
DataConversion newKeyDataConversion = keyDataConversion.withEncoding(keyEncoderClass);
DataConversion newValueDataConversion = valueDataConversion.withEncoding(valueEncoderClass);
EncoderCache encoderCache = new EncoderCache<>(cache, newKeyDataConversion, newValueDataConversion);
initState(encoderCache, this);
return encoderCache;
}
@Override
public AdvancedCache withEncoding(Class extends Encoder> encoderClass) {
checkSubclass(encoderClass, Encoder.class);
DataConversion newKeyDataConversion = keyDataConversion.withEncoding(encoderClass);
DataConversion newValueDataConversion = valueDataConversion.withEncoding(encoderClass);
EncoderCache encoderCache = new EncoderCache<>(cache, newKeyDataConversion, newValueDataConversion);
initState(encoderCache, this);
return encoderCache;
}
private void checkSubclass(Class> configured, Class> required) {
if (!required.isAssignableFrom(configured)) {
throw log.invalidEncodingClass(configured, required);
}
}
@Override
public AdvancedCache withWrapping(Class extends Wrapper> keyWrapperClass, Class extends Wrapper> valueWrapperClass) {
checkSubclass(keyWrapperClass, Wrapper.class);
checkSubclass(valueWrapperClass, Wrapper.class);
DataConversion newKeyDataConversion = keyDataConversion.withWrapping(keyWrapperClass);
DataConversion newValueDataConversion = valueDataConversion.withWrapping(valueWrapperClass);
EncoderCache encoderCache = new EncoderCache<>(cache, newKeyDataConversion, newValueDataConversion);
initState(encoderCache, this);
return encoderCache;
}
@Override
public AdvancedCache withWrapping(Class extends Wrapper> wrapper) {
return withWrapping(wrapper, wrapper);
}
@Override
public AdvancedCache withFlags(Flag... flags) {
AdvancedCache returned = super.withFlags(flags);
if (returned != this && returned instanceof EncoderCache) {
initState((EncoderCache) returned, this);
}
return returned;
}
@Override
public AdvancedCache withSubject(Subject subject) {
AdvancedCache returned = super.withSubject(subject);
if (returned != this && returned instanceof EncoderCache) {
initState((EncoderCache) returned, this);
}
return returned;
}
@Override
public AdvancedCache with(ClassLoader classLoader) {
AdvancedCache returned = super.with(classLoader);
if (returned != this && returned instanceof EncoderCache) {
initState((EncoderCache) returned, this);
}
return returned;
}
@Override
public boolean remove(Object key, Object value) {
return super.remove(keyToStorage(key), valueToStorage(value));
}
@Override
public boolean replace(K key, V oldValue, V newValue) {
return super.replace(keyToStorage(key), valueToStorage(oldValue), valueToStorage(newValue));
}
@Override
public V replace(K key, V value) {
V ret = super.replace(keyToStorage(key), valueToStorage(value));
return valueFromStorage(ret);
}
@Override
public boolean containsKey(Object key) {
return super.containsKey(keyToStorage(key));
}
@Override
public boolean containsValue(Object value) {
return super.containsValue(valueToStorage(value));
}
@Override
public V compute(K key, BiFunction super K, ? super V, ? extends V> remappingFunction) {
Object returned = super.compute(keyToStorage(key),
new BiFunctionMapper(remappingFunction, keyDataConversion, valueDataConversion));
return valueFromStorage(returned);
}
@Override
public V computeIfPresent(K key, BiFunction super K, ? super V, ? extends V> remappingFunction) {
Object returned = super.computeIfPresent(keyToStorage(key),
new BiFunctionMapper(remappingFunction, keyDataConversion, valueDataConversion));
return valueFromStorage(returned);
}
@Override
public V computeIfAbsent(K key, Function super K, ? extends V> mappingFunction) {
Object ret = super.computeIfAbsent(keyToStorage(key),
new FunctionMapper(mappingFunction, keyDataConversion, valueDataConversion));
return valueFromStorage(ret);
}
@Override
public V get(Object key) {
V v = super.get(keyToStorage(key));
return valueFromStorage(v);
}
@Override
public V getOrDefault(Object key, V defaultValue) {
V returned = super.getOrDefault(keyToStorage(key), defaultValue);
if (returned == defaultValue) {
return returned;
}
return valueFromStorage(returned);
}
@Override
public V put(K key, V value) {
V ret = super.put(keyToStorage(key), valueToStorage(value));
if (ret == null) {
return null;
}
return valueFromStorage(ret);
}
@Override
public V remove(Object key) {
V ret = super.remove(keyToStorage(key));
return valueFromStorage(ret);
}
@Override
public void putAll(Map extends K, ? extends V> t) {
super.putAll(encodeMapForWrite(t));
}
@Override
public V merge(K key, V value, BiFunction super V, ? super V, ? extends V> remappingFunction) {
Object returned = super.merge(keyToStorage(key), valueToStorage(value),
new BiFunctionMapper(remappingFunction, keyDataConversion, valueDataConversion));
return valueFromStorage(returned);
}
@Override
public void forEach(BiConsumer super K, ? super V> action) {
super.forEach((k, v) -> {
K newK = keyFromStorage(k);
V newV = valueFromStorage(v);
action.accept(newK, newV);
});
}
@Override
public CacheSet keySet() {
return new EncodedKeySet(this, super.keySet());
}
private class EncoderIterator implements CloseableIterator> {
private final CloseableIterator> iterator;
private final InternalEntryFactory entryFactory;
EncoderIterator(CloseableIterator> iterator, InternalEntryFactory entryFactory) {
this.iterator = iterator;
this.entryFactory = entryFactory;
}
@Override
public void close() {
iterator.close();
}
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public CacheEntry next() {
CacheEntry entry = iterator.next();
return new EntryWrapper<>(entry, convert(entry));
}
private CacheEntry convert(CacheEntry entry) {
A newKey = (A) keyFromStorage(entry.getKey());
B newValue = (B) valueFromStorage(entry.getValue());
// If either value changed then make a copy
if (newKey != entry.getKey() || newValue != entry.getValue()) {
if (entry instanceof InternalCacheEntry) {
return entryFactory.create(newKey, newValue, (InternalCacheEntry) entry);
}
return entryFactory.create(newKey, newValue, entry.getMetadata());
}
return entry;
}
@Override
public void remove() {
iterator.remove();
}
}
private class EncoderEntrySet extends AbstractCloseableIteratorCollection, K, V> implements CacheSet> {
private CacheSet> actualCollection;
private EncoderEntryMapper entryMapper;
EncoderEntrySet(Cache cache, CacheSet> actualCollection) {
super(cache);
this.entryMapper = new EncoderEntryMapper(keyDataConversion, valueDataConversion);
this.actualCollection = actualCollection;
}
@Override
public CacheStream> stream() {
return new EncodedCacheStream<>(actualCollection.stream().map(entryMapper));
}
@Override
public CacheStream> parallelStream() {
return new EncodedCacheStream<>(actualCollection.parallelStream().map(entryMapper));
}
@Override
public CloseableIterator> iterator() {
return new EncoderIterator<>(actualCollection.iterator(), entryFactory);
}
@Override
public CloseableSpliterator> spliterator() {
return new CloseableSpliteratorMapper<>(actualCollection.spliterator(),
entry -> {
K key = entry.getKey();
K keyFromStorage = keyFromStorage(key);
V value = entry.getValue();
V valueFromStorage = valueFromStorage(value);
if (keyFromStorage != key || valueFromStorage != value) {
return convertEntry(keyFromStorage, valueFromStorage, entry);
}
return entry;
});
}
@Override
public boolean contains(Object o) {
Map.Entry entry = toEntry(o);
if (entry != null) {
return actualCollection.contains(entry);
}
return false;
}
@Override
public boolean remove(Object o) {
Map.Entry entry = toEntry(o);
if (entry != null) {
return actualCollection.remove(entry);
}
return false;
}
Map.Entry toEntry(Object o) {
if (o instanceof Map.Entry) {
Map.Entry entry = (Map.Entry) o;
K key = entry.getKey();
K newKey = keyToStorage(key);
V value = entry.getValue();
V newValue = valueToStorage(value);
if (key != newKey || value != newValue) {
if (o instanceof CacheEntry) {
CacheEntry returned = (CacheEntry) o;
return convertEntry(newKey, newValue, returned);
} else {
return entryFactory.create(newKey, newValue, (Metadata) null);
}
}
return entry;
}
return null;
}
}
private class EntryWrapper extends ForwardingCacheEntry {
private final CacheEntry previousEntry;
private final CacheEntry entry;
EntryWrapper(CacheEntry previousEntry, CacheEntry entry) {
this.previousEntry = previousEntry;
this.entry = entry;
}
@Override
protected CacheEntry delegate() {
return entry;
}
@Override
public B setValue(B value) {
previousEntry.setValue((B) valueToStorage(value));
return super.setValue(value);
}
}
@Override
public CacheSet> entrySet() {
return cast(new EncoderEntrySet(this, cast(super.cacheEntrySet())));
}
private > CacheSet cast(CacheSet set) {
return (CacheSet) set;
}
private class EncoderValuesCollection extends AbstractCloseableIteratorCollection implements CacheCollection {
private final CacheCollection actualCollection;
final EncoderValueMapper valueMapper = new EncoderValueMapper(valueDataConversion);
EncoderValuesCollection(Cache cache, CacheCollection actualCollection) {
super(cache);
this.actualCollection = actualCollection;
}
@Override
public CacheStream stream() {
return new EncodedCacheStream<>(actualCollection.stream().map(valueMapper));
}
@Override
public CacheStream parallelStream() {
return new EncodedCacheStream<>(actualCollection.parallelStream().map(valueMapper));
}
@Override
public CloseableIterator iterator() {
return new CloseableIteratorMapper<>(actualCollection.iterator(), EncoderCache.this::valueFromStorage);
}
@Override
public CloseableSpliterator spliterator() {
return new CloseableSpliteratorMapper<>(actualCollection.spliterator(), EncoderCache.this::valueFromStorage);
}
@Override
public boolean contains(Object o) {
return actualCollection.contains(valueToStorage(o));
}
@Override
public boolean remove(Object o) {
return actualCollection.remove(valueToStorage(o));
}
}
@Override
public CacheCollection values() {
return new EncoderValuesCollection(this, super.values());
}
@Override
public CompletableFuture getAsync(K key) {
return super.getAsync(keyToStorage(key)).thenApply(decodedValueForRead);
}
@Override
public void addListener(Object listener) {
ListenerHolder listenerHolder = new ListenerHolder(listener, keyDataConversion, valueDataConversion);
Cache unwrapped = super.unwrapCache(this.cache);
if (unwrapped instanceof CacheImpl) {
((CacheImpl) unwrapped).addListener(listenerHolder);
} else {
super.addListener(listener);
}
}
@Override
public void addListener(Object listener, CacheEventFilter super K, ? super V> filter,
CacheEventConverter super K, ? super V, C> converter) {
ListenerHolder listenerHolder = new ListenerHolder(listener, keyDataConversion, valueDataConversion);
Cache unwrapped = super.unwrapCache(this.cache);
if (unwrapped instanceof CacheImpl) {
((CacheImpl) unwrapped).addListener(listenerHolder, filter, converter);
} else {
super.addListener(listener);
}
}
@Override
public void addFilteredListener(Object listener,
CacheEventFilter super K, ? super V> filter,
CacheEventConverter super K, ? super V, C> converter,
Set> filterAnnotations) {
ListenerHolder listenerHolder = new ListenerHolder(listener, keyDataConversion, valueDataConversion);
Cache unwrapped = super.unwrapCache(this.cache);
if (unwrapped instanceof CacheImpl) {
((CacheImpl) unwrapped).addFilteredListener(listenerHolder, filter, converter, filterAnnotations);
} else {
super.addFilteredListener(listener, filter, converter, filterAnnotations);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy