1 package org.onap.vid.aai.util;
3 import com.google.common.cache.CacheBuilder;
4 import com.google.common.cache.CacheLoader;
5 import com.google.common.cache.LoadingCache;
6 import com.google.common.util.concurrent.UncheckedExecutionException;
7 import org.apache.commons.lang3.exception.ExceptionUtils;
8 import org.jetbrains.annotations.NotNull;
9 import org.onap.vid.properties.Features;
10 import org.springframework.beans.factory.annotation.Autowired;
11 import org.springframework.stereotype.Component;
12 import org.togglz.core.manager.FeatureManager;
14 import java.util.concurrent.ConcurrentHashMap;
15 import java.util.concurrent.ExecutorService;
16 import java.util.concurrent.Executors;
17 import java.util.concurrent.TimeUnit;
18 import java.util.function.Function;
20 import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
23 public class CacheProviderWithLoadingCache implements CacheProvider {
25 private final ExecutorService cacheReloadPool;
26 private final FeatureManager featureManager;
27 private final CacheConfigProvider cacheConfigProvider;
28 private final ConcurrentHashMap<String, Cache> caches;
32 public CacheProviderWithLoadingCache(FeatureManager featureManager, CacheConfigProvider cacheConfigProvider) {
33 this.featureManager = featureManager;
34 this.cacheConfigProvider = cacheConfigProvider;
35 this.cacheReloadPool = Executors.newFixedThreadPool(3);
36 this.caches = new ConcurrentHashMap<>();
40 Returns the cache associated with given name; creates one if wasn't any
43 public <K, V> Cache<K, V> aaiClientCacheFor(String name, Function<K, V> loader) {
44 return (Cache<K, V>) caches.computeIfAbsent(name, s -> buildAaiClientCacheFrom(loader, name));
48 public void resetCache(String name) {
53 Creates and returns a Cache that use provided `loader` to fetch values for
54 search keys, and stores the result for reuse over a certain time.
55 The cache will not use any stored key if FLAG_1810_AAI_LOCAL_CACHE is turned off.
56 In that case, `loader` will be invoked for any `get()` request from the cache. The
57 cache adheres the flag in real-time; so no restart is required.
59 protected <K, V> Cache<K, V> buildAaiClientCacheFrom(Function<K, V> loader, String name) {
60 final LoadingCache<K, V> activeCache = buildAaiClientActiveCacheFrom(loader, name);
62 // this works because Cache interface has only a single method: "get()"
63 // can be replaced with new anonimous class; e.g.:
64 // return new Cache() { ... }
66 if (featureManager.isActive(Features.FLAG_1810_AAI_LOCAL_CACHE) &&
67 defaultIfNull(cacheConfigProvider.getCacheConfig(name).isActive(), true)) {
69 return activeCache.getUnchecked(key);
71 catch (UncheckedExecutionException exception) {
72 return ExceptionUtils.rethrow(exception.getCause());
75 activeCache.invalidateAll();
76 activeCache.cleanUp();
77 return loader.apply(key);
82 private <K, V> LoadingCache<K, V> buildAaiClientActiveCacheFrom(Function<K, V> loader, String name) {
83 return createCacheBuilder(name).build(createAsyncReloadingCacheLoaderFrom(loader));
88 protected CacheBuilder<Object, Object> createCacheBuilder(String name) {
89 CacheConfig cacheConfig = cacheConfigProvider.getCacheConfig(name);
90 return CacheBuilder.newBuilder()
92 .expireAfterWrite(cacheConfig.getExpireAfterWriteHours(), TimeUnit.HOURS)
93 .refreshAfterWrite(cacheConfig.getRefreshAfterWriteSeconds(), TimeUnit.SECONDS);
96 private <K, V> CacheLoader<K, V> createAsyncReloadingCacheLoaderFrom(Function<K, V> loader) {
97 return CacheLoader.asyncReloading(CacheLoader.from(loader::apply), cacheReloadPool);