
commons.box.app.DataLoadingCache Maven / Gradle / Ivy
Show all versions of commons-box-app Show documentation
package commons.box.app;
import com.google.common.cache.*;
import javax.annotation.Nonnull;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
/**
* 数据map 通过定义loader来实现值得载入机制
*
* 如果定义了max(值大于0时),此类将按需清除部分记录
*
* @author xingxiuyi
* 创建于 14/12/14
* 版权所有 xingxiuyi
*/
public final class DataLoadingCache {
private final LoadingCache> cache;
public static DataLoadingCache build() {
DataCache.Spec spec = new DataCache.Spec(-1);
return build(null, spec);
}
public static DataLoadingCache build(DataLoader loader) {
DataCache.Spec spec = new DataCache.Spec(-1);
return build(loader, spec);
}
public static DataLoadingCache build(DataLoader loader, long max) {
DataCache.Spec spec = new DataCache.Spec(max);
return build(loader, spec);
}
public static DataLoadingCache build(DataLoader loader, long max, long expireAfterAccess, long expireAfterWrite) {
DataCache.Spec spec = new DataCache.Spec(max, expireAfterAccess, expireAfterWrite);
return build(loader, spec);
}
public static DataLoadingCache build(DataLoader loader, long max, long expireAfterAccess, long expireAfterWrite, int initCapacity) {
DataCache.Spec spec = new DataCache.Spec(max, expireAfterAccess, expireAfterWrite, initCapacity);
return build(loader, spec);
}
public static DataLoadingCache build(DataLoader loader, long max,
Consumer> removalCmd) {
DataCache.Spec spec = new DataCache.Spec(max);
return build(loader, spec, removalCmd);
}
public static DataLoadingCache build(DataLoader loader, long max, long expireAfterAccess, long expireAfterWrite,
Consumer> removalCmd) {
DataCache.Spec spec = new DataCache.Spec(max, expireAfterAccess, expireAfterWrite);
return build(loader, spec, removalCmd);
}
public static DataLoadingCache build(DataLoader loader, long max, long expireAfterAccess, long expireAfterWrite, int initCapacity,
Consumer> removalCmd) {
DataCache.Spec spec = new DataCache.Spec(max, expireAfterAccess, expireAfterWrite, initCapacity);
return build(loader, spec, removalCmd);
}
private static DataLoadingCache build(DataLoader loader, DataCache.Spec spec) {
return build(loader, spec, null);
}
@SuppressWarnings("unchecked")
private static DataLoadingCache build(DataLoader loader, DataCache.Spec spec, Consumer> removalCmd) {
CacheBuilder> cb = (CacheBuilder) CacheBuilder.newBuilder();
if (spec != null) {
if (spec.getMax() > 0) cb = cb.maximumSize(spec.getMax());
if (spec.getExpireAfterAccess() > 0) cb = cb.expireAfterAccess(spec.getExpireAfterAccess(), TimeUnit.MILLISECONDS);
if (spec.getExpireAfterWrite() > 0) cb = cb.expireAfterWrite(spec.getExpireAfterWrite(), TimeUnit.MILLISECONDS);
if (spec.getInitCapacity() > 0) cb = cb.initialCapacity(spec.getInitCapacity());
}
if (removalCmd != null) cb = cb.removalListener(new RemovalCmds<>(removalCmd));
return new DataLoadingCache(cb.build(new DataCacheLoader<>(loader)));
}
private DataLoadingCache(LoadingCache> cache) {
this.cache = cache;
}
public V get(K key) {
try {
DataEntry nv = this.cache.get(key);
if (nv != null) return nv.getValue();
} catch (Throwable e) {
throw new AppError("DataCache载入元素出错", e);
}
return null;
}
public V get(K key, DataLoader loader) {
if (loader == null) return this.get(key);
DataEntry nv = this.cache.getIfPresent(key);
if (nv == null) {
nv = new DataEntry<>(key, loader.load(key));
this.cache.put(key, nv);
}
return nv.getValue();
}
public V getIfPresent(K key) {
DataEntry nv = this.cache.getIfPresent(key);
if (nv != null) return nv.getValue();
else return null;
}
public Map getAll(Iterable extends K> keys) {
Map map = new HashMap<>();
try {
Map> all = this.cache.getAll(keys);
if (all != null) for (Map.Entry> me : all.entrySet()) {
if (me == null || me.getKey() == null || me.getValue() == null) continue;
map.put(me.getKey(), me.getValue().getValue());
}
} catch (Throwable e) {
throw new AppError("DataCache载入元素出错", e);
}
return map;
}
public void put(K key, V value) {
if (key == null) return;
this.cache.put(key, new DataEntry<>(key, value));
}
public void putAll(Map map) {
if (map == null) return;
for (Map.Entry me : map.entrySet()) if (me != null) this.put(me.getKey(), me.getValue());
}
public long size() {
return this.cache.size();
}
public void remove(K key) {
this.cache.invalidate(key);
}
public void clear() {
this.cache.cleanUp();
}
public Map asMap() {
Map map = new HashMap<>();
try {
Map> all = this.cache.asMap();
if (all != null) for (Map.Entry> me : all.entrySet()) {
if (me == null || me.getKey() == null || me.getValue() == null) continue;
map.put(me.getKey(), me.getValue().getValue());
}
} catch (Throwable e) {
throw AppError.error("DataCache载入元素出错", e);
}
return map;
}
private static class DataCacheLoader extends CacheLoader> {
private final DataLoader loader;
public DataCacheLoader(DataLoader loader) {
this.loader = (loader == null) ? new EmptyLoader() : loader;//保证loader不为空
}
@SuppressWarnings("NullableProblems")
@Override
public DataEntry load(K key) throws Exception {
return new DataEntry<>(key, this.loader.load(key));
}
}
private static class EmptyLoader implements DataLoader {
@Override
public V load(K key) {
return null;
}
}
private static class RemovalCmds implements RemovalListener> {
private final Consumer> cmd;
public RemovalCmds(Consumer> chain) {
this.cmd = chain;
}
@Override
public void onRemoval(@Nonnull RemovalNotification> notification) {
if (notification.getValue() == null) return;
if (this.cmd != null)
this.cmd.accept(new DataEntry<>(notification.getKey(), notification.getValue().getValue()));
}
}
}