Caffeine.java
Home
/
src /
main /
java /
br /
ufrgs /
inf /
prosoft /
cache /
Caffeine.java
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package br.ufrgs.inf.prosoft.cache;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
/**
*
* @author root
* @param <K>
* @param <V>
*/
public class Caffeine<K, V> implements Cache<K, V> {
private static final boolean CACHE_EVALUATE_PERFORMANCE = System.getenv("CACHE_EVENTS") == null || !System.getenv("CACHE_EVENTS").equals("false");
private static final boolean CACHE_REGISTER_SIZE = System.getenv("CACHE_REGISTER_SIZE") != null && System.getenv("CACHE_REGISTER_SIZE").equals("true");
private final com.github.benmanes.caffeine.cache.Cache<Optional<K>, Optional<V>> cache;
private final CachePerformance cachePerformance;
public Caffeine() {
this(new CachePerformance());
}
public Caffeine(long ttl) {
this(new CachePerformance(), ttl);
}
public Caffeine(String name) {
this(new CachePerformance(name));
}
public Caffeine(String name, long ttl) {
this(new CachePerformance(name), ttl);
}
public Caffeine(String name, Long ttl, long size) {
this(new CachePerformance(name), ttl, size);
}
public Caffeine(CachePerformance cachingPerformance) {
this.cachePerformance = cachingPerformance;
this.cache = com.github.benmanes.caffeine.cache.Caffeine.newBuilder()
.build();
}
public Caffeine(CachePerformance cachingPerformance, long ttl) {
this.cachePerformance = cachingPerformance;
this.cache = com.github.benmanes.caffeine.cache.Caffeine.newBuilder()
.expireAfterWrite(ttl, TimeUnit.MILLISECONDS)
.build();
}
public Caffeine(CachePerformance cachingPerformance, Long ttl, long size) {
this.cachePerformance = cachingPerformance;
if (ttl == null) {
this.cache = com.github.benmanes.caffeine.cache.Caffeine.newBuilder()
.maximumSize(size)
.build();
} else {
this.cache = com.github.benmanes.caffeine.cache.Caffeine.newBuilder()
.expireAfterWrite(ttl, TimeUnit.MILLISECONDS)
.maximumSize(size)
.build();
}
}
public CachePerformance getCachePerformance() {
return this.cachePerformance;
}
@Override
public void put(K key, V value, long timeToLive) {
put(key, value);
}
@Override
public void put(K key, V value) {
this.cache.put(Optional.ofNullable(key), Optional.ofNullable(value));
registerEvent(EventType.ADDITION, value);
}
@Override
public V get(K key) throws KeyNotFoundException {
Optional<V> get = this.cache.getIfPresent(Optional.ofNullable(key));
if (get == null) {
registerEvent(EventType.MISS, key);
throw new KeyNotFoundException();
}
registerEvent(EventType.HIT, get);
return get.orElse(null);
}
@Override
public void invalidate(K key) {
this.cache.invalidate(Optional.ofNullable(key));
registerEvent(EventType.INVALIDATION, null);
}
public boolean containsKey(K key) {
Optional<V> get = this.cache.getIfPresent(Optional.ofNullable(key));
return get != null;
}
public Set<Map.Entry<K, V>> entrySet() {
Set<Map.Entry<K, V>> entrySet = this.cache.asMap().entrySet().stream().collect(
Collectors.toMap(entry -> entry.getKey().orElse(null), entry -> entry.getValue().orElse(null)))
.entrySet();
if (CACHE_EVALUATE_PERFORMANCE) {
entrySet.forEach(entry -> {
registerEvent(EventType.HIT, entry.getValue());
});
}
return entrySet;
}
public void forEach(BiConsumer<K, V> consumer) {
entrySet().forEach(entry -> {
consumer.accept(entry.getKey(), entry.getValue());
});
}
public int size() {
return values().size();
}
public boolean isEmpty() {
return values().isEmpty();
}
private String getIdentifier(Object object) {
return object != null ? String.valueOf(object.hashCode()) : "null";
}
private void registerEvent(EventType eventType, Object object) {
if (!CACHE_EVALUATE_PERFORMANCE) {
return;
}
String identifier = getIdentifier(object);
if (CACHE_REGISTER_SIZE) {
this.cachePerformance.registerEvent(eventType, identifier, CachePerformance.calculateObjectSize(object));
} else {
this.cachePerformance.registerEvent(eventType, identifier);
}
if (eventType.equals(EventType.ADDITION)) {
this.cachePerformance.registerSize((int) this.cache.stats().loadCount());
}
}
public List<V> values() {
return this.cache.asMap().values().stream()
.map(value -> value.orElse(null))
.collect(Collectors.toList());
}
}