package org.infinispan.scripting.impl;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.infinispan.Cache;
import org.infinispan.CacheCollection;
import org.infinispan.CacheSet;
import org.infinispan.cache.impl.AbstractDelegatingAdvancedCache;
import org.infinispan.commons.marshall.Marshaller;
import org.infinispan.commons.marshall.SerializeWith;
import org.infinispan.commons.util.InjectiveFunction;
import org.infinispan.commons.util.Immutables;
import org.infinispan.util.CacheCollectionMapper;
import org.infinispan.util.CacheSetMapper;
public final class DataTypedCache<K, V> extends AbstractDelegatingAdvancedCache<K, V> {
final DataTypedCacheManager dataTypedCacheManager;
private final Function<V, V> toDataType = this::toDataType;
public DataTypedCache(DataTypedCacheManager dataTypedCacheManager, Cache<K, V> cache) {
super(cache.getAdvancedCache());
this.dataTypedCacheManager = dataTypedCacheManager;
}
private <T> T fromDataType(Object obj) {
return (T) dataTypedCacheManager.dataType.transformer.fromDataType(obj, dataTypedCacheManager.marshaller);
}
private <T> T toDataType(Object obj) {
return (T) dataTypedCacheManager.dataType.transformer.toDataType(obj, dataTypedCacheManager.marshaller);
}
@Override
public void putForExternalRead(K key, V value) {
getDelegate().putForExternalRead(fromDataType(key), fromDataType(value));
}
@Override
public void putForExternalRead(K key, V value, long lifespan, TimeUnit unit) {
getDelegate().putForExternalRead(fromDataType(key), fromDataType(value), lifespan, unit);
}
@Override
public void putForExternalRead(K key, V value, long lifespan, TimeUnit lifespanUnit, long maxIdle, TimeUnit maxIdleUnit) {
getDelegate().putForExternalRead(fromDataType(key), fromDataType(value), lifespan, lifespanUnit, maxIdle, maxIdleUnit);
}
@Override
public void evict(K key) {
getDelegate().evict(fromDataType(key));
}
@Override
public boolean containsKey(Object key) {
return getDelegate().containsKey(fromDataType(key));
}
@Override
public boolean containsValue(Object value) {
return getDelegate().containsValue(fromDataType(value));
}
@Override
public V get(Object key) {
return toDataType(getDelegate().get(fromDataType(key)));
}
@Override
public CacheSet<K> keySet() {
return new CacheSetMapper<>(getDelegate().keySet(),
new ValueToTypedValueFunction<>(
dataTypedCacheManager.dataType, dataTypedCacheManager.marshaller));
}
@Override
public CacheCollection<V> values() {
return new CacheCollectionMapper<>(getDelegate().values(),
new ValueToTypedValueFunction<>(
dataTypedCacheManager.dataType, dataTypedCacheManager.marshaller));
}
@Override
public CacheSet<Entry<K, V>> entrySet() {
return new CacheSetMapper<>(getDelegate().entrySet(),
new EntryToTypedEntryFunction<>(
dataTypedCacheManager.dataType, dataTypedCacheManager.marshaller));
}
@Override
public V put(K key, V value) {
return toDataType(getDelegate().put(fromDataType(key), fromDataType(value)));
}
@Override
public V put(K key, V value, long lifespan, TimeUnit unit) {
return toDataType(getDelegate().put(
fromDataType(key), fromDataType(value), lifespan, unit));
}
@Override
public V putIfAbsent(K key, V value, long lifespan, TimeUnit unit) {
return toDataType(getDelegate().putIfAbsent(
fromDataType(key), fromDataType(value), lifespan, unit));
}
@Override
public void putAll(Map<? extends K, ? extends V> map, long lifespan, TimeUnit unit) {
Map<K, V> map2 = fromDataTypeMap(map);
getDelegate().putAll(map2, lifespan, unit);
}
public Map<K, V> fromDataTypeMap(Map<? extends K, ? extends V> map) {
Stream<Entry<K, V>> stream = map.entrySet().stream().map(
e -> Immutables.immutableEntry(
fromDataType(e.getKey()), fromDataType(e.getValue())));
return stream.collect(Collectors.toMap(Entry::getKey, Entry::getValue));
}
@Override
public V replace(K key, V value, long lifespan, TimeUnit unit) {
return toDataType(getDelegate().replace(
fromDataType(key), fromDataType(value), lifespan, unit));
}
@Override
public boolean replace(K key, V oldValue, V value, long lifespan, TimeUnit unit) {
return getDelegate().replace(fromDataType(key), fromDataType(oldValue),
fromDataType(value), lifespan, unit);
}
@Override
public V put(K key, V value, long lifespan, TimeUnit lifespanUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit) {
return toDataType(getDelegate().put(
fromDataType(key), fromDataType(value), lifespan, lifespanUnit,
maxIdleTime, maxIdleTimeUnit));
}
@Override
public V putIfAbsent(K key, V value, long lifespan, TimeUnit lifespanUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit) {
return toDataType(getDelegate().putIfAbsent(
fromDataType(key), fromDataType(value), lifespan, lifespanUnit,
maxIdleTime, maxIdleTimeUnit));
}
@Override
public void putAll(Map<? extends K, ? extends V> map, long lifespan, TimeUnit lifespanUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit) {
Map<K, V> map2 = fromDataTypeMap(map);
getDelegate().putAll(map2, lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit);
}
@Override
public V replace(K key, V value, long lifespan, TimeUnit lifespanUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit) {
return toDataType(getDelegate().replace(fromDataType(key), fromDataType(value),
lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit));
}
@Override
public boolean replace(K key, V oldValue, V value, long lifespan, TimeUnit lifespanUnit, long maxIdleTime, TimeUnit maxIdleTimeUnit) {
return getDelegate().replace(fromDataType(key), fromDataType(oldValue),
fromDataType(value), lifespan, lifespanUnit, maxIdleTime, maxIdleTimeUnit);
}
@Override
public V remove(Object key) {
return toDataType(getDelegate().remove(fromDataType(key)));
}
@Override
public void putAll(Map<? extends K, ? extends V> m) {
Map<K, V> map2 = fromDataTypeMap(m);
getDelegate().putAll(map2);
}
@Override
public CompletableFuture<V> putAsync(K key, V value) {
return getDelegate().putAsync(fromDataType(key), fromDataType(value))
.thenApply(toDataType);
}
@Override
public CompletableFuture<V> putAsync(K key, V value, long lifespan, TimeUnit unit) {
return getDelegate().putAsync(fromDataType(key), fromDataType(value), lifespan, unit)
.thenApply(toDataType);
}
@Override
public CompletableFuture<V> putAsync(K key, V value, long lifespan, TimeUnit lifespanUnit, long maxIdle, TimeUnit maxIdleUnit) {
return getDelegate().putAsync(fromDataType(key), fromDataType(value),
lifespan, lifespanUnit, maxIdle, maxIdleUnit)
.thenApply(toDataType);
}
@Override
public CompletableFuture<Void> putAllAsync(Map<? extends K, ? extends V> data) {
Map<K, V> map2 = fromDataTypeMap(data);
return getDelegate().putAllAsync(map2);
}
@Override
public CompletableFuture<Void> putAllAsync(Map<? extends K, ? extends V> data, long lifespan, TimeUnit unit) {
Map<K, V> map2 = fromDataTypeMap(data);
return getDelegate().putAllAsync(map2, lifespan, unit);
}
@Override
public CompletableFuture<Void> putAllAsync(Map<? extends K, ? extends V> data, long lifespan, TimeUnit lifespanUnit, long maxIdle, TimeUnit maxIdleUnit) {
Map<K, V> map2 = fromDataTypeMap(data);
return getDelegate().putAllAsync(map2, lifespan, lifespanUnit, maxIdle, maxIdleUnit);
}
@Override
public CompletableFuture<V> putIfAbsentAsync(K key, V value) {
return getDelegate().putIfAbsentAsync(fromDataType(key), fromDataType(value))
.thenApply(toDataType);
}
@Override
public CompletableFuture<V> putIfAbsentAsync(K key, V value, long lifespan, TimeUnit unit) {
return getDelegate().putIfAbsentAsync(fromDataType(key), fromDataType(value), lifespan, unit)
.thenApply(toDataType);
}
@Override
public CompletableFuture<V> putIfAbsentAsync(K key, V value, long lifespan, TimeUnit lifespanUnit, long maxIdle, TimeUnit maxIdleUnit) {
return getDelegate().putIfAbsentAsync(fromDataType(key), fromDataType(value),
lifespan, lifespanUnit, maxIdle, maxIdleUnit)
.thenApply(toDataType);
}
@Override
public CompletableFuture<V> removeAsync(Object key) {
return getDelegate().removeAsync(fromDataType(key))
.thenApply(toDataType);
}
@Override
public CompletableFuture<Boolean> removeAsync(Object key, Object value) {
return getDelegate().removeAsync(fromDataType(key), fromDataType(value));
}
@Override
public CompletableFuture<V> replaceAsync(K key, V value) {
return getDelegate().replaceAsync(fromDataType(key), fromDataType(value))
.thenApply(toDataType);
}
@Override
public CompletableFuture<V> replaceAsync(K key, V value, long lifespan, TimeUnit unit) {
return getDelegate().replaceAsync(fromDataType(key), fromDataType(value), lifespan, unit)
.thenApply(toDataType);
}
@Override
public CompletableFuture<V> replaceAsync(K key, V value, long lifespan, TimeUnit lifespanUnit, long maxIdle, TimeUnit maxIdleUnit) {
return getDelegate().replaceAsync(fromDataType(key), fromDataType(value),
lifespan, lifespanUnit, maxIdle, maxIdleUnit)
.thenApply(toDataType);
}
@Override
public CompletableFuture<Boolean> replaceAsync(K key, V oldValue, V newValue) {
return getDelegate().replaceAsync(fromDataType(key),
fromDataType(oldValue), fromDataType(newValue));
}
@Override
public CompletableFuture<Boolean> replaceAsync(K key, V oldValue, V newValue, long lifespan, TimeUnit unit) {
return getDelegate().replaceAsync(fromDataType(key),
fromDataType(oldValue), fromDataType(newValue), lifespan, unit);
}
@Override
public CompletableFuture<Boolean> replaceAsync(K key, V oldValue, V newValue, long lifespan, TimeUnit lifespanUnit, long maxIdle, TimeUnit maxIdleUnit) {
return getDelegate().replaceAsync(fromDataType(key),
fromDataType(oldValue), fromDataType(newValue),
lifespan, lifespanUnit, maxIdle, maxIdleUnit);
}
@Override
public CompletableFuture<V> getAsync(K key) {
return getDelegate().getAsync(fromDataType(key))
.thenApply(toDataType);
}
@Override
public V putIfAbsent(K key, V value) {
return toDataType(getDelegate().putIfAbsent(fromDataType(key), fromDataType(value)));
}
@Override
public boolean remove(Object key, Object value) {
return getDelegate().remove(fromDataType(key), fromDataType(value));
}
@Override
public boolean replace(K key, V oldValue, V newValue) {
return getDelegate().replace(fromDataType(key), fromDataType(oldValue), fromDataType(newValue));
}
@Override
public V replace(K key, V value) {
return getDelegate().replace(fromDataType(key), fromDataType(value));
}
@SerializeWith(ValueToTypedValueFunction.Externalizer.class)
public static final class ValueToTypedValueFunction<T> implements Function<T, T>, InjectiveFunction<T, T> {
private final DataType dataType;
private final Optional<Marshaller> marshaller;
public ValueToTypedValueFunction(DataType dataType, Optional<Marshaller> marshaller) {
this.dataType = dataType;
this.marshaller = marshaller;
}
@Override
public Object apply(Object o) {
return dataType.transformer.toDataType(o, marshaller);
}
public static class Externalizer implements org.infinispan.commons.marshall.Externalizer<ValueToTypedValueFunction> {
@Override
public void writeObject(ObjectOutput output, ValueToTypedValueFunction object) throws IOException {
output.writeInt(object.dataType.ordinal());
}
@Override
public ValueToTypedValueFunction readObject(ObjectInput input) throws IOException {
int ordinal = input.readInt();
return new ValueToTypedValueFunction(DataType.values()[ordinal], Optional.empty());
}
}
}
@SerializeWith(EntryToTypedEntryFunction.Externalizer.class)
public static final class EntryToTypedEntryFunction<K, V>
implements Function<Entry<K, V>, Entry<K, V>>, InjectiveFunction<Entry<K, V>, Entry<K, V>> {
private final DataType dataType;
private final Optional<Marshaller> marshaller;
public EntryToTypedEntryFunction(DataType dataType, Optional<Marshaller> marshaller) {
this.dataType = dataType;
this.marshaller = marshaller;
}
@Override
public Entry<K, V> apply(Entry<K, V> e) {
return Immutables.immutableEntry(
(K) dataType.transformer.toDataType(e.getKey(), marshaller),
(V) dataType.transformer.toDataType(e.getValue(), marshaller));
}
public static class Externalizer implements org.infinispan.commons.marshall.Externalizer<EntryToTypedEntryFunction> {
@Override
public void writeObject(ObjectOutput output, EntryToTypedEntryFunction object) throws IOException {
output.writeInt(object.dataType.ordinal());
}
@Override
public EntryToTypedEntryFunction readObject(ObjectInput input) throws IOException {
int ordinal = input.readInt();
return new EntryToTypedEntryFunction(DataType.values()[ordinal], Optional.empty());
}
}
}
}