package org.n3r.eql.cache;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import lombok.Value;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.n3r.eql.impl.EqlUniqueSqlId;
import org.n3r.eql.spec.ParamsAppliable;
import org.n3r.eql.spec.Spec;
import org.n3r.eql.spec.SpecParser;
import org.n3r.eql.util.KeyValue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import static com.google.common.base.MoreObjects.firstNonNull;
@Slf4j
public class EqlCacheSettings {
public static final String DEFAULT_GUAVA_CACHE_MODEL = "guava";
public static final String DEFAULT_DIAMOND_GUAVA_CACHE_MODEL = "diamond-guava";
private static Cache<EqlCacheModelKey, EqlCacheProvider> eqlCacheModels;
static {
eqlCacheModels = CacheBuilder.newBuilder().build();
}
public static EqlCacheProvider processCacheModel(
String sqlClassPath,
KeyValue cacheModelSetting) {
return processCacheModel(sqlClassPath, cacheModelSetting, true);
}
public static EqlCacheProvider processCacheModel(
String sqlClassPath,
KeyValue cacheModelSetting,
boolean addToCache) {
if (!cacheModelSetting.keyStartsWith("impl")) return null;
KeyValue implKeyValue = cacheModelSetting.removeKeyPrefix("impl");
String cacheModelName = implKeyValue.getKey();
String cacheModelImpl = implKeyValue.getValue();
Spec spec = SpecParser.parseSpecLeniently(cacheModelImpl);
try {
Class<?> clazz = Class.forName(spec.getName());
if (!EqlCacheProvider.class.isAssignableFrom(clazz)) {
log.error("processCacheModel {} required to implement " +
"org.n3r.eql.cache.EqlCacheProvider", spec.getName());
return null;
}
val impl = (EqlCacheProvider) clazz.newInstance();
if (impl instanceof ParamsAppliable)
((ParamsAppliable) impl).applyParams(spec.getParams());
if (addToCache)
eqlCacheModels.put(new EqlCacheModelKey(sqlClassPath, cacheModelName), impl);
return impl;
} catch (Exception e) {
log.error("processCacheModel error", e);
}
return null;
}
public static EqlCacheProvider getCacheProvider(
EqlUniqueSqlId uniqueSQLId, String cacheModel) {
val model = firstNonNull(cacheModel, EqlCacheSettings.DEFAULT_GUAVA_CACHE_MODEL);
val cacheModelKey = new EqlCacheModelKey(uniqueSQLId.getSqlClassPath(), model);
val provider = eqlCacheModels.getIfPresent(cacheModelKey);
if (provider != null) return provider;
if (DEFAULT_GUAVA_CACHE_MODEL.equals(model))
return createDefaultGuavaCacheModel(uniqueSQLId.getSqlClassPath(), cacheModelKey);
if (DEFAULT_DIAMOND_GUAVA_CACHE_MODEL.equals(model))
return createDefaultDiamondGuavaCacheModel(uniqueSQLId.getSqlClassPath(), cacheModelKey);
log.warn("unable to find cache provider by cache model {}", model);
return null;
}
private static EqlCacheProvider createDefaultGuavaCacheModel(
String sqlClassPath,
EqlCacheModelKey cacheModelKey) {
String settingKey = "impl." + DEFAULT_GUAVA_CACHE_MODEL;
String settingVal = "@org.n3r.eql.cache.GuavaCacheProvider(\"expireAfterWrite=1d\")";
KeyValue setting = new KeyValue(settingKey, settingVal);
return createCacheModel(sqlClassPath, cacheModelKey, setting);
}
private static EqlCacheProvider createDefaultDiamondGuavaCacheModel(
String sqlClassPath,
EqlCacheModelKey cacheModelKey) {
String settingKey = "impl." + DEFAULT_DIAMOND_GUAVA_CACHE_MODEL;
String settingVal = "@org.n3r.eql.cache.DiamondGuavaCacheProvider";
KeyValue setting = new KeyValue(settingKey, settingVal);
return createCacheModel(sqlClassPath, cacheModelKey, setting);
}
private static EqlCacheProvider createCacheModel(
final String sqlClassPath,
EqlCacheModelKey cacheModelKey,
final KeyValue setting) {
try {
return eqlCacheModels.get(cacheModelKey, new Callable<EqlCacheProvider>() {
@Override
public EqlCacheProvider call() throws Exception {
return processCacheModel(sqlClassPath, setting, false);
}
});
} catch (ExecutionException e) {
log.warn("create default cache model error", e.getCause());
}
return null;
}
@Value
static class EqlCacheModelKey {
private String sqlClassPath;
private String modelName;
}
}