TenantAwareCacheResolver.java
package com.tradecloud.cache;
import com.hazelcast.config.*;
import com.hazelcast.spring.cache.HazelcastCacheManager;
import com.tradecloud.authentication.Client;
import com.tradecloud.authentication.MultiTenantUtil;
import com.tradecloud.config.MyEvictionListener;
import com.tradecloud.repository.UserClientMappingRepository;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.interceptor.CacheOperationInvocationContext;
import org.springframework.cache.interceptor.CacheResolver;
import org.springframework.stereotype.Component;
import java.util.*;
@Component("tenantAwareCacheResolver")
public class TenantAwareCacheResolver implements CacheResolver {
private static final Logger log = Logger.getLogger(TenantAwareCacheResolver.class);
@Autowired
private CacheManager cacheManager;
@Autowired
private UserClientMappingRepository userClientMappingLookupService;
private Set<String> configured = new HashSet();
@Override
public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {
String tenant = MultiTenantUtil.getActiveClient();
Collection<String> baseNames = context.getOperation().getCacheNames();
if (baseNames == null || baseNames.isEmpty()) {
return Collections.emptyList();
}
java.util.List<Cache> caches = new java.util.ArrayList<>(baseNames.size());
for (String baseName : baseNames) {
String cacheName = tenant + "_" + baseName;
Cache cache = cacheManager.getCache(cacheName);
if (cache == null) {
throw new IllegalStateException("No cache found with name: " + cacheName);
}
configureCache(tenant, cacheName);
caches.add(cache);
}
return caches;
}
private void configureCache(String tenant, String cacheName) {
if (tenant != null && !configured.contains(cacheName)) {
Client client = userClientMappingLookupService.findClientByCode(tenant);
Map<String, String> connectionProperties = client.getConnectionProperties();
if (connectionProperties != null && !connectionProperties.isEmpty()) {
MapConfig currentConfig = ((HazelcastCacheManager) cacheManager).getHazelcastInstance().getConfig().getMapConfig(cacheName);
currentConfig = overrideConfig(currentConfig, connectionProperties);
((HazelcastCacheManager) cacheManager).getHazelcastInstance().getConfig().addMapConfig(currentConfig);
}
configured.add(cacheName);
}
}
public MapConfig overrideConfig(MapConfig mapConfig, Map<String, String> connectionProperties) {
if (connectionProperties != null && !connectionProperties.isEmpty()) {
EntryListenerConfig entryListenerConfig = new EntryListenerConfig();
entryListenerConfig.setImplementation(new MyEvictionListener());
entryListenerConfig.setLocal(false); // Set to true if you only want to hear about local partition events
mapConfig.addEntryListenerConfig(entryListenerConfig);
EvictionConfig evictionConfig = mapConfig.setBackupCount(valueOrDefault("backup-count", connectionProperties, 1))
.setTimeToLiveSeconds(valueOrDefault("time-to-live", connectionProperties, 0))
.setMaxIdleSeconds(valueOrDefault("max-idle-seconds", connectionProperties, 0))
.setReadBackupData(valueOrDefault("read-backup-data", connectionProperties, true))
.setStatisticsEnabled(valueOrDefault("statistics-enabled", connectionProperties, true))
.setPerEntryStatsEnabled(valueOrDefault("per-entry-stats-enabled", connectionProperties, true))
.setMergePolicyConfig(new MergePolicyConfig("com.hazelcast.spi.merge.PassThroughMergePolicy", MergePolicyConfig.DEFAULT_BATCH_SIZE))
.getEvictionConfig();
//use default or general max size unless there is a named value
int maxSize = valueOrDefault("max-size", connectionProperties, 10000);
int maxSizeNamed = valueOrDefault(mapConfig.getName().replace("*_", ""),
connectionProperties, 10000);
if (maxSize != maxSizeNamed)
evictionConfig.setSize(maxSizeNamed);
else
evictionConfig.setSize(maxSize);
evictionConfig.setEvictionPolicy(valueOrDefault("eviction-policy", connectionProperties, EvictionPolicy.LFU));
//specific case: if not found(max-size-policy) do not configure
if (connectionProperties.get("max-size-policy") != null)
evictionConfig.setMaxSizePolicy(valueOrDefault("max-size-policy", connectionProperties));
log.debug("Override Map: " + mapConfig.getName() + " | TTL: " + mapConfig.getTimeToLiveSeconds() + " seconds");
}
return mapConfig;
}
private static int valueOrDefault(String key, Map<String, String> map, int defaultValue) {
key = liteConfigKey(key);
if (map.get(key) != null) {
return Integer.parseInt(map.get(key));
}
return defaultValue;
}
private static String valueOrDefault(String key, Map<String, String> map, String defaultValue) {
key = liteConfigKey(key);
if (map.get(key) != null) {
return map.get(key);
}
return defaultValue;
}
private static MaxSizePolicy valueOrDefault(String key, Map<String, String> map) {
key = liteConfigKey(key);
if (map.get(key) != null) {
return MaxSizePolicy.valueOf(map.get(key));
}
return null;
}
private static EvictionPolicy valueOrDefault(String key, Map<String, String> map, EvictionPolicy defaultPolicy) {
key = liteConfigKey(key);
if (map.get(key) != null) {
return EvictionPolicy.valueOf(map.get(key));
}
return defaultPolicy;
}
private static boolean valueOrDefault(String key, Map<String, String> map, boolean defaultValue) {
key = liteConfigKey(key);
if (map.get(key) != null) {
return Boolean.parseBoolean(map.get(key));
}
return defaultValue;
}
/**
*
* @param key
* @return the worker need it's own set of config
*/
private static String liteConfigKey(String key) {
if (System.getenv("hazelcast_role") != null && System.getenv("hazelcast_role").equals("WORKER")) {
return key + "_lite";
}
return key;
}
public void setCacheManager(CacheManager cacheManager) {
this.cacheManager = cacheManager;
}
}