1212 */
1313package org .openhab .core .automation .module .script .rulesupport .internal ;
1414
15+ import java .lang .reflect .InvocationTargetException ;
16+ import java .lang .reflect .Method ;
1517import java .util .Collection ;
1618import java .util .HashMap ;
1719import java .util .HashSet ;
@@ -52,6 +54,7 @@ public class CacheScriptExtension implements ScriptExtensionProvider {
5254 static final String SHARED_CACHE_NAME = "sharedCache" ;
5355 static final String PRIVATE_CACHE_NAME = "privateCache" ;
5456 static final String OBJECT_CACHE_NAME = "objectCache" ;
57+ static final String LOCKING_CACHE_NAME = "lockingCache" ;
5558
5659 private final Logger logger = LoggerFactory .getLogger (CacheScriptExtension .class );
5760 private final ScheduledExecutorService scheduler = ThreadPoolManager
@@ -60,6 +63,7 @@ public class CacheScriptExtension implements ScriptExtensionProvider {
6063 private final Lock cacheLock = new ReentrantLock ();
6164 private final Map <String , Object > sharedCache = new HashMap <>();
6265 private final ObjectCache objectCache = new ObjectCacheImpl ();
66+ private final LockingCache lockingCache = new LockingCacheImpl ();
6367 private final Map <String , Set <String >> sharedCacheKeyAccessors = new ConcurrentHashMap <>();
6468
6569 private final Map <String , ValueCacheImpl > privateCaches = new ConcurrentHashMap <>();
@@ -79,7 +83,7 @@ public Collection<String> getPresets() {
7983
8084 @ Override
8185 public Collection <String > getTypes () {
82- return Set .of (PRIVATE_CACHE_NAME , SHARED_CACHE_NAME , OBJECT_CACHE_NAME );
86+ return Set .of (PRIVATE_CACHE_NAME , SHARED_CACHE_NAME , OBJECT_CACHE_NAME , LOCKING_CACHE_NAME );
8387 }
8488
8589 @ Override
@@ -91,6 +95,8 @@ public Collection<String> getTypes() {
9195 return privateCaches .computeIfAbsent (scriptIdentifier , ValueCacheImpl ::new );
9296 case OBJECT_CACHE_NAME :
9397 return objectCache ;
98+ case LOCKING_CACHE_NAME :
99+ return lockingCache ;
94100 default :
95101 return null ;
96102 }
@@ -102,7 +108,7 @@ public Map<String, Object> importPreset(String scriptIdentifier, String preset)
102108 Object privateCache = Objects
103109 .requireNonNull (privateCaches .computeIfAbsent (scriptIdentifier , ValueCacheImpl ::new ));
104110 return Map .of (SHARED_CACHE_NAME , new TrackingValueCacheImpl (scriptIdentifier ), PRIVATE_CACHE_NAME ,
105- privateCache , OBJECT_CACHE_NAME , objectCache );
111+ privateCache , OBJECT_CACHE_NAME , objectCache , LOCKING_CACHE_NAME , lockingCache );
106112 }
107113
108114 return Map .of ();
@@ -344,33 +350,6 @@ private static class LockingCacheImpl implements LockingCache {
344350 // All access must be guarded by "cache"
345351 private final Map <String , LockingCacheValue > cache = new HashMap <>();
346352
347- @ Override
348- public @ Nullable Object put (String key , Object object ) {
349- LockingCacheValue value ;
350- boolean created = false ;
351- synchronized (cache ) {
352- value = cache .get (key );
353- if (value == null || value .removed ) {
354- created = true ;
355- value = new LockingCacheValue ();
356- value .lock .lock ();
357- cache .put (key , value );
358- }
359- }
360- Object result ;
361- if (!created ) {
362- value .lock .lock ();
363- }
364- try {
365- result = value .object ;
366- value .object = object ;
367- } finally {
368- value .lock .unlock ();
369- }
370-
371- return result ;
372- }
373-
374353 @ Override
375354 public @ Nullable Object lockAndPut (String key , Object object ) {
376355 LockingCacheValue value ;
@@ -453,13 +432,13 @@ public Object lockAndGet(String key, Supplier<Object> supplier) {
453432 }
454433
455434 @ Override
456- public void unlock (String key ) {
435+ public @ Nullable Object unlock (String key ) {
457436 LockingCacheValue value ;
458437 synchronized (cache ) {
459438 value = cache .get (key );
460439 }
461440 if (value == null ) {
462- return ;
441+ return null ;
463442 }
464443 if (value .removed ) {
465444 unlockAll (value );
@@ -470,6 +449,18 @@ public void unlock(String key) {
470449 // Ignore
471450 }
472451 }
452+ if (value .object instanceof Cloneable c ) {
453+ try {
454+ Method method = c .getClass ().getMethod ("clone" );
455+ if (method .canAccess (c )) {
456+ return method .invoke (c );
457+ }
458+ } catch (NoSuchMethodException | SecurityException | IllegalAccessException
459+ | InvocationTargetException e ) {
460+ // Ignore, just return null
461+ }
462+ }
463+ return null ;
473464 }
474465
475466 private void unlockAll (LockingCacheValue value ) {
0 commit comments