package org.ehcache.impl.store;
import org.ehcache.config.ResourceType;
import org.ehcache.core.config.store.StoreStatisticsConfiguration;
import org.ehcache.core.spi.store.Store;
import org.ehcache.impl.internal.statistics.StatsUtils;
import org.terracotta.statistics.MappedOperationStatistic;
import org.terracotta.statistics.OperationStatistic;
import org.terracotta.statistics.StatisticType;
import org.terracotta.statistics.StatisticsManager;
import org.terracotta.statistics.ZeroOperationStatistic;
import org.terracotta.statistics.observer.OperationObserver;
import java.io.Serializable;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Supplier;
import static org.terracotta.statistics.StatisticBuilder.operation;
public abstract class BaseStore<K, V> implements Store<K, V> {
protected final Class<K> keyType;
protected final Class<V> valueType;
protected final boolean operationStatisticsEnabled;
public BaseStore(Configuration<K, V> config) {
this(config.getKeyType(), config.getValueType(), config.isOperationStatisticsEnabled());
}
public BaseStore(Class<K> keyType, Class<V> valueType, boolean operationStatisticsEnabled) {
this.keyType = keyType;
this.valueType = valueType;
this.operationStatisticsEnabled = operationStatisticsEnabled;
}
protected void checkKey(K keyObject) {
if (!keyType.isInstance(Objects.requireNonNull((Object) keyObject))) {
throw new ClassCastException("Invalid key type, expected : " + keyType.getName() + " but was : " + keyObject.getClass().getName());
}
}
protected void checkValue(V valueObject) {
if (!valueType.isInstance(Objects.requireNonNull((Object) valueObject))) {
throw new ClassCastException("Invalid value type, expected : " + valueType.getName() + " but was : " + valueObject.getClass().getName());
}
}
protected <T extends Enum<T>> OperationObserver<T> createObserver(String name, Class<T> outcome, boolean canBeDisabled) {
if(!operationStatisticsEnabled && canBeDisabled) {
return ZeroOperationStatistic.get();
}
return operation(outcome).named(name).of(this).tag(getStatisticsTag()).build();
}
protected <T extends Serializable> void registerStatistic(String name, StatisticType type, Set<String> tags, Supplier<T> valueSupplier) {
StatisticsManager.createPassThroughStatistic(this, name, tags, type, valueSupplier);
}
protected abstract String getStatisticsTag();
protected static abstract class BaseStoreProvider implements Store.Provider {
protected <K, V, S extends Enum<S>, T extends Enum<T>> OperationStatistic<T> createTranslatedStatistic(BaseStore<K, V> store, String statisticName, Map<T, Set<S>> translation, String targetName) {
Class<S> outcomeType = getOutcomeType(translation);
if (StatsUtils.hasOperationStat(store, outcomeType, targetName)) {
int tierHeight = getResourceType().getTierHeight();
OperationStatistic<T> stat = new MappedOperationStatistic<>(store, translation, statisticName, tierHeight, targetName, store
.getStatisticsTag());
StatisticsManager.associate(stat).withParent(store);
return stat;
}
return ZeroOperationStatistic.get();
}
private static <S extends Enum<S>, T extends Enum<T>> Class<S> getOutcomeType(Map<T, Set<S>> translation) {
Map.Entry<T, Set<S>> first = translation.entrySet().iterator().next();
Class<S> outcomeType = first.getValue().iterator().next().getDeclaringClass();
return outcomeType;
}
protected abstract ResourceType<?> getResourceType();
}
}