-
Notifications
You must be signed in to change notification settings - Fork 74
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rewrite the Script Engine API #2107
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package org.phoenicis.engines; | ||
|
||
import org.graalvm.polyglot.Value; | ||
import org.phoenicis.scripts.engine.implementation.PhoenicisScriptEngine; | ||
import org.phoenicis.scripts.engine.implementation.TypedScriptEngine; | ||
|
||
public class EngineSettingScriptEngine implements TypedScriptEngine<EngineSetting> { | ||
private final PhoenicisScriptEngine<Value> scriptEngine; | ||
|
||
public EngineSettingScriptEngine(PhoenicisScriptEngine<Value> scriptEngine) { | ||
super(); | ||
|
||
this.scriptEngine = scriptEngine; | ||
} | ||
|
||
@Override | ||
public EngineSetting evaluate(String scriptId) { | ||
final String script = String.format("include(\"%s\")", scriptId); | ||
|
||
return scriptEngine.evaluate(script).newInstance().as(EngineSetting.class); | ||
} | ||
} | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,12 +18,12 @@ | |
|
||
package org.phoenicis.engines; | ||
|
||
import org.graalvm.polyglot.Value; | ||
import org.phoenicis.repository.dto.ApplicationDTO; | ||
import org.phoenicis.repository.dto.CategoryDTO; | ||
import org.phoenicis.repository.dto.RepositoryDTO; | ||
import org.phoenicis.scripts.engine.PhoenicisScriptEngineFactory; | ||
import org.phoenicis.scripts.engine.implementation.PhoenicisScriptEngine; | ||
import org.phoenicis.scripts.engine.implementation.TypedScriptEngine; | ||
import org.phoenicis.scripts.engine.implementation.TypedScriptEngineFactory; | ||
import org.phoenicis.scripts.exceptions.ScriptException; | ||
|
||
import java.util.List; | ||
import java.util.Map; | ||
|
@@ -35,49 +35,52 @@ | |
* Manages the engine settings | ||
*/ | ||
public class EngineSettingsManager { | ||
private final PhoenicisScriptEngineFactory phoenicisScriptEngineFactory; | ||
private final TypedScriptEngineFactory typedScriptEngineFactory; | ||
private final ExecutorService executorService; | ||
|
||
/** | ||
* Constructor | ||
* | ||
* @param phoenicisScriptEngineFactory The used script engine factory | ||
* @param executorService The executor service to allow for parallelization | ||
* @param typedScriptEngineFactory The used script engine factory | ||
* @param executorService The executor service to allow for parallelization | ||
*/ | ||
public EngineSettingsManager(PhoenicisScriptEngineFactory phoenicisScriptEngineFactory, | ||
ExecutorService executorService) { | ||
public EngineSettingsManager(TypedScriptEngineFactory typedScriptEngineFactory, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This class shows an example how I intend to use the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does it mean that we cannot access e.g. applications and engines via the same script engine? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. We will need to provide a dedicated There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Understood. So this is also because we want to keep the APIs in the modules and not centralize them in phoenicis-scripts (we discussed this somewhere else). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
No the reason why I want to implement a dedicated I still plan to move all application types (and ideally also the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I thought @qparis doesn't like this? |
||
ExecutorService executorService) { | ||
super(); | ||
|
||
this.phoenicisScriptEngineFactory = phoenicisScriptEngineFactory; | ||
this.typedScriptEngineFactory = typedScriptEngineFactory; | ||
this.executorService = executorService; | ||
} | ||
|
||
/** | ||
* Fetches the available engine settings | ||
* | ||
* @param repositoryDTO The repository containing the engine settings | ||
* @param callback The callback which recieves the found engine settings | ||
* @param callback The callback which recieves the found engine settings | ||
* @param errorCallback The callback which will be executed if an error occurs | ||
*/ | ||
public void fetchAvailableEngineSettings(RepositoryDTO repositoryDTO, | ||
Consumer<Map<String, List<EngineSetting>>> callback, Consumer<Exception> errorCallback) { | ||
Consumer<Map<String, List<EngineSetting>>> callback, Consumer<Exception> errorCallback) { | ||
executorService.execute(() -> { | ||
final List<SettingConfig> configurations = fetchSettingConfigurations(repositoryDTO); | ||
|
||
// the script engine needs to be created inside the correct thread otherwise GraalJS throws an error | ||
final PhoenicisScriptEngine phoenicisScriptEngine = phoenicisScriptEngineFactory.createEngine(); | ||
final TypedScriptEngine<EngineSetting> phoenicisScriptEngine = typedScriptEngineFactory.createScriptEngine(EngineSetting.class); | ||
|
||
final Map<String, List<EngineSetting>> result = configurations.stream() | ||
.collect(Collectors.groupingBy( | ||
configuration -> configuration.engineId, | ||
Collectors.mapping(configuration -> { | ||
final String include = String.format("include(\"engines.%s.settings.%s\");", | ||
configuration.engineId, configuration.settingId); | ||
final String scriptId = String.format("engines.%s.settings.%s", configuration.engineId, configuration.settingId); | ||
|
||
final Value settingClass = (Value) phoenicisScriptEngine.evalAndReturn(include, | ||
errorCallback); | ||
try { | ||
return phoenicisScriptEngine.evaluate(scriptId); | ||
} catch (ScriptException se) { | ||
errorCallback.accept(se); | ||
|
||
return settingClass.newInstance().as(EngineSetting.class); | ||
// rethrow exception | ||
throw se; | ||
} | ||
}, Collectors.toList()))); | ||
|
||
callback.accept(result); | ||
|
@@ -122,7 +125,7 @@ private List<SettingConfig> fetchSettingConfigurations(RepositoryDTO repositoryD | |
.collect(Collectors.toList()); | ||
} | ||
|
||
private class EngineInformation { | ||
private static class EngineInformation { | ||
public final String engineId; | ||
|
||
public final ApplicationDTO application; | ||
|
@@ -133,7 +136,7 @@ private EngineInformation(String engineId, ApplicationDTO application) { | |
} | ||
} | ||
|
||
private class SettingConfig { | ||
private static class SettingConfig { | ||
public final String engineId; | ||
|
||
public final String settingId; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,46 +1,22 @@ | ||
package org.phoenicis.scripts.engine; | ||
|
||
import org.graalvm.polyglot.Value; | ||
import org.phoenicis.scripts.engine.implementation.GraalEngineType; | ||
import org.phoenicis.scripts.engine.implementation.PhoenicisScriptEngine; | ||
import org.phoenicis.scripts.engine.implementation.PolyglotScriptEngine; | ||
|
||
import java.util.Map; | ||
|
||
/** | ||
* The supported script engine types | ||
* A script engine type supported by Phoenicis | ||
* | ||
* @param <T> The internal script result type used by the script engine | ||
*/ | ||
public enum ScriptEngineType { | ||
GRAAL("graal.js") { | ||
@Override | ||
public PhoenicisScriptEngine createScriptEngine() { | ||
return new PolyglotScriptEngine("js", | ||
Map.of("js.nashorn-compat", "true", | ||
"js.experimental-foreign-object-prototype", "true")); | ||
} | ||
}; | ||
public interface ScriptEngineType<T> { | ||
// convenience instance | ||
ScriptEngineType<Value> GRAAL = new GraalEngineType(); | ||
|
||
/** | ||
* The name of the script engine type | ||
*/ | ||
private final String name; | ||
|
||
/** | ||
* Constructor | ||
* Creates a new script engine | ||
* | ||
* @param name The name of the script engine type | ||
* @return The created script engine | ||
*/ | ||
ScriptEngineType(String name) { | ||
this.name = name; | ||
} | ||
|
||
/** | ||
* Creates a new instance of the {@link ScriptEngineType} | ||
* | ||
* @return The new instance of the {@link ScriptEngineType} | ||
*/ | ||
public abstract PhoenicisScriptEngine createScriptEngine(); | ||
|
||
@Override | ||
public String toString() { | ||
return this.name; | ||
} | ||
} | ||
PhoenicisScriptEngine<T> createScriptEngine(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package org.phoenicis.scripts.engine.implementation; | ||
|
||
import org.graalvm.polyglot.Value; | ||
import org.phoenicis.scripts.engine.ScriptEngineType; | ||
|
||
import java.util.Map; | ||
|
||
public class GraalEngineType implements ScriptEngineType<Value> { | ||
@Override | ||
public PhoenicisScriptEngine<Value> createScriptEngine() { | ||
return new PolyglotScriptEngine("js", | ||
Map.of("js.nashorn-compat", "true", | ||
"js.experimental-foreign-object-prototype", "true")); | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "graal.js"; | ||
} | ||
} | ||
Comment on lines
+8
to
+20
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here the |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,23 +18,25 @@ | |
|
||
package org.phoenicis.scripts.engine.implementation; | ||
|
||
import com.google.common.util.concurrent.Runnables; | ||
|
||
import java.io.InputStreamReader; | ||
import java.util.function.Consumer; | ||
|
||
public interface PhoenicisScriptEngine { | ||
void eval(InputStreamReader inputStreamReader, Consumer<Exception> errorCallback); | ||
|
||
void eval(String script, Runnable doneCallback, Consumer<Exception> errorCallback); | ||
|
||
default void eval(String script, Consumer<Exception> errorCallback) { | ||
eval(script, Runnables.doNothing(), errorCallback); | ||
} | ||
|
||
Object evalAndReturn(String line, Consumer<Exception> errorCallback); | ||
|
||
void put(String name, Object object, Consumer<Exception> errorCallback); | ||
|
||
void addErrorHandler(Consumer<Exception> errorHandler); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because I'm removing the |
||
/** | ||
* A script engine used by Phoenicis | ||
* | ||
* @param <R> The internal script result type | ||
*/ | ||
public interface PhoenicisScriptEngine<R> { | ||
/** | ||
* Sets a global value for the given key (variable) in the script context | ||
* | ||
* @param key The variable name in the script context | ||
* @param value The corresponding value | ||
*/ | ||
void put(String key, Object value); | ||
|
||
/** | ||
* Evaluates the given script and returns its result | ||
* | ||
* @param script The script | ||
* @return The result of the evaluated script | ||
*/ | ||
R evaluate(String script); | ||
} | ||
Comment on lines
+21
to
42
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here the
TypedScriptEngine
for theEngineSetting
application class