From 4eec4a3e45309b76498e0971f5229942d86c710a Mon Sep 17 00:00:00 2001 From: Florian Hotze Date: Wed, 6 Nov 2024 21:20:34 +0100 Subject: [PATCH] ScriptProfile: Recover from closed context for JS Scripting (#4437) Co-authored-by: J-N-K Signed-off-by: Florian Hotze --- .../script/ScriptTransformationService.java | 12 ++++++++++++ .../ScriptTransformationServiceTest.java | 18 +++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/bundles/org.openhab.core.automation.module.script/src/main/java/org/openhab/core/automation/module/script/ScriptTransformationService.java b/bundles/org.openhab.core.automation.module.script/src/main/java/org/openhab/core/automation/module/script/ScriptTransformationService.java index 0126ceb2032..3e88206101b 100644 --- a/bundles/org.openhab.core.automation.module.script/src/main/java/org/openhab/core/automation/module/script/ScriptTransformationService.java +++ b/bundles/org.openhab.core.automation.module.script/src/main/java/org/openhab/core/automation/module/script/ScriptTransformationService.java @@ -214,6 +214,18 @@ public void deactivate() { return result == null ? null : result.toString(); } catch (ScriptException e) { throw new TransformationException("Failed to execute script.", e); + } catch (IllegalStateException e) { + // ISE thrown by JS Scripting if script engine already closed + if ("The Context is already closed.".equals(e.getMessage())) { + logger.warn( + "Script engine context {} is already closed, this should not happen. Recreating script engine.", + scriptUid); + scriptCache.remove(scriptUid); + return transform(function, source); + } else { + // rethrow + throw e; + } } } finally { scriptRecord.lock.unlock(); diff --git a/bundles/org.openhab.core.automation.module.script/src/test/java/org/openhab/core/automation/module/script/ScriptTransformationServiceTest.java b/bundles/org.openhab.core.automation.module.script/src/test/java/org/openhab/core/automation/module/script/ScriptTransformationServiceTest.java index 53e0c38a37c..6752013ef58 100644 --- a/bundles/org.openhab.core.automation.module.script/src/test/java/org/openhab/core/automation/module/script/ScriptTransformationServiceTest.java +++ b/bundles/org.openhab.core.automation.module.script/src/test/java/org/openhab/core/automation/module/script/ScriptTransformationServiceTest.java @@ -37,6 +37,7 @@ import org.mockito.junit.jupiter.MockitoSettings; import org.mockito.quality.Strictness; import org.openhab.core.config.core.ConfigDescriptionRegistry; +import org.openhab.core.test.java.JavaTest; import org.openhab.core.transform.Transformation; import org.openhab.core.transform.TransformationException; import org.openhab.core.transform.TransformationRegistry; @@ -49,7 +50,7 @@ @NonNullByDefault @ExtendWith(MockitoExtension.class) @MockitoSettings(strictness = Strictness.LENIENT) -public class ScriptTransformationServiceTest { +public class ScriptTransformationServiceTest extends JavaTest { private static final String SCRIPT_LANGUAGE = "customDsl"; private static final String SCRIPT_UID = "scriptUid." + SCRIPT_LANGUAGE; private static final String INVALID_SCRIPT_UID = "invalidScriptUid"; @@ -189,6 +190,21 @@ public void scriptExceptionResultsInTransformationException() throws ScriptExcep assertThat(e.getCause().getMessage(), is("exception")); } + @Test + public void recoversFromClosedScriptContext() throws ScriptException, TransformationException { + when(scriptEngine.eval(SCRIPT)).thenThrow(new IllegalStateException("The Context is already closed.")) + .thenReturn(SCRIPT_OUTPUT); + setupInterceptedLogger(ScriptTransformationService.class, LogLevel.WARN); + + String returnValue = Objects.requireNonNull(service.transform(SCRIPT_UID, "input")); + + assertThat(returnValue, is(SCRIPT_OUTPUT)); + + stopInterceptedLogger(ScriptTransformationService.class); + assertLogMessage(ScriptTransformationService.class, LogLevel.WARN, "Script engine context " + SCRIPT_UID + + " is already closed, this should not happen. Recreating script engine."); + } + @Test public void inlineScriptProperlyProcessed() throws TransformationException, ScriptException { service.transform(INLINE_SCRIPT, "input");