package org.trimou.engine.cache; import static org.junit.Assert.assertEquals; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.junit.Test; import org.trimou.AbstractTest; import org.trimou.Hammer; import org.trimou.engine.MustacheEngine; import org.trimou.engine.MustacheEngineBuilder; import org.trimou.engine.cache.ComputingCache.Function; import org.trimou.engine.cache.ComputingCache.Listener; import org.trimou.engine.config.AbstractConfigurationAware; import org.trimou.engine.locator.MapTemplateLocator; import org.trimou.engine.resolver.ReflectionResolver; import org.trimou.engine.resolver.Resolver; import org.trimou.util.ImmutableMap; /** * * @author Martin Kouba */ public class CustomComputingCacheFactoryTest extends AbstractTest { @SuppressWarnings("rawtypes") @Test public void testCustomFactory() { CustomFactory factory = new CustomFactory(); MustacheEngine engine = MustacheEngineBuilder .newBuilder() .addTemplateLocator( new MapTemplateLocator(ImmutableMap.of("foo", "{{this.age}}"))) .setComputingCacheFactory(factory).build(); assertEquals("10",engine.getMustache("foo").render(new Hammer())); List<CustomComputingCache> reflectionCaches = factory.caches.get(ReflectionResolver.COMPUTING_CACHE_CONSUMER_ID); assertEquals(1, reflectionCaches.size()); CustomComputingCache reflectionCache = reflectionCaches.get(0); assertEquals(1, reflectionCache.size()); List<CustomComputingCache> templateCaches = factory.caches.get(MustacheEngine.COMPUTING_CACHE_CONSUMER_ID); assertEquals(1, templateCaches.size()); for (CustomComputingCache cache : templateCaches) { cache.clear(); } getReflectionResolver(engine).invalidateMemberCache(null); assertEquals(0, reflectionCache.size()); assertEquals("10",engine.getMustache("foo").render(new Hammer())); } private ReflectionResolver getReflectionResolver(MustacheEngine engine) { for (Resolver resolver : engine.getConfiguration().getResolvers()) { if(resolver instanceof ReflectionResolver) { return (ReflectionResolver) resolver; } } return null; } private static class CustomFactory extends AbstractConfigurationAware implements ComputingCacheFactory { @SuppressWarnings("rawtypes") final Map<String, List<CustomComputingCache>> caches = new HashMap<>(); @SuppressWarnings("rawtypes") @Override public <K, V> ComputingCache<K, V> create(String consumerId, Function<K, V> computingFunction, Long expirationTimeout, Long maxSize, Listener<K> listener) { CustomComputingCache<K, V> cache = new CustomComputingCache<>(new HashMap<>(), computingFunction); List<CustomComputingCache> list = caches.computeIfAbsent(consumerId, k -> new ArrayList<>()); list.add(cache); return cache; } } private static class CustomComputingCache<K, V> implements ComputingCache<K, V> { final Map<K, V> map; final Function<K, V> computingFunction; public CustomComputingCache(Map<K, V> map, ComputingCache.Function<K, V> computingFunction) { this.map = map; this.computingFunction = computingFunction; } @Override public synchronized V get(K key) { return map.computeIfAbsent(key, k -> computingFunction.compute(key)); } @Override public synchronized void clear() { map.clear(); } @Override public synchronized long size() { return map.size(); } @Override public synchronized void invalidate( ComputingCache.KeyPredicate<K> keyPredicate) { map.entrySet().removeIf(entry -> keyPredicate.apply(entry.getKey())); } @Override public synchronized V getIfPresent(K key) { return map.get(key); } @Override public synchronized Map<K, V> getAllPresent() { return ImmutableMap.copyOf(map); } } }