[jsscripting] Await activation of OSGiScriptExtensionProvider before registering ScriptEngineFactory (#21042)

* [jsscripting] Await activation of OSGiScriptExtensionProvider before registering ScriptEngineFactory

This ensures that OSGiScriptExtensionProvider / `require('@runtime/osgi').bundleContext` is always available when JS ScriptEngines are created.
Fixes issues such as #21014.

Signed-off-by: Florian Hotze <dev@florianhotze.com>
This commit is contained in:
Florian Hotze
2026-06-26 14:34:39 +02:00
committed by GitHub
parent 2c5f67d303
commit a94c69fd36
3 changed files with 23 additions and 4 deletions
@@ -24,6 +24,7 @@ import org.eclipse.jdt.annotation.Nullable;
import org.graalvm.polyglot.Engine;
import org.graalvm.polyglot.Language;
import org.openhab.automation.jsscripting.internal.fs.watch.JSDependencyTracker;
import org.openhab.automation.jsscripting.internal.scope.OSGiScriptExtensionProvider;
import org.openhab.automation.jsscripting.internal.util.ThreadLocalSlf4jOutputStream;
import org.openhab.core.OpenHAB;
import org.openhab.core.automation.module.script.ScriptDependencyTracker;
@@ -75,8 +76,16 @@ public class GraalJSScriptEngineFactory implements ScriptEngineFactory {
private final JSDependencyTracker jsDependencyTracker;
@Activate
public GraalJSScriptEngineFactory(final @Reference JSScriptServiceUtil jsScriptServiceUtil,
final @Reference JSDependencyTracker jsDependencyTracker, Map<String, Object> config) {
public GraalJSScriptEngineFactory(final @Reference JSScriptServiceUtil jsScriptServiceUtil, //
final @Reference JSDependencyTracker jsDependencyTracker, //
final @Reference OSGiScriptExtensionProvider osgiScriptExtensionProvider, // declare dependency on
// OSGiScriptExtensionProvider to
// fix a timing issue where
// openhab-js attempts to lookup
// OSGi services before
// OSGiScriptExtensionProvider is
// active
Map<String, Object> config) {
logger.debug("Loading GraalJSScriptEngineFactory");
this.jsDependencyTracker = jsDependencyTracker;
@@ -21,7 +21,7 @@ import org.osgi.service.component.annotations.Component;
*
* @author Jonathan Gilbert - Initial contribution
*/
@Component(immediate = true, service = ScriptExtensionProvider.class)
@Component(immediate = true, service = { ScriptExtensionProvider.class, OSGiScriptExtensionProvider.class })
public class OSGiScriptExtensionProvider extends ScriptDisposalAwareScriptExtensionProvider {
@Override
@@ -30,6 +30,7 @@ import org.mockito.quality.Strictness;
import org.openhab.automation.jsscripting.internal.GraalJSScriptEngineFactory;
import org.openhab.automation.jsscripting.internal.JSScriptServiceUtil;
import org.openhab.automation.jsscripting.internal.fs.watch.JSDependencyTracker;
import org.openhab.automation.jsscripting.internal.scope.OSGiScriptExtensionProvider;
import org.openhab.core.automation.module.script.action.ScriptExecution;
import org.openhab.core.scheduler.Scheduler;
import org.openhab.core.service.WatchService;
@@ -63,6 +64,9 @@ public abstract class GraalJSOSGiTest extends JavaOSGiTest {
@NonNullByDefault({})
ScriptExecution scriptExecution;
@NonNullByDefault({})
OSGiScriptExtensionProvider osgiScriptExtensionProvider;
@NonNullByDefault({})
JSScriptServiceUtil jsScriptServiceUtil;
@NonNullByDefault({})
@@ -82,10 +86,14 @@ public abstract class GraalJSOSGiTest extends JavaOSGiTest {
public void beforeEach() throws Exception {
when(watchService.getWatchPath()).thenReturn(tempDir);
osgiScriptExtensionProvider = new OSGiScriptExtensionProvider();
osgiScriptExtensionProvider.activate(bundleContext);
jsScriptServiceUtil = new JSScriptServiceUtil(scheduler, scriptExecution);
jsDependencyTracker = new JSDependencyTracker(watchService);
scriptEngineFactory = new GraalJSScriptEngineFactory(jsScriptServiceUtil, jsDependencyTracker, config);
scriptEngineFactory = new GraalJSScriptEngineFactory(jsScriptServiceUtil, jsDependencyTracker,
osgiScriptExtensionProvider, config);
}
@AfterEach
@@ -96,6 +104,8 @@ public abstract class GraalJSOSGiTest extends JavaOSGiTest {
jsDependencyTracker.deactivate();
jsDependencyTracker = null;
osgiScriptExtensionProvider = null;
clearInvocations(watchService, scheduler, scriptExecution);
}
}