diff --git a/build.gradle b/build.gradle index d3cd452..70fa290 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { } group "io.github.jamsesso" -version "1.1.1-SNAPSHOT" +version "1.1.2-SNAPSHOT" sourceCompatibility = 1.8 targetCompatibility = 1.8 @@ -17,6 +17,7 @@ repositories { dependencies { compile "com.google.code.gson:gson:2.8.5" testCompile "junit:junit:4.12" + implementation "com.github.ben-manes.caffeine:caffeine:2.9.3" } task javadocJar(type: Jar, dependsOn: javadoc) { diff --git a/src/main/java/io/github/jamsesso/jsonlogic/JsonLogic.java b/src/main/java/io/github/jamsesso/jsonlogic/JsonLogic.java index fa25f2f..b42cf62 100644 --- a/src/main/java/io/github/jamsesso/jsonlogic/JsonLogic.java +++ b/src/main/java/io/github/jamsesso/jsonlogic/JsonLogic.java @@ -1,7 +1,10 @@ package io.github.jamsesso.jsonlogic; import io.github.jamsesso.jsonlogic.ast.JsonLogicNode; +import io.github.jamsesso.jsonlogic.ast.JsonLogicParseException; import io.github.jamsesso.jsonlogic.ast.JsonLogicParser; +import io.github.jamsesso.jsonlogic.cache.CacheManager; +import io.github.jamsesso.jsonlogic.cache.ConcurrentHashMapCacheManager; import io.github.jamsesso.jsonlogic.evaluator.JsonLogicEvaluator; import io.github.jamsesso.jsonlogic.evaluator.JsonLogicExpression; import io.github.jamsesso.jsonlogic.evaluator.expressions.*; @@ -12,11 +15,21 @@ import java.util.function.Function; public final class JsonLogic { - private final Map parseCache = new ConcurrentHashMap<>(); + private final CacheManager parseCache; private final Map expressions = new ConcurrentHashMap<>(); private JsonLogicEvaluator evaluator; public JsonLogic() { + this.parseCache = new ConcurrentHashMapCacheManager<>(); + initializeOperations(); + } + + public JsonLogic(final CacheManager parseCache) { + this.parseCache = parseCache; + initializeOperations(); + } + + private void initializeOperations() { // Add default operations addOperation(MathExpression.ADD); addOperation(MathExpression.SUBTRACT); diff --git a/src/main/java/io/github/jamsesso/jsonlogic/cache/CacheManager.java b/src/main/java/io/github/jamsesso/jsonlogic/cache/CacheManager.java new file mode 100644 index 0000000..f0582cf --- /dev/null +++ b/src/main/java/io/github/jamsesso/jsonlogic/cache/CacheManager.java @@ -0,0 +1,30 @@ +package io.github.jamsesso.jsonlogic.cache; + +/** + * CacheManager interface for managing cache operations. + * + * @param the type of keys maintained by this cache + * @param the type of cached values + */ +public interface CacheManager { + /** + * Checks if the cache contains a value for the specified key. + * @param key the key to check + * @return true if the cache contains the key, false otherwise + */ + boolean containsKey(K key); + + /** + * Puts a value in the cache with the specified key. + * @param key the key to associate with the value + * @param value the value to cache + */ + void put(K key, V value); + + /** + * Retrieves a value from the cache for the specified key. + * @param key the key to look up + * @return the cached value, or null if not found + */ + V get(K key); +} diff --git a/src/main/java/io/github/jamsesso/jsonlogic/cache/CaffeineCacheManager.java b/src/main/java/io/github/jamsesso/jsonlogic/cache/CaffeineCacheManager.java new file mode 100644 index 0000000..8a3c0bc --- /dev/null +++ b/src/main/java/io/github/jamsesso/jsonlogic/cache/CaffeineCacheManager.java @@ -0,0 +1,44 @@ +package io.github.jamsesso.jsonlogic.cache; + +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; + +/** + * CaffeineCacheManager is a cache manager that uses Caffeine for caching. + * It provides methods to check if a key exists, put a value in the cache, + * and retrieve a value from the cache. + * + * @param the type of keys maintained by this cache + * @param the type of cached values + */ +public class CaffeineCacheManager implements CacheManager { + private final Cache cache; + + public CaffeineCacheManager() { + this.cache = Caffeine.newBuilder().build(); + } + + /** + * Constructs a CaffeineCacheManager with the specified maximum capacity. + * + * @param maxCapacity the maximum number of entries the cache can hold + */ + public CaffeineCacheManager(int maxCapacity) { + this.cache = Caffeine.newBuilder().maximumSize(maxCapacity).build(); + } + + @Override + public boolean containsKey(K key) { + return cache.asMap().containsKey(key); + } + + @Override + public void put(K key, V value) { + cache.put(key, value); + } + + @Override + public V get(K key) { + return cache.getIfPresent(key); + } +} \ No newline at end of file diff --git a/src/main/java/io/github/jamsesso/jsonlogic/cache/ConcurrentHashMapCacheManager.java b/src/main/java/io/github/jamsesso/jsonlogic/cache/ConcurrentHashMapCacheManager.java new file mode 100644 index 0000000..fc8fb8c --- /dev/null +++ b/src/main/java/io/github/jamsesso/jsonlogic/cache/ConcurrentHashMapCacheManager.java @@ -0,0 +1,35 @@ +package io.github.jamsesso.jsonlogic.cache; + +import java.util.concurrent.ConcurrentHashMap; + +/** + * ConcurrentHashMapCacheManager is a cache manager that uses ConcurrentHashMap for caching. + * It provides methods to check if a key exists, put a value in the cache, + * and retrieve a value from the cache. + * + * @param the type of keys maintained by this cache + * @param the type of cached values + */ +public class ConcurrentHashMapCacheManager implements CacheManager { + private final ConcurrentHashMap cache; + + public ConcurrentHashMapCacheManager() { + this.cache = new ConcurrentHashMap<>(); + } + + @Override + public boolean containsKey(K key) { + return cache.containsKey(key); + } + + @Override + public void put(K key, V value) { + cache.put(key, value); + } + + @Override + public V get(K key) { + return cache.get(key); + } + +} diff --git a/src/test/java/io/github/jamsesso/jsonlogic/CaffeineCacheJsonLogicTest.java b/src/test/java/io/github/jamsesso/jsonlogic/CaffeineCacheJsonLogicTest.java new file mode 100644 index 0000000..aac3f98 --- /dev/null +++ b/src/test/java/io/github/jamsesso/jsonlogic/CaffeineCacheJsonLogicTest.java @@ -0,0 +1,28 @@ +package io.github.jamsesso.jsonlogic; + +import org.junit.Test; + +import io.github.jamsesso.jsonlogic.cache.CaffeineCacheManager; + +import static org.junit.Assert.assertEquals; + +public class CaffeineCacheJsonLogicTest { + private static final JsonLogic jsonLogic = new JsonLogic(new CaffeineCacheManager<>()); + private static final JsonLogic jsonLogicWithMaxCacheSize = new JsonLogic(new CaffeineCacheManager<>(1000)); + + + @Test + public void testEmptyArray() throws JsonLogicException { + assertEquals(false, jsonLogic.apply("{\"all\": [[], {\">\": [{\"var\": \"\"}, 0]}]}", null)); + assertEquals(false, jsonLogicWithMaxCacheSize.apply("{\"all\": [[], {\">\": [{\"var\": \"\"}, 0]}]}", null)); + } + + @Test + public void testAll() throws JsonLogicException { + assertEquals(true, jsonLogic.apply("{\"all\": [[1, 2, 3], {\">\": [{\"var\": \"\"}, 0]}]}", null)); + assertEquals(false, jsonLogic.apply("{\"all\": [[1, 2, 3], {\">\": [{\"var\": \"\"}, 1]}]}", null)); + + assertEquals(true, jsonLogicWithMaxCacheSize.apply("{\"all\": [[1, 2, 3], {\">\": [{\"var\": \"\"}, 0]}]}", null)); + assertEquals(false, jsonLogicWithMaxCacheSize.apply("{\"all\": [[1, 2, 3], {\">\": [{\"var\": \"\"}, 1]}]}", null)); + } +}