Remove guice from ScriptService

Makes ScriptModule just a plain class that manages building the
ScriptSettings and ScriptService from plugins. When we *need*
to bind ScriptService with guice we bind it in a lambda.
This commit is contained in:
Nik Everett 2016-06-21 11:53:19 -04:00
parent 28fd684eef
commit 8925400f67
11 changed files with 123 additions and 157 deletions

View File

@ -225,7 +225,9 @@ public class Node implements Closeable {
for (final ExecutorBuilder<?> builder : threadPool.builders()) {
additionalSettings.addAll(builder.getRegisteredSettings());
}
final ScriptModule scriptModule = ScriptModule.create(settings, pluginsService.filterPlugins(ScriptPlugin.class));
final ResourceWatcherService resourceWatcherService = new ResourceWatcherService(settings, threadPool);
final ScriptModule scriptModule = ScriptModule.create(settings, environment, resourceWatcherService,
pluginsService.filterPlugins(ScriptPlugin.class));
additionalSettings.addAll(scriptModule.getSettings());
// this is as early as we can validate settings at this point. we already pass them to ScriptModule as well as ThreadPool
// so we might be late here already
@ -237,7 +239,6 @@ public class Node implements Closeable {
} catch (IOException ex) {
throw new IllegalStateException("Failed to created node environment", ex);
}
final ResourceWatcherService resourceWatcherService = new ResourceWatcherService(settings, threadPool);
resourcesToClose.add(resourceWatcherService);
final NetworkService networkService = new NetworkService(settings);
final ClusterService clusterService = new ClusterService(settings, settingsModule.getClusterSettings(), threadPool);
@ -253,7 +254,6 @@ public class Node implements Closeable {
final MonitorService monitorService = new MonitorService(settings, nodeEnvironment, threadPool);
modules.add(new NodeModule(this, monitorService));
modules.add(new NetworkModule(networkService, settings, false, namedWriteableRegistry));
modules.add(scriptModule);
modules.add(new DiscoveryModule(this.settings));
modules.add(new ClusterModule(this.settings, clusterService));
modules.add(new IndicesModule(namedWriteableRegistry));
@ -279,6 +279,7 @@ public class Node implements Closeable {
b.bind(ResourceWatcherService.class).toInstance(resourceWatcherService);
b.bind(CircuitBreakerService.class).toInstance(circuitBreakerService);
b.bind(BigArrays.class).toInstance(bigArrays);
b.bind(ScriptService.class).toInstance(scriptModule.getScriptService());
}
);
injector = modules.createInjector();

View File

@ -19,12 +19,13 @@
package org.elasticsearch.script;
import org.elasticsearch.common.inject.AbstractModule;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.plugins.ScriptPlugin;
import org.elasticsearch.watcher.ResourceWatcherService;
import java.util.ArrayList;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@ -34,57 +35,56 @@ import java.util.function.Function;
import java.util.stream.Collectors;
/**
* An {@link org.elasticsearch.common.inject.Module} which manages {@link ScriptEngineService}s, as well
* as named script
* Manages building {@link ScriptService} and {@link ScriptSettings} from a list of plugins.
*/
public class ScriptModule extends AbstractModule {
protected final ScriptContextRegistry scriptContextRegistry;
protected final ScriptEngineRegistry scriptEngineRegistry;
protected final ScriptSettings scriptSettings;
public ScriptModule(ScriptEngineService... services) {
this(Arrays.asList(services), Collections.emptyList());
}
public ScriptModule(List<ScriptEngineService> scriptEngineServices,
List<ScriptContext.Plugin> customScriptContexts) {
this.scriptContextRegistry = new ScriptContextRegistry(customScriptContexts);
this.scriptEngineRegistry = new ScriptEngineRegistry(scriptEngineServices);
this.scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
}
public class ScriptModule {
private final ScriptSettings scriptSettings;
private final ScriptService scriptService;
/**
* This method is called after all modules have been processed but before we actually validate all settings. This allows the
* script extensions to add all their settings.
* Build from {@linkplain ScriptPlugin}s. Convenient for normal use but not great for tests. See
* {@link ScriptModule#ScriptModule(Settings, Environment, ResourceWatcherService, List, List)} for easier use in tests.
*/
public List<Setting<?>> getSettings() {
ArrayList<Setting<?>> settings = new ArrayList<>();
scriptSettings.getScriptTypeSettings().forEach(settings::add);
scriptSettings.getScriptContextSettings().forEach(settings::add);
scriptSettings.getScriptLanguageSettings().forEach(settings::add);
settings.add(scriptSettings.getDefaultScriptLanguageSetting());
return settings;
}
@Override
protected void configure() {
ScriptSettings scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
bind(ScriptContextRegistry.class).toInstance(scriptContextRegistry);
bind(ScriptEngineRegistry.class).toInstance(scriptEngineRegistry);
bind(ScriptSettings.class).toInstance(scriptSettings);
bind(ScriptService.class).asEagerSingleton();
}
public static ScriptModule create(Settings settings, List<ScriptPlugin> scriptPlugins) {
public static ScriptModule create(Settings settings, Environment environment, ResourceWatcherService resourceWatcherService,
List<ScriptPlugin> scriptPlugins) {
Map<String, NativeScriptFactory> factoryMap = scriptPlugins.stream().flatMap(x -> x.getNativeScripts().stream())
.collect(Collectors.toMap(NativeScriptFactory::getName, Function.identity()));
NativeScriptEngineService nativeScriptEngineService = new NativeScriptEngineService(settings, factoryMap);
List<ScriptEngineService> scriptEngineServices = scriptPlugins.stream().map(x -> x.getScriptEngineService(settings))
.filter(Objects::nonNull).collect(Collectors.toList());
scriptEngineServices.add(nativeScriptEngineService);
return new ScriptModule(scriptEngineServices, scriptPlugins.stream().map(x -> x.getCustomScriptContexts())
.filter(Objects::nonNull).collect(Collectors.toList()));
List<ScriptContext.Plugin> plugins = scriptPlugins.stream().map(x -> x.getCustomScriptContexts()).filter(Objects::nonNull)
.collect(Collectors.toList());
return new ScriptModule(settings, environment, resourceWatcherService, scriptEngineServices, plugins);
}
/**
* Build {@linkplain ScriptEngineService} and {@linkplain ScriptContext.Plugin}.
*/
public ScriptModule(Settings settings, Environment environment, ResourceWatcherService resourceWatcherService,
List<ScriptEngineService> scriptEngineServices, List<ScriptContext.Plugin> customScriptContexts) {
ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(customScriptContexts);
ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(scriptEngineServices);
scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
try {
scriptService = new ScriptService(settings, environment, resourceWatcherService, scriptEngineRegistry, scriptContextRegistry,
scriptSettings);
} catch (IOException e) {
throw new RuntimeException("Couldn't setup ScriptService", e);
}
}
/**
* Extra settings for scripts.
*/
public List<Setting<?>> getSettings() {
return scriptSettings.getSettings();
}
/**
* Service responsible for managing scripts.
*/
public ScriptService getScriptService() {
return scriptService;
}
}

View File

@ -41,7 +41,6 @@ import org.elasticsearch.common.cache.RemovalListener;
import org.elasticsearch.common.cache.RemovalNotification;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.io.Streams;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
@ -72,7 +71,6 @@ import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import static java.util.Collections.unmodifiableMap;
@ -132,7 +130,6 @@ public class ScriptService extends AbstractComponent implements Closeable {
@Deprecated
public static final ParseField SCRIPT_INLINE = new ParseField("script");
@Inject
public ScriptService(Settings settings, Environment env,
ResourceWatcherService resourceWatcherService, ScriptEngineRegistry scriptEngineRegistry,
ScriptContextRegistry scriptContextRegistry, ScriptSettings scriptSettings) throws IOException {

View File

@ -142,12 +142,13 @@ public class ScriptSettings {
return scriptModeSettings;
}
public Iterable<Setting<Boolean>> getScriptTypeSettings() {
return Collections.unmodifiableCollection(SCRIPT_TYPE_SETTING_MAP.values());
}
public Iterable<Setting<Boolean>> getScriptContextSettings() {
return Collections.unmodifiableCollection(scriptContextSettingMap.values());
public List<Setting<?>> getSettings() {
List<Setting<?>> settings = new ArrayList<>();
settings.addAll(SCRIPT_TYPE_SETTING_MAP.values());
settings.addAll(scriptContextSettingMap.values());
settings.addAll(scriptLanguageSettings);
settings.add(defaultScriptLanguageSetting);
return settings;
}
public Iterable<Setting<Boolean>> getScriptLanguageSettings() {

View File

@ -22,16 +22,12 @@ package org.elasticsearch.script;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.inject.Injector;
import org.elasticsearch.common.inject.ModulesBuilder;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsModule;
import org.elasticsearch.env.Environment;
import org.elasticsearch.script.ScriptService.ScriptType;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.InternalSettingsPlugin;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.watcher.ResourceWatcherService;
import java.io.IOException;
@ -41,6 +37,9 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.notNullValue;
@ -49,28 +48,18 @@ public class NativeScriptTests extends ESTestCase {
Settings settings = Settings.builder()
.put("node.name", "testNativeScript")
.put(Environment.PATH_HOME_SETTING.getKey(), createTempDir())
.put(ScriptService.SCRIPT_AUTO_RELOAD_ENABLED_SETTING.getKey(), false)
.build();
ScriptModule scriptModule = new ScriptModule(new NativeScriptEngineService(settings,
Collections.singletonMap("my", new MyNativeScriptFactory())));
ScriptModule scriptModule = new ScriptModule(settings, new Environment(settings), null,
singletonList(new NativeScriptEngineService(settings, singletonMap("my", new MyNativeScriptFactory()))), emptyList());
List<Setting<?>> scriptSettings = scriptModule.getSettings();
scriptSettings.add(InternalSettingsPlugin.VERSION_CREATED);
SettingsModule settingsModule = new SettingsModule(settings, scriptSettings, Collections.emptyList());
final ThreadPool threadPool = new ThreadPool(settings);
Injector injector = new ModulesBuilder().add(
(b) -> {
b.bind(Environment.class).toInstance(new Environment(settings));
b.bind(ThreadPool.class).toInstance(threadPool);
},
new SettingsModule(settings),
scriptModule).createInjector();
ScriptService scriptService = injector.getInstance(ScriptService.class);
ClusterState state = ClusterState.builder(new ClusterName("_name")).build();
ExecutableScript executable = scriptService.executable(new Script("my", ScriptType.INLINE, NativeScriptEngineService.NAME, null),
ScriptContext.Standard.SEARCH, Collections.emptyMap(), state);
ExecutableScript executable = scriptModule.getScriptService().executable(
new Script("my", ScriptType.INLINE, NativeScriptEngineService.NAME, null), ScriptContext.Standard.SEARCH,
Collections.emptyMap(), state);
assertThat(executable.run().toString(), equalTo("test"));
terminate(injector.getInstance(ThreadPool.class));
}
public void testFineGrainedSettingsDontAffectNativeScripts() throws IOException {

View File

@ -29,7 +29,6 @@ import org.elasticsearch.common.ParsingException;
import org.elasticsearch.common.inject.AbstractModule;
import org.elasticsearch.common.inject.Injector;
import org.elasticsearch.common.inject.ModulesBuilder;
import org.elasticsearch.common.inject.util.Providers;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
@ -112,28 +111,29 @@ public class AggregatorParsingTests extends ESTestCase {
(b) -> {
b.bind(Environment.class).toInstance(new Environment(settings));
b.bind(ThreadPool.class).toInstance(threadPool);
}, settingsModule
, scriptModule, new IndicesModule(namedWriteableRegistry) {
b.bind(ScriptService.class).toInstance(scriptModule.getScriptService());
},
settingsModule,
new IndicesModule(namedWriteableRegistry) {
@Override
protected void configure() {
bindMapperExtension();
}
}, new SearchModule(settings, namedWriteableRegistry) {
@Override
protected void configureSearch() {
// Skip me
}
}, new IndexSettingsModule(index, settings),
@Override
protected void configure() {
bindMapperExtension();
}
}, new SearchModule(settings, namedWriteableRegistry) {
@Override
protected void configureSearch() {
// Skip me
}
}, new IndexSettingsModule(index, settings),
new AbstractModule() {
@Override
protected void configure() {
bind(ClusterService.class).toProvider(Providers.of(clusterService));
bind(CircuitBreakerService.class).to(NoneCircuitBreakerService.class);
bind(NamedWriteableRegistry.class).toInstance(namedWriteableRegistry);
}
}).createInjector();
new AbstractModule() {
@Override
protected void configure() {
bind(ClusterService.class).toInstance(clusterService);
bind(CircuitBreakerService.class).toInstance(new NoneCircuitBreakerService());
bind(NamedWriteableRegistry.class).toInstance(namedWriteableRegistry);
}
}).createInjector();
aggParsers = injector.getInstance(AggregatorParsers.class);
// create some random type with some default field, those types will
// stick around for all of the subclasses

View File

@ -25,7 +25,6 @@ import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.ParseFieldMatcher;
import org.elasticsearch.common.inject.AbstractModule;
import org.elasticsearch.common.inject.Injector;
import org.elasticsearch.common.inject.ModulesBuilder;
import org.elasticsearch.common.inject.util.Providers;
@ -140,31 +139,26 @@ public abstract class BaseAggregationTestCase<AB extends AbstractAggregationBuil
(b) -> {
b.bind(Environment.class).toInstance(new Environment(settings));
b.bind(ThreadPool.class).toInstance(threadPool);
b.bind(ScriptService.class).toInstance(scriptModule.getScriptService());
b.bind(ClusterService.class).toProvider(Providers.of(clusterService));
b.bind(CircuitBreakerService.class).to(NoneCircuitBreakerService.class);
b.bind(NamedWriteableRegistry.class).toInstance(namedWriteableRegistry);
},
settingsModule,
scriptModule,
new IndicesModule(namedWriteableRegistry) {
@Override
protected void configure() {
bindMapperExtension();
}
}, new SearchModule(settings, namedWriteableRegistry) {
},
new SearchModule(settings, namedWriteableRegistry) {
@Override
protected void configureSearch() {
// Skip me
}
},
new IndexSettingsModule(index, settings),
new AbstractModule() {
@Override
protected void configure() {
bind(ClusterService.class).toProvider(Providers.of(clusterService));
bind(CircuitBreakerService.class).to(NoneCircuitBreakerService.class);
bind(NamedWriteableRegistry.class).toInstance(namedWriteableRegistry);
}
}
new IndexSettingsModule(index, settings)
).createInjector();
}

View File

@ -134,13 +134,16 @@ public class SearchSourceBuilderTests extends ESTestCase {
(b) -> {
b.bind(Environment.class).toInstance(new Environment(settings));
b.bind(ThreadPool.class).toInstance(threadPool);
}, settingsModule,
scriptModule, new IndicesModule(namedWriteableRegistry) {
b.bind(ScriptService.class).toInstance(scriptModule.getScriptService());
},
settingsModule,
new IndicesModule(namedWriteableRegistry) {
@Override
protected void configure() {
bindMapperExtension();
}
}, new SearchModule(settings, namedWriteableRegistry) {
},
new SearchModule(settings, namedWriteableRegistry) {
@Override
protected void configureSearch() {
// Skip me

View File

@ -75,6 +75,8 @@ import java.util.Collections;
import java.util.List;
import java.util.function.Supplier;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static org.hamcrest.Matchers.containsString;
/**
@ -93,7 +95,9 @@ public class TemplateQueryParserTests extends ESTestCase {
.put(Environment.PATH_CONF_SETTING.getKey(), this.getDataPath("config"))
.put("node.name", getClass().getName())
.put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT)
.put(ScriptService.SCRIPT_AUTO_RELOAD_ENABLED_SETTING.getKey(), false)
.build();
Environment environment = new Environment(settings);
final Client proxy = (Client) Proxy.newProxyInstance(
Client.class.getClassLoader(),
new Class<?>[]{Client.class}, (proxy1, method, args) -> {
@ -102,15 +106,18 @@ public class TemplateQueryParserTests extends ESTestCase {
IndexSettings idxSettings = IndexSettingsModule.newIndexSettings("test", settings);
Index index = idxSettings.getIndex();
// TODO: make this use a mock engine instead of mustache and it will no longer be messy!
ScriptModule scriptModule = new ScriptModule(new MustacheScriptEngineService(settings));
ScriptModule scriptModule = new ScriptModule(settings, environment, null, singletonList(new MustacheScriptEngineService(settings)),
emptyList());
List<Setting<?>> scriptSettings = scriptModule.getSettings();
scriptSettings.add(InternalSettingsPlugin.VERSION_CREATED);
SettingsModule settingsModule = new SettingsModule(settings, scriptSettings, Collections.emptyList());
final ThreadPool threadPool = new ThreadPool(settings);
injector = new ModulesBuilder().add(
(b) -> {
b.bind(Environment.class).toInstance(new Environment(settings));
b.bind(ThreadPool.class).toInstance(threadPool);
b.bind(ThreadPool.class).toInstance(new ThreadPool(settings));
b.bind(Client.class).toInstance(proxy); // not needed here
Multibinder.newSetBinder(b, ScoreFunctionParser.class);
b.bind(ClusterService.class).toProvider(Providers.of((ClusterService) null));
b.bind(CircuitBreakerService.class).to(NoneCircuitBreakerService.class);
},
settingsModule,
new SearchModule(settings, new NamedWriteableRegistry()) {
@ -119,21 +126,10 @@ public class TemplateQueryParserTests extends ESTestCase {
// skip so we don't need transport
}
},
scriptModule,
new IndexSettingsModule(index, settings),
new AbstractModule() {
@Override
protected void configure() {
bind(Client.class).toInstance(proxy); // not needed here
Multibinder.newSetBinder(binder(), ScoreFunctionParser.class);
bind(ClusterService.class).toProvider(Providers.of((ClusterService) null));
bind(CircuitBreakerService.class).to(NoneCircuitBreakerService.class);
}
}
new IndexSettingsModule(index, settings)
).createInjector();
AnalysisService analysisService = new AnalysisRegistry(null, new Environment(settings)).build(idxSettings);
ScriptService scriptService = injector.getInstance(ScriptService.class);
AnalysisService analysisService = new AnalysisRegistry(null, environment).build(idxSettings);
SimilarityService similarityService = new SimilarityService(idxSettings, Collections.emptyMap());
MapperRegistry mapperRegistry = new IndicesModule(new NamedWriteableRegistry()).getMapperRegistry();
MapperService mapperService = new MapperService(idxSettings, analysisService, similarityService, mapperRegistry, () ->
@ -153,7 +149,7 @@ public class TemplateQueryParserTests extends ESTestCase {
});
IndicesQueriesRegistry indicesQueriesRegistry = injector.getInstance(IndicesQueriesRegistry.class);
contextFactory = () -> new QueryShardContext(idxSettings, bitsetFilterCache, indexFieldDataService, mapperService,
similarityService, scriptService, indicesQueriesRegistry, proxy, null, null);
similarityService, scriptModule.getScriptService(), indicesQueriesRegistry, proxy, null, null);
}
@Override

View File

@ -901,7 +901,6 @@ public abstract class AbstractQueryTestCase<QB extends AbstractQueryBuilder<QB>>
bindMapperExtension();
}
},
scriptModule,
new IndexSettingsModule(index, indexSettings),
searchModule,
new AbstractModule() {
@ -919,7 +918,7 @@ public abstract class AbstractQueryTestCase<QB extends AbstractQueryBuilder<QB>>
IndexScopedSettings indexScopedSettings = injector.getInstance(IndexScopedSettings.class);
idxSettings = IndexSettingsModule.newIndexSettings(index, indexSettings, indexScopedSettings);
AnalysisService analysisService = new AnalysisRegistry(null, new Environment(settings)).build(idxSettings);
scriptService = injector.getInstance(ScriptService.class);
scriptService = scriptModule.getScriptService();
similarityService = new SimilarityService(idxSettings, Collections.emptyMap());
MapperRegistry mapperRegistry = injector.getInstance(MapperRegistry.class);
mapperService = new MapperService(idxSettings, analysisService, similarityService, mapperRegistry,

View File

@ -58,11 +58,8 @@ import org.elasticsearch.index.analysis.AnalysisService;
import org.elasticsearch.indices.IndicesService;
import org.elasticsearch.indices.analysis.AnalysisModule;
import org.elasticsearch.script.MockScriptEngine;
import org.elasticsearch.script.ScriptContextRegistry;
import org.elasticsearch.script.ScriptEngineRegistry;
import org.elasticsearch.script.ScriptModule;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptSettings;
import org.elasticsearch.search.MockSearchService;
import org.elasticsearch.test.junit.listeners.LoggingListener;
import org.elasticsearch.test.junit.listeners.ReproduceInfoPrinter;
@ -97,6 +94,8 @@ import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static org.elasticsearch.common.util.CollectionUtils.arrayAsArrayList;
import static org.hamcrest.Matchers.equalTo;
@ -796,25 +795,12 @@ public abstract class ESTestCase extends LuceneTestCase {
}
public static ScriptModule newTestScriptModule() {
return new ScriptModule(new MockScriptEngine()) {
@Override
protected void configure() {
Settings settings = Settings.builder()
.put(Environment.PATH_HOME_SETTING.getKey(), createTempDir())
// no file watching, so we don't need a ResourceWatcherService
.put(ScriptService.SCRIPT_AUTO_RELOAD_ENABLED_SETTING.getKey(), false)
.build();
bind(ScriptEngineRegistry.class).toInstance(scriptEngineRegistry);
bind(ScriptContextRegistry.class).toInstance(scriptContextRegistry);
bind(ScriptSettings.class).toInstance(scriptSettings);
try {
ScriptService scriptService = new ScriptService(settings, new Environment(settings), null,
scriptEngineRegistry, scriptContextRegistry, scriptSettings);
bind(ScriptService.class).toInstance(scriptService);
} catch (IOException e) {
throw new IllegalStateException("error while binding ScriptService", e);
}
}
};
Settings settings = Settings.builder()
.put(Environment.PATH_HOME_SETTING.getKey(), createTempDir())
// no file watching, so we don't need a ResourceWatcherService
.put(ScriptService.SCRIPT_AUTO_RELOAD_ENABLED_SETTING.getKey(), false)
.build();
Environment environment = new Environment(settings);
return new ScriptModule(settings, environment, null, singletonList(new MockScriptEngine()), emptyList());
}
}