Add ValueCache.compute method (#4704)

Signed-off-by: Jimmy Tanagra <jcode@tanagra.id.au>
pull/4491/merge
jimtng 2025-06-14 21:52:34 +09:00 committed by GitHub
parent f695acfc4c
commit 98e3b13c71
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 61 additions and 0 deletions

View File

@ -25,6 +25,7 @@ import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.BiFunction;
import java.util.function.Supplier;
import org.eclipse.jdt.annotation.NonNullByDefault;
@ -176,6 +177,12 @@ public class CacheScriptExtension implements ScriptExtensionProvider {
return Objects.requireNonNull(cache.computeIfAbsent(key, k -> supplier.get()));
}
@Override
@Nullable
public Object compute(String key, BiFunction<String, @Nullable Object, @Nullable Object> remappingFunction) {
return cache.compute(key, (k, v) -> remappingFunction.apply(k, v));
}
private Collection<Object> values() {
return cache.values();
}
@ -244,6 +251,24 @@ public class CacheScriptExtension implements ScriptExtensionProvider {
}
}
@Override
@Nullable
public Object compute(String key, BiFunction<String, @Nullable Object, @Nullable Object> remappingFunction) {
cacheLock.lock();
try {
Object value = sharedCache.compute(key, (k, v) -> remappingFunction.apply(k, v));
if (value == null) {
sharedCacheKeyAccessors.remove(key);
} else {
rememberAccessToKey(key);
}
logger.trace("COMPUTE to cache from '{}': '{}' -> '{}'", scriptIdentifier, key, value);
return value;
} finally {
cacheLock.unlock();
}
}
private void rememberAccessToKey(String key) {
Objects.requireNonNull(sharedCacheKeyAccessors.computeIfAbsent(key, k -> new HashSet<>()))
.add(scriptIdentifier);

View File

@ -12,6 +12,7 @@
*/
package org.openhab.core.automation.module.script.rulesupport.shared;
import java.util.function.BiFunction;
import java.util.function.Supplier;
import org.eclipse.jdt.annotation.NonNullByDefault;
@ -62,4 +63,17 @@ public interface ValueCache {
* @return the value associated with the key
*/
Object get(String key, Supplier<Object> supplier);
/**
* Attempts to compute a mapping for the specified key and its current mapped value
* (or null if there is no current mapping).
*
* See {@code java.util.Map.compute()} for details.
*
* @param key the key of the requested value.
* @param remappingFunction the remapping function to compute a value.
* @return the new value associated with the specified key, or null if none
*/
@Nullable
Object compute(String key, BiFunction<String, @Nullable Object, @Nullable Object> remappingFunction);
}

View File

@ -206,6 +206,28 @@ public class CacheScriptExtensionTest {
cache.put(KEY2, VALUE2);
assertThat(cache.get(KEY1), is(VALUE1));
assertThat(cache.get(KEY2), is(VALUE2));
// computed value is returned
assertThat(cache.compute(KEY1, (k, v) -> VALUE1), is(VALUE1));
assertThat(cache.get(KEY1), is(VALUE1));
assertThat(cache.compute(KEY1, (k, v) -> VALUE2), is(VALUE2));
assertThat(cache.get(KEY1), is(VALUE2));
assertThat(cache.compute(KEY1, (k, v) -> null), nullValue());
assertThat(cache.get(KEY1), nullValue());
// remappingFunction is called with key and old value
cache.remove(KEY1);
cache.compute(KEY1, (k, v) -> {
assertThat(k, is(KEY1));
assertThat(v, nullValue());
return VALUE2;
});
cache.put(KEY1, VALUE1);
cache.compute(KEY1, (k, v) -> {
assertThat(k, is(KEY1));
assertThat(v, is(VALUE1));
return VALUE2;
});
}
private ValueCache getCache(CacheScriptExtension se, String scriptIdentifier, String type) {