Merge from ECOMP's repository
[vid.git] / vid-app-common / src / main / java / org / onap / vid / aai / util / CacheProviderWithLoadingCache.java
1 package org.onap.vid.aai.util;
2
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;
13
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;
19
20 import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
21
22 @Component
23 public class CacheProviderWithLoadingCache implements CacheProvider {
24
25     private final ExecutorService cacheReloadPool;
26     private final FeatureManager featureManager;
27     private final CacheConfigProvider cacheConfigProvider;
28     private final ConcurrentHashMap<String, Cache> caches;
29
30
31     @Autowired
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<>();
37     }
38
39     /*
40     Returns the cache associated with given name; creates one if wasn't any
41      */
42     @Override
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));
45     }
46
47     @Override
48     public void resetCache(String name) {
49         caches.remove(name);
50     }
51
52     /*
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.
58      */
59     protected <K, V> Cache<K, V> buildAaiClientCacheFrom(Function<K, V> loader, String name) {
60         final LoadingCache<K, V> activeCache = buildAaiClientActiveCacheFrom(loader, name);
61
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() { ... }
65         return key -> {
66             if (featureManager.isActive(Features.FLAG_1810_AAI_LOCAL_CACHE) &&
67                     defaultIfNull(cacheConfigProvider.getCacheConfig(name).isActive(), true)) {
68                 try {
69                     return activeCache.getUnchecked(key);
70                 }
71                 catch (UncheckedExecutionException exception) {
72                     return ExceptionUtils.rethrow(exception.getCause());
73                 }
74             } else {
75                 activeCache.invalidateAll();
76                 activeCache.cleanUp();
77                 return loader.apply(key);
78             }
79         };
80     }
81
82     private <K, V> LoadingCache<K, V> buildAaiClientActiveCacheFrom(Function<K, V> loader, String name) {
83         return createCacheBuilder(name).build(createAsyncReloadingCacheLoaderFrom(loader));
84
85     }
86
87     @NotNull
88     protected CacheBuilder<Object, Object> createCacheBuilder(String name) {
89         CacheConfig cacheConfig = cacheConfigProvider.getCacheConfig(name);
90         return CacheBuilder.newBuilder()
91                 .maximumSize(1000)
92                 .expireAfterWrite(cacheConfig.getExpireAfterWriteHours(), TimeUnit.HOURS)
93                 .refreshAfterWrite(cacheConfig.getRefreshAfterWriteSeconds(), TimeUnit.SECONDS);
94     }
95
96     private <K, V> CacheLoader<K, V> createAsyncReloadingCacheLoaderFrom(Function<K, V> loader) {
97         return CacheLoader.asyncReloading(CacheLoader.from(loader::apply), cacheReloadPool);
98     }
99
100 }