Skip to content

Commit

Permalink
Simplify the Setting Scripts (#2007)
Browse files Browse the repository at this point in the history
- change signature of the include command to return an Object
- change the way Phoenicis accesses engine settings
- overhaul the EngineSettingsManager
  • Loading branch information
madoar authored Jun 30, 2019
1 parent 9bcacf0 commit d8b87d2
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 68 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,98 +19,128 @@
package org.phoenicis.engines;

import org.graalvm.polyglot.Value;
import org.phoenicis.repository.dto.*;
import org.phoenicis.scripts.session.InteractiveScriptSession;
import org.phoenicis.scripts.interpreter.ScriptInterpreter;
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 java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
* manages the engine settings
* Manages the engine settings
*/
public class EngineSettingsManager {
private final ScriptInterpreter scriptInterpreter;
private final PhoenicisScriptEngineFactory phoenicisScriptEngineFactory;
private final ExecutorService executorService;

/**
* constructor
* @param scriptInterpreter
* Constructor
*
* @param phoenicisScriptEngineFactory The used script engine factory
* @param executorService The executor service to allow for parallelization
*/
public EngineSettingsManager(ScriptInterpreter scriptInterpreter) {
this.scriptInterpreter = scriptInterpreter;
}
public EngineSettingsManager(PhoenicisScriptEngineFactory phoenicisScriptEngineFactory,
ExecutorService executorService) {
super();

/**
* fetches the required setting
* @param engineId setting ID (e.g. "glsl")
* @param settingId setting ID (e.g. "glsl")
* @param doneCallback callback which will be executed with the fetched setting
* @param errorCallback callback which will be executed if an error occurs
*/
public void getSetting(String engineId, String settingId, Consumer<EngineSetting> doneCallback,
Consumer<Exception> errorCallback) {
final InteractiveScriptSession interactiveScriptSession = scriptInterpreter.createInteractiveSession();

interactiveScriptSession.eval(
"include(\"engines." + engineId + ".settings." + settingId + "\"); new Setting();",
output -> {
final EngineSetting setting = ((Value) output).as(EngineSetting.class);
doneCallback.accept(setting);
}, errorCallback);
this.phoenicisScriptEngineFactory = phoenicisScriptEngineFactory;
this.executorService = executorService;
}

/**
* fetches the available engine settings
* @param repositoryDTO
* @param callback
* @param errorCallback callback which will be executed if an error occurs
* Fetches the available engine settings
*
* @param repositoryDTO The repository containing the 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) {
final InteractiveScriptSession interactiveScriptSession = scriptInterpreter.createInteractiveSession();
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 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);

interactiveScriptSession.eval(this.createFetchScript(repositoryDTO),
output -> callback.accept(((Value) output).as(Map.class)),
errorCallback);
final Value settingClass = (Value) phoenicisScriptEngine.evalAndReturn(include,
errorCallback);

return settingClass.newInstance().as(EngineSetting.class);
}, Collectors.toList())));

callback.accept(result);
});
}

/**
* retrieves a Javascript string which can be used to fetch the available settings
* @param repositoryDTO repository containing the settings
* @return Javascript
* Fetches a list of the setting parameters requires to fetch all settings in the given repository
*
* @param repositoryDTO The repository containing the settings
* @return A list containing all necessary setting parameters
*/
private String createFetchScript(RepositoryDTO repositoryDTO) {
private List<SettingConfig> fetchSettingConfigurations(RepositoryDTO repositoryDTO) {
// get engine CategoryDTOs
List<CategoryDTO> categoryDTOS = new ArrayList<>();
for (TypeDTO typeDTO : repositoryDTO.getTypes()) {
if (typeDTO.getId().equals("engines")) {
categoryDTOS = typeDTO.getCategories();
}
}
StringBuilder script = new StringBuilder();
script.append("(function () {\n");
script.append("var settings = {};\n");
for (CategoryDTO engine : categoryDTOS) {
final String engineId = engine.getId().replaceAll("^.*\\.", "");
for (ApplicationDTO applicationDTO : engine.getApplications()) {
if (applicationDTO.getId().equals("engines." + engineId + ".settings")) {
for (ScriptDTO scriptDTO : applicationDTO.getScripts()) {
script.append("include(\"engines." + engineId + ".settings."
+ scriptDTO.getId().replaceAll("^.*\\.", "") + "\");\n");
script.append("if (!(\"" + engineId + "\" in settings))\n");
script.append("{\n");
script.append("settings[\"" + engineId + "\"] = new java.util.ArrayList();\n");
script.append("}\n");
script.append("settings[\"" + engineId + "\"].add(new Setting());\n");
}
}
}
List<CategoryDTO> categoryDTOs = repositoryDTO.getTypes().stream()
.filter(typeDTO -> typeDTO.getId().equals("engines"))
.flatMap(typeDTO -> typeDTO.getCategories().stream())
.collect(Collectors.toList());

return categoryDTOs.stream()
// map category -> (engineId, application)
.flatMap(engine -> {
final String engineId = engine.getId().replaceAll("^.*\\.", "");

return engine.getApplications().stream()
.map(application -> new EngineInformation(engineId, application));
})
// filter to setting applications
.filter(engineInformation -> {
final String applicationId = engineInformation.application.getId();
final String settingIdPrefix = String.format("engines.%s.settings", engineInformation.engineId);

return applicationId.equals(settingIdPrefix);
})
// map (engineId, application) -> (engineId, settingId)
.flatMap(engineInformation -> engineInformation.application.getScripts().stream()
.map(script -> {
final String settingId = script.getId().replaceAll("^.*\\.", "");

return new SettingConfig(engineInformation.engineId, settingId);
}))
.collect(Collectors.toList());
}

private class EngineInformation {
public final String engineId;

public final ApplicationDTO application;

private EngineInformation(String engineId, ApplicationDTO application) {
this.engineId = engineId;
this.application = application;
}
script.append("return settings;\n");
script.append("})();\n");
}

private class SettingConfig {
public final String engineId;

return script.toString();
public final String settingId;

public SettingConfig(String engineId, String settingId) {
this.engineId = engineId;
this.settingId = settingId;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package org.phoenicis.engines;

import org.phoenicis.configuration.PhoenicisGlobalConfiguration;
import org.phoenicis.multithreading.MultithreadingConfiguration;
import org.phoenicis.scripts.ScriptsConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
Expand All @@ -32,6 +33,9 @@ public class EnginesConfiguration {
@Autowired
private PhoenicisGlobalConfiguration phoenicisGlobalConfiguration;

@Autowired
private MultithreadingConfiguration multithreadingConfiguration;

@Bean
public EnginesManager enginesSource() {
return new EnginesManager(scriptsConfiguration.scriptInterpreter(),
Expand All @@ -40,7 +44,8 @@ public EnginesManager enginesSource() {

@Bean
public EngineSettingsManager engineSettingsManager() {
return new EngineSettingsManager(scriptsConfiguration.scriptInterpreter());
return new EngineSettingsManager(scriptsConfiguration.graalScriptEngineFactory(),
multithreadingConfiguration.scriptExecutorService());
}

@Bean
Expand Down

0 comments on commit d8b87d2

Please sign in to comment.