Class DefaultScriptEngineResolver
- All Implemented Interfaces:
ScriptEngineResolver
-
Field Summary
FieldsModifier and TypeFieldDescriptionprotected final Map<String,ScriptEngine> protected final ScriptEngineManager -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionvoidaddScriptEngineFactory(ScriptEngineFactory scriptEngineFactory) protected voidconfigureGraalJsScriptEngine(ScriptEngine scriptEngine) Allows providing custom configuration for the Graal JS script engine.protected voidconfigureGroovyScriptEngine(ScriptEngine scriptEngine) Allows providing custom configuration for the groovy script engine.protected voidconfigureScriptEngines(String language, ScriptEngine scriptEngine) protected ScriptEngineConstructs a GraalJSScriptEnginebound to a freshly created, privateorg.graalvm.polyglot.Engine- never the implicit JVM-wide shared default.protected ScriptEnginegetEngineByName(String name) Resolves a script engine by name, giving GraalJS its own private, single-useorg.graalvm.polyglot.Engineinstead of going throughscriptEngineManager.getEngineByName(...)directly - see issue #3174.protected ScriptEnginegetJavaScriptScriptEngine(String language) protected ScriptEnginegetScriptEngine(String language) getScriptEngine(String language, boolean resolveFromCache) Returns a cached script engine or creates a new script engine if no such engine is currently cached.protected booleanisCachable(ScriptEngine scriptEngine) Allows checking whether the script engine can be cached.protected booleanReturnstrueif the default JavaScript engine (ScriptingEngines.DEFAULT_JS_SCRIPTING_LANGUAGE, i.e.protected booleanisGraalJs(ScriptEngine scriptEngine) protected booleanisGraalJsAlias(String name) ReturnstrueifscriptEngineManagerhas a GraalJS factory registered whoseScriptEngineFactory.getNames()containsname(case-insensitively) - i.e.protected booleanisJavaScriptAlias(String language) protected booleanisJsEngineNameStale(ScriptEngine cached, ProcessEngineConfigurationImpl config) Returnstrueif the cached engine's factory no longer matches the effective JavaScript engine name for the current configuration.
-
Field Details
-
scriptEngineManager
-
cachedEngines
-
-
Constructor Details
-
DefaultScriptEngineResolver
-
-
Method Details
-
addScriptEngineFactory
- Specified by:
addScriptEngineFactoryin interfaceScriptEngineResolver
-
getScriptEngineManager
- Specified by:
getScriptEngineManagerin interfaceScriptEngineResolver
-
getScriptEngine
Returns a cached script engine or creates a new script engine if no such engine is currently cached.GraalJS is deliberately never cached here - see issue #3174. It reports
THREADING = nullvia the JSR-223 factory parameter (seeisCachable(javax.script.ScriptEngine)), so a fresh engine is created for every call, and the caller is responsible for explicitly releasing it once done (seeScriptingEngines.disposeScriptEngine(javax.script.ScriptEngine)).An engine-level cache was tried twice for GraalJS (issues #3101, #3148) and both attempts had to be reverted: GraalJS never releases the native/heap-resident Truffle state behind a discarded engine via garbage collection alone, so any cache needs to explicitly close evicted entries - but GraalJS also enforces thread affinity (a Context is bound to its creating thread) and, separately, BPMN/DMN each keep their own long-lived cache of a
CompiledScripttied to whichever engine compiled it (seeSourceExecutableScript/CompiledExecutableScriptand DMN'sCachedCompiledScriptSupport). Any engine-level cache's own eviction timing (LRU capacity, or a GraalJS config change - see issue #3174) can end up closing an engine that one of those long-lived compiled-script caches still depends on, since the two caches have no way to coordinate their lifetimes. Not caching at all avoids this entirely: the decision of whether an engine may be closed is made once, locally, by whichever call site just used it - seeScriptingEngines.disposeScriptEngine(javax.script.ScriptEngine).- Specified by:
getScriptEnginein interfaceScriptEngineResolver- Parameters:
language- the language (such as 'groovy' for the script engine)- Returns:
- the cached engine or null if no script engine can be created for the given language
-
isJsEngineNameStale
Returnstrueif the cached engine's factory no longer matches the effective JavaScript engine name for the current configuration.The effective name is determined as follows:
- If
scriptEngineNameJavaScriptis explicitly configured, that name is used. - Otherwise, if the default JavaScript engine
(
ScriptingEngines.DEFAULT_JS_SCRIPTING_LANGUAGE, i.e. GraalJS) is available on the classpath, that is the effective name — a cached engine from a previous explicit configuration that has since been reset tonullis therefore correctly detected as stale. - Otherwise (default engine unavailable — fallback path in
getJavaScriptScriptEngine(java.lang.String)is in effect), the cached fallback engine is treated as not stale to prevent unnecessary recreation on every lookup.
If
configisnull(no process engine context available), the entry is conservatively treated as not stale, mirroring the pre-existing behavior for this edge case. - If
-
isDefaultJsEngineAvailable
protected boolean isDefaultJsEngineAvailable()Returnstrueif the default JavaScript engine (ScriptingEngines.DEFAULT_JS_SCRIPTING_LANGUAGE, i.e. GraalJS) appears in the JDKServiceLoader/SPI metadata already visible to theScriptEngineManager, without instantiating a new engine. Used byisJsEngineNameStale(javax.script.ScriptEngine, org.camunda.bpm.engine.impl.cfg.ProcessEngineConfigurationImpl)to correctly distinguish "no explicit engine configured, use the default" from "default unavailable, fallback is in effect".Treats a
nullScriptEngineManager.getEngineFactories()result (never returned by the JDK's own implementation, but possible for a custom/mockedScriptEngineManager) the same as an empty one - i.e. the default engine is unavailable. -
isJavaScriptAlias
-
getScriptEngine
-
getJavaScriptScriptEngine
-
getEngineByName
Resolves a script engine by name, giving GraalJS its own private, single-useorg.graalvm.polyglot.Engineinstead of going throughscriptEngineManager.getEngineByName(...)directly - see issue #3174.GraalJSScriptEngine.create()(which is whatScriptEngineManagercalls internally when no explicitEngineis supplied) implicitly participates in GraalVM's JVM-wide shared/pooled defaultEngine. Confirmed by experiment: two separately obtainedGraalJSScriptEngineinstances fromScriptEngineManager#getEngineByName("Graal.js")returngetPolyglotEngine() ==the exact same object. Also confirmed by experiment: closing only the JSR-223Context(whatGraalJSScriptEngine#close()does) never actually releases the native/heap-resident state GraalJS retains per execution - only closing the underlyingEnginedoes (seeScriptingEngines.disposeScriptEngine(javax.script.ScriptEngine)) - so closing that shared defaultEnginewould break every other GraalJS engine in the entire JVM, permanently, while never closing it leaks unboundedly. Giving each execution its own privateEngine(used for exactly oneScriptEngine, then closed alongside it) sidesteps this entirely: nothing else could ever be sharing it.nameis matched against every alias GraalJS's own factory registers (e.g."js","graal.js","ecmascript"- not just the canonicalScriptingEngines.GRAAL_JS_SCRIPT_ENGINE_NAME), viaisGraalJsAlias(String), so any of them - whether from a script task/DMN literal expression's language attribute or an explicitly configuredscriptEngineNameJavaScript- reach the substitution below; see issue #3174.That match is deliberately metadata-only (
ScriptEngineFactory.getNames()), never by first askingscriptEngineManagerfor an actual engine: doing the latter would itself construct a realGraalJSScriptEnginebound to GraalVM's shared defaultEnginejust to inspect it - and per the same experiments referenced above, closing only that probe'sContext(the most a shared engine ever allows) does not release its native/heap-resident state, so it would leak on every single lookup.Falls back to the plain
ScriptEngineManagerlookup for every other language, and for GraalJS itself if no matching factory is registered withscriptEngineManager(e.g. a classloader-isolated deployment where the caller-supplied manager has no GraalJS factory registered, even though GraalJS classes are reflectively loadable from this module's own classloader - seeScriptEngineNameJavaScriptTest#shouldFallbackToAnyEngineForJavaScriptIfDefaultUnavailable), or if the reflective construction itself fails (e.g. an incompatible GraalJS version without the expected API). -
isGraalJsAlias
ReturnstrueifscriptEngineManagerhas a GraalJS factory registered whoseScriptEngineFactory.getNames()containsname(case-insensitively) - i.e.nameis any alias GraalJS itself registers, not justScriptingEngines.GRAAL_JS_SCRIPT_ENGINE_NAME. Purely metadata-based - never instantiates aScriptEngine- seegetEngineByName(String). -
createGraalJsScriptEngineWithPrivateEngine
Constructs a GraalJSScriptEnginebound to a freshly created, privateorg.graalvm.polyglot.Engine- never the implicit JVM-wide shared default. Passingnullfor theContext.Builderargument letsGraalJSScriptEnginebuild its own default set of Context options (the same ones a plainScriptEngineManager#getEngineByName("Graal.js")lookup would use), so behavior is unaffected except for whichEnginebacks it.Accessed via reflection because
org.graalvm.polyglot/GraalJS classes are only a test-scope dependency of this module - seegetScriptEngine(String, boolean)Javadoc.- Returns:
- the constructed engine, or
nullif this GraalJS version doesn't expose the expectedEngine.Builder/GraalJSScriptEngine.create(Engine, Context.Builder)API, in which case the caller falls back to the plainScriptEngineManagerlookup.
-
isCachable
Allows checking whether the script engine can be cached. Cache if the engine declares thread-safety via theTHREADINGfactory parameter.GraalJS reports
THREADING = null, so it is - deliberately - never cached here. See thegetScriptEngine(String, boolean)Javadoc for why.- Parameters:
scriptEngine- the script engine to check.- Returns:
- true if the script engine may be cached.
-
configureScriptEngines
-
isGraalJs
- Returns:
trueifscriptEngine's factory reports the canonical GraalJS engine name. UnlikeisGraalJsAlias(String), this checks an already-resolved engine's own (fixed, alias-independent)ScriptEngineFactory.getEngineName(), so a plainequalsis sufficient here.
-
configureGroovyScriptEngine
Allows providing custom configuration for the groovy script engine.- Parameters:
scriptEngine- the groovy script engine to configure.
-
configureGraalJsScriptEngine
Allows providing custom configuration for the Graal JS script engine.- Parameters:
scriptEngine- the Graal JS script engine to configure.
-