Skip to content

Added ability to use Caffeine for Caching, which enables additional features like eviction, which is not supported by existing ConcurrentHashMap parseCache (#45) #56

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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) {
Expand Down
15 changes: 14 additions & 1 deletion src/main/java/io/github/jamsesso/jsonlogic/JsonLogic.java
Original file line number Diff line number Diff line change
@@ -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.*;
Expand All @@ -12,11 +15,21 @@
import java.util.function.Function;

public final class JsonLogic {
private final Map<String, JsonLogicNode> parseCache = new ConcurrentHashMap<>();
private final CacheManager<String, JsonLogicNode> parseCache;
private final Map<String, JsonLogicExpression> expressions = new ConcurrentHashMap<>();
private JsonLogicEvaluator evaluator;

public JsonLogic() {
this.parseCache = new ConcurrentHashMapCacheManager<>();
initializeOperations();
}

public JsonLogic(final CacheManager<String, JsonLogicNode> parseCache) {
this.parseCache = parseCache;
initializeOperations();
}

private void initializeOperations() {
// Add default operations
addOperation(MathExpression.ADD);
addOperation(MathExpression.SUBTRACT);
Expand Down
30 changes: 30 additions & 0 deletions src/main/java/io/github/jamsesso/jsonlogic/cache/CacheManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package io.github.jamsesso.jsonlogic.cache;

/**
* CacheManager interface for managing cache operations.
*
* @param <K> the type of keys maintained by this cache
* @param <V> the type of cached values
*/
public interface CacheManager<K, V> {
/**
* 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);
}
Original file line number Diff line number Diff line change
@@ -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 <K> the type of keys maintained by this cache
* @param <V> the type of cached values
*/
public class CaffeineCacheManager<K, V> implements CacheManager<K, V> {
private final Cache<K, V> 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);
}
}
Original file line number Diff line number Diff line change
@@ -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 <K> the type of keys maintained by this cache
* @param <V> the type of cached values
*/
public class ConcurrentHashMapCacheManager<K, V> implements CacheManager<K, V> {
private final ConcurrentHashMap<K, V> 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);
}

}
Original file line number Diff line number Diff line change
@@ -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));
}
}