package org.n3r.eql.diamond;
import com.google.common.base.Optional;
import com.google.common.base.Throwables;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.LoadingCache;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.n3r.diamond.client.DiamondListenerAdapter;
import org.n3r.diamond.client.DiamondManager;
import org.n3r.diamond.client.DiamondStone;
import org.n3r.eql.base.EqlResourceLoader;
import org.n3r.eql.impl.AbstractEqlResourceLoader;
import org.n3r.eql.impl.EqlResourceLoaderHelper;
import org.n3r.eql.impl.EqlUniqueSqlId;
import org.n3r.eql.impl.FileEqlResourceLoader;
import org.n3r.eql.parser.EqlBlock;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import static org.n3r.eql.impl.EqlResourceLoaderHelper.updateBlockCache;
import static org.n3r.eql.impl.EqlResourceLoaderHelper.updateFileCache;
@Slf4j
public class DiamondEqlResourceLoader extends AbstractEqlResourceLoader {
static Cache<String, Optional<Map<String, EqlBlock>>> fileCache;
static LoadingCache<EqlUniqueSqlId, Optional<EqlBlock>> sqlCache;
static FileEqlResourceLoader fileLoader = new FileEqlResourceLoader();
static {
fileCache = CacheBuilder.newBuilder().build();
sqlCache = EqlResourceLoaderHelper.buildSqlCache(fileCache);
}
@Override
public EqlBlock loadEqlBlock(String sqlClassPath, String sqlId) {
load(this, sqlClassPath);
val key = new EqlUniqueSqlId(sqlClassPath, sqlId);
val blockOptional = sqlCache.getUnchecked(key);
if (blockOptional.isPresent()) return blockOptional.get();
val eqlBlock = fileLoader.loadEqlBlock(sqlClassPath, sqlId);
if (eqlBlock != null) return eqlBlock;
throw new RuntimeException("unable to find sql id " + sqlId);
}
@Override
public Map<String, EqlBlock> load(String classPath) {
return load(this, classPath);
}
@SneakyThrows
private Map<String, EqlBlock> load(
final EqlResourceLoader eqlResourceLoader,
final String sqlClassPath) {
val dataId = sqlClassPath.replaceAll("/", ".");
val valueLoader = new Callable<Optional<Map<String, EqlBlock>>>() {
@Override
public Optional<Map<String, EqlBlock>> call() throws Exception {
val manager = new DiamondManager("EQL", dataId);
manager.addDiamondListener(new DiamondListenerAdapter() {
@Override
public void accept(DiamondStone diamondStone) {
String eql = diamondStone.getContent();
updateBlockCache(eql, eqlResourceLoader, sqlClassPath, sqlCache, fileCache);
}
});
val sqlContent = manager.getDiamond();
if (sqlContent == null) {
log.warn("classpath sql {} not found", dataId);
return Optional.absent();
}
return Optional.of(updateFileCache(sqlContent,
eqlResourceLoader, sqlClassPath, eqlLazyLoad));
}
};
try {
return fileCache.get(sqlClassPath, valueLoader).orNull();
} catch (ExecutionException e) {
throw Throwables.getRootCause(e);
}
}
}