diff --git a/bundles/org.openhab.core.automation.module.script.rulesupport/src/main/java/org/openhab/core/automation/module/script/rulesupport/internal/CacheScriptExtension.java b/bundles/org.openhab.core.automation.module.script.rulesupport/src/main/java/org/openhab/core/automation/module/script/rulesupport/internal/CacheScriptExtension.java index 07d3a2d6c8..f0ddddf48b 100644 --- a/bundles/org.openhab.core.automation.module.script.rulesupport/src/main/java/org/openhab/core/automation/module/script/rulesupport/internal/CacheScriptExtension.java +++ b/bundles/org.openhab.core.automation.module.script.rulesupport/src/main/java/org/openhab/core/automation/module/script/rulesupport/internal/CacheScriptExtension.java @@ -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 remappingFunction) { + return cache.compute(key, (k, v) -> remappingFunction.apply(k, v)); + } + private Collection values() { return cache.values(); } @@ -244,6 +251,24 @@ public class CacheScriptExtension implements ScriptExtensionProvider { } } + @Override + @Nullable + public Object compute(String key, BiFunction 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); diff --git a/bundles/org.openhab.core.automation.module.script.rulesupport/src/main/java/org/openhab/core/automation/module/script/rulesupport/shared/ValueCache.java b/bundles/org.openhab.core.automation.module.script.rulesupport/src/main/java/org/openhab/core/automation/module/script/rulesupport/shared/ValueCache.java index 7aa8ecd950..1dbd9db798 100644 --- a/bundles/org.openhab.core.automation.module.script.rulesupport/src/main/java/org/openhab/core/automation/module/script/rulesupport/shared/ValueCache.java +++ b/bundles/org.openhab.core.automation.module.script.rulesupport/src/main/java/org/openhab/core/automation/module/script/rulesupport/shared/ValueCache.java @@ -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 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 remappingFunction); } diff --git a/bundles/org.openhab.core.automation.module.script.rulesupport/src/test/java/org/openhab/core/automation/module/script/rulesupport/internal/CacheScriptExtensionTest.java b/bundles/org.openhab.core.automation.module.script.rulesupport/src/test/java/org/openhab/core/automation/module/script/rulesupport/internal/CacheScriptExtensionTest.java index 9648de2ffd..e2ae417a04 100644 --- a/bundles/org.openhab.core.automation.module.script.rulesupport/src/test/java/org/openhab/core/automation/module/script/rulesupport/internal/CacheScriptExtensionTest.java +++ b/bundles/org.openhab.core.automation.module.script.rulesupport/src/test/java/org/openhab/core/automation/module/script/rulesupport/internal/CacheScriptExtensionTest.java @@ -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) {