* TenantAwareCacheManager define CacheEvictEvent which could be used to evict entities in general way * JpaTenantConfigurationManagement start using genera cache approach Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
@@ -13,18 +13,21 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.NonNull;
|
||||
import lombok.Value;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware.TenantResolver;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.caffeine.CaffeineCache;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
@@ -44,7 +47,6 @@ public class TenantAwareCacheManager implements CacheManager {
|
||||
private static final String CONFIG_SPEC = "spec";
|
||||
|
||||
private static final TenantAwareCacheManager SINGLETON = new TenantAwareCacheManager();
|
||||
|
||||
private CacheManager globalCacheManager;
|
||||
private final Map<String, CacheManager> tenant2CacheManager = new ConcurrentHashMap<>();
|
||||
|
||||
@@ -66,13 +68,14 @@ public class TenantAwareCacheManager implements CacheManager {
|
||||
globalCacheManager = new TenantCacheManager(null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@NonNull
|
||||
@Override
|
||||
public Cache getCache(@NonNull final String name) {
|
||||
return Optional.ofNullable(resolver.resolveTenant())
|
||||
final Cache cache = Optional.ofNullable(resolver.resolveTenant())
|
||||
.map(currentTenant -> tenant2CacheManager.computeIfAbsent(currentTenant, TenantCacheManager::new))
|
||||
.orElse(globalCacheManager)
|
||||
.getCache(name);
|
||||
return cache == null ? new Nop(name) : cache;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -87,11 +90,54 @@ public class TenantAwareCacheManager implements CacheManager {
|
||||
}
|
||||
}
|
||||
|
||||
public void evictTenant(final String tenant) {
|
||||
if (tenant == null) {
|
||||
globalCacheManager.getCacheNames().forEach(name -> Optional.ofNullable(globalCacheManager.getCache(name)).ifPresent(Cache::clear));
|
||||
} else {
|
||||
tenant2CacheManager.remove(tenant);
|
||||
/**
|
||||
* Ensures that cache eviction takes place in microservice mode in case of deletions.
|
||||
*
|
||||
* @param event The event indicating that a configuration value has been deleted.
|
||||
*/
|
||||
@EventListener
|
||||
@SuppressWarnings("java:S3776") // not too complex and this way is more readable
|
||||
public void onCacheEvictEvent(final CacheEvictEvent event) {
|
||||
final CacheManager cacheManager = event.getTenant() == null ? globalCacheManager : tenant2CacheManager.get(event.getTenant());
|
||||
if (cacheManager != null) {
|
||||
if (event.getCacheName() == null) { // evict all caches
|
||||
if (event.getTenant() == null) { // global cache
|
||||
cacheManager.getCacheNames().forEach(name -> {
|
||||
final Cache cache = cacheManager.getCache(name);
|
||||
if (cache != null) {
|
||||
cache.clear();
|
||||
}
|
||||
});
|
||||
} else { // tenant specific cache
|
||||
tenant2CacheManager.remove(event.getTenant());
|
||||
}
|
||||
} else {
|
||||
final Cache cache = cacheManager.getCache(event.getCacheName());
|
||||
if (cache != null) {
|
||||
if (event.getCacheKey() == null) { // evict all keys
|
||||
cache.clear();
|
||||
} else { // evict specific key
|
||||
cache.evict(event.getCacheKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface CacheEvictEvent {
|
||||
|
||||
String getTenant();
|
||||
|
||||
String getCacheName(); // null means - all caches shall be evicted
|
||||
|
||||
Object getCacheKey(); // null means - all keys shall be evicted
|
||||
|
||||
@Value
|
||||
class Default implements CacheEvictEvent {
|
||||
|
||||
String tenant;
|
||||
String cacheName;
|
||||
Object cacheKey;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +164,17 @@ public class TenantAwareCacheManager implements CacheManager {
|
||||
}
|
||||
}
|
||||
try {
|
||||
return new CaffeineCache(n, Caffeine.from(spec).build(), false);
|
||||
return new CaffeineCache(n, Caffeine.from(spec).build(), false) {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
@SuppressWarnings("java:S2638") // used internally in hawkbit and want to return null instead of error
|
||||
protected Object toStoreValue(@Nullable Object userValue) {
|
||||
// we want to return pure null to caffeine when null, in order to do not cache
|
||||
// we want to allow null results but not to be cached!
|
||||
return userValue;
|
||||
}
|
||||
};
|
||||
} catch (final IllegalArgumentException e) {
|
||||
log.error("Invalid cache spec: {}", spec, e);
|
||||
throw new IllegalStateException("Invalid cache spec: " + spec, e);
|
||||
@@ -132,4 +188,52 @@ public class TenantAwareCacheManager implements CacheManager {
|
||||
return caches.keySet();
|
||||
}
|
||||
}
|
||||
|
||||
@Value
|
||||
private static class Nop implements Cache {
|
||||
|
||||
String name;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Object getNativeCache() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueWrapper get(@NonNull final Object key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T get(@NonNull final Object key, final Class<T> type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T get(@NonNull final Object key, @NonNull final Callable<T> valueLoader) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(@NonNull final Object key, final Object value) {
|
||||
// nop
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evict(@NonNull final Object key) {
|
||||
// nop
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
// nop
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user