package org.junit.jupiter.engine.script;
import static org.apiguardian.api.API.Status.INTERNAL;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javax.script.Bindings;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import org.apiguardian.api.API;
import org.junit.platform.commons.util.Preconditions;
@API(status = INTERNAL, since = "5.1")
public class ScriptExecutionManager {
private final ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
private final ConcurrentMap<String, ScriptEngine> scriptEngines = new ConcurrentHashMap<>();
private final ConcurrentMap<Script, CompiledScript> compiledScripts = new ConcurrentHashMap<>();
private final ScriptAccessor systemPropertyAccessor = new ScriptAccessor.SystemPropertyAccessor();
private final ScriptAccessor environmentVariableAccessor = new ScriptAccessor.EnvironmentVariableAccessor();
boolean forceScriptEvaluation = false;
public Object evaluate(Script script, Bindings bindings) throws ScriptException {
CompiledScript compiledScript = compiledScripts.get(script);
if (compiledScript == null) {
String source = script.getSource();
ScriptEngine scriptEngine = scriptEngines.computeIfAbsent(script.getEngine(), this::createScriptEngine);
if (!(scriptEngine instanceof Compilable) || forceScriptEvaluation) {
return scriptEngine.eval(source, bindings);
}
compiledScript = ((Compilable) scriptEngine).compile(source);
compiledScripts.putIfAbsent(script, compiledScript);
}
return compiledScript.eval(bindings);
}
ScriptEngine createScriptEngine(String engine) {
ScriptEngine scriptEngine = scriptEngineManager.getEngineByName(engine);
if (scriptEngine == null) {
scriptEngine = scriptEngineManager.getEngineByExtension(engine);
}
if (scriptEngine == null) {
scriptEngine = scriptEngineManager.getEngineByMimeType(engine);
}
Preconditions.notNull(scriptEngine, () -> "Script engine not found: " + engine);
Bindings bindings = scriptEngine.getBindings(ScriptContext.GLOBAL_SCOPE);
bindings.put(Script.BIND_SYSTEM_PROPERTY, systemPropertyAccessor);
bindings.put(Script.BIND_SYSTEM_ENVIRONMENT, environmentVariableAccessor);
return scriptEngine;
}
boolean isCompiledScriptsEmpty() {
return compiledScripts.isEmpty();
}
}