Browse Source

Simplify ScriptModule and script registration (#18903)

Registering a script engine or native scripts still uses Guice today
and is much more complicated than needed. This change moves to a pull
based model where script plugins have to implement a dedicated interface
`ScriptPlugin` and defines simple getter returning instances rather than
classes.
Simon Willnauer 9 years ago
parent
commit
18ff051ad5
56 changed files with 527 additions and 467 deletions
  1. 2 2
      core/src/main/java/org/elasticsearch/node/Node.java
  2. 9 1
      core/src/main/java/org/elasticsearch/plugins/Plugin.java
  3. 10 0
      core/src/main/java/org/elasticsearch/plugins/PluginsService.java
  4. 55 0
      core/src/main/java/org/elasticsearch/plugins/ScriptPlugin.java
  5. 5 4
      core/src/main/java/org/elasticsearch/script/NativeScriptEngineService.java
  6. 7 2
      core/src/main/java/org/elasticsearch/script/NativeScriptFactory.java
  7. 4 1
      core/src/main/java/org/elasticsearch/script/ScriptContextRegistry.java
  8. 15 55
      core/src/main/java/org/elasticsearch/script/ScriptEngineRegistry.java
  9. 8 1
      core/src/main/java/org/elasticsearch/script/ScriptEngineService.java
  10. 27 50
      core/src/main/java/org/elasticsearch/script/ScriptModule.java
  11. 4 3
      core/src/main/java/org/elasticsearch/script/ScriptService.java
  12. 2 4
      core/src/test/java/org/elasticsearch/index/IndexModuleTests.java
  13. 12 3
      core/src/test/java/org/elasticsearch/index/WaitUntilRefreshIT.java
  14. 26 0
      core/src/test/java/org/elasticsearch/plugins/PluginsServiceTests.java
  15. 2 3
      core/src/test/java/org/elasticsearch/script/FileScriptTests.java
  16. 11 5
      core/src/test/java/org/elasticsearch/script/NativeScriptTests.java
  17. 2 5
      core/src/test/java/org/elasticsearch/script/ScriptContextTests.java
  18. 28 7
      core/src/test/java/org/elasticsearch/script/ScriptFieldIT.java
  19. 1 6
      core/src/test/java/org/elasticsearch/script/ScriptModesTests.java
  20. 7 12
      core/src/test/java/org/elasticsearch/script/ScriptServiceTests.java
  21. 3 7
      core/src/test/java/org/elasticsearch/script/ScriptSettingsTests.java
  22. 11 3
      core/src/test/java/org/elasticsearch/search/SearchTimeoutIT.java
  23. 1 32
      core/src/test/java/org/elasticsearch/search/aggregations/AggregatorParsingTests.java
  24. 1 32
      core/src/test/java/org/elasticsearch/search/aggregations/BaseAggregationTestCase.java
  25. 1 31
      core/src/test/java/org/elasticsearch/search/aggregations/BasePipelineAggregationTestCase.java
  26. 17 4
      core/src/test/java/org/elasticsearch/search/aggregations/bucket/DateScriptMocks.java
  27. 11 3
      core/src/test/java/org/elasticsearch/search/aggregations/bucket/IpRangeIT.java
  28. 7 4
      core/src/test/java/org/elasticsearch/search/aggregations/bucket/SignificantTermsSignificanceScoreIT.java
  29. 15 10
      core/src/test/java/org/elasticsearch/search/aggregations/metrics/AvgIT.java
  30. 20 11
      core/src/test/java/org/elasticsearch/search/aggregations/metrics/SumIT.java
  31. 11 4
      core/src/test/java/org/elasticsearch/search/aggregations/metrics/ValueCountIT.java
  32. 1 31
      core/src/test/java/org/elasticsearch/search/builder/SearchSourceBuilderTests.java
  33. 5 0
      core/src/test/java/org/elasticsearch/search/functionscore/ExplainableScriptIT.java
  34. 10 3
      core/src/test/java/org/elasticsearch/search/functionscore/ExplainableScriptPlugin.java
  35. 2 3
      core/src/test/java/org/elasticsearch/search/sort/AbstractSortTestCase.java
  36. 13 4
      core/src/test/java/org/elasticsearch/update/UpdateByNativeScriptIT.java
  37. 35 18
      core/src/test/java/org/elasticsearch/update/UpdateIT.java
  38. 7 4
      modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionPlugin.java
  39. 12 10
      modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionScriptEngineService.java
  40. 7 3
      modules/lang-groovy/src/main/java/org/elasticsearch/script/groovy/GroovyPlugin.java
  41. 0 4
      modules/lang-groovy/src/main/java/org/elasticsearch/script/groovy/GroovyScriptEngineService.java
  42. 7 4
      modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/MustachePlugin.java
  43. 5 3
      modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/MustacheScriptEngineService.java
  44. 2 3
      modules/lang-mustache/src/test/java/org/elasticsearch/messy/tests/TemplateQueryParserTests.java
  45. 7 4
      modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessPlugin.java
  46. 9 6
      modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngineService.java
  47. 7 3
      plugins/lang-javascript/src/main/java/org/elasticsearch/plugin/javascript/JavaScriptPlugin.java
  48. 0 4
      plugins/lang-javascript/src/main/java/org/elasticsearch/script/javascript/JavaScriptScriptEngineService.java
  49. 7 3
      plugins/lang-python/src/main/java/org/elasticsearch/plugin/python/PythonPlugin.java
  50. 0 5
      plugins/lang-python/src/main/java/org/elasticsearch/script/python/PythonScriptEngineService.java
  51. 2 5
      qa/smoke-test-ingest-with-all-dependencies/src/test/java/org/elasticsearch/ingest/AbstractScriptTestCase.java
  52. 14 10
      test/framework/src/main/java/org/elasticsearch/script/MockScriptEngine.java
  53. 5 0
      test/framework/src/main/java/org/elasticsearch/search/aggregations/bucket/script/NativeSignificanceScoreScriptNoParams.java
  54. 5 0
      test/framework/src/main/java/org/elasticsearch/search/aggregations/bucket/script/NativeSignificanceScoreScriptWithParams.java
  55. 1 32
      test/framework/src/main/java/org/elasticsearch/test/AbstractQueryTestCase.java
  56. 29 0
      test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java

+ 2 - 2
core/src/main/java/org/elasticsearch/node/Node.java

@@ -89,6 +89,7 @@ import org.elasticsearch.node.service.NodeService;
 import org.elasticsearch.plugins.Plugin;
 import org.elasticsearch.plugins.PluginsModule;
 import org.elasticsearch.plugins.PluginsService;
+import org.elasticsearch.plugins.ScriptPlugin;
 import org.elasticsearch.repositories.RepositoriesModule;
 import org.elasticsearch.rest.RestController;
 import org.elasticsearch.script.ScriptModule;
@@ -213,7 +214,7 @@ public class Node implements Closeable {
         final NetworkService networkService = new NetworkService(settings);
         final List<ExecutorBuilder<?>> executorBuilders = pluginsService.getExecutorBuilders(settings);
         final ThreadPool threadPool = new ThreadPool(settings, executorBuilders.toArray(new ExecutorBuilder[0]));
-
+        final ScriptModule scriptModule = ScriptModule.create(settings, pluginsService.filterPlugins(ScriptPlugin.class));
         NamedWriteableRegistry namedWriteableRegistry = new NamedWriteableRegistry();
         boolean success = false;
         try {
@@ -231,7 +232,6 @@ public class Node implements Closeable {
             modules.add(new EnvironmentModule(environment));
             modules.add(new NodeModule(this, monitorService));
             modules.add(new NetworkModule(networkService, settings, false, namedWriteableRegistry));
-            ScriptModule scriptModule = new ScriptModule();
             modules.add(scriptModule);
             modules.add(new NodeEnvironmentModule(nodeEnvironment));
             modules.add(new ClusterNameModule(this.settings));

+ 9 - 1
core/src/main/java/org/elasticsearch/plugins/Plugin.java

@@ -23,8 +23,8 @@ import org.elasticsearch.common.component.LifecycleComponent;
 import org.elasticsearch.common.inject.Module;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.index.IndexModule;
+import org.elasticsearch.script.ScriptModule;
 import org.elasticsearch.threadpool.ExecutorBuilder;
-import org.elasticsearch.threadpool.ThreadPool;
 
 import java.util.Collection;
 import java.util.Collections;
@@ -84,6 +84,14 @@ public abstract class Plugin {
     @Deprecated
     public final void onModule(IndexModule indexModule) {}
 
+    /**
+     * Old-style guice scripting extension point.
+     *
+     * @deprecated implement {@link ScriptPlugin} instead
+     */
+    @Deprecated
+    public final void onModule(ScriptModule module) {}
+
     /**
      * Provides the list of this plugin's custom thread pools, empty if
      * none.

+ 10 - 0
core/src/main/java/org/elasticsearch/plugins/PluginsService.java

@@ -40,6 +40,9 @@ import org.elasticsearch.common.settings.Setting;
 import org.elasticsearch.common.settings.Setting.Property;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.index.IndexModule;
+import org.elasticsearch.script.NativeScriptFactory;
+import org.elasticsearch.script.ScriptContext;
+import org.elasticsearch.script.ScriptEngineService;
 import org.elasticsearch.threadpool.ExecutorBuilder;
 
 import java.io.IOException;
@@ -60,6 +63,8 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import static org.elasticsearch.common.io.FileSystemUtils.isAccessibleDirectory;
 
@@ -440,4 +445,9 @@ public class PluginsService extends AbstractComponent {
             throw new ElasticsearchException("Failed to load plugin class [" + pluginClass.getName() + "]", e);
         }
     }
+
+    public <T> List<T> filterPlugins(Class<T> type) {
+        return plugins.stream().filter(x -> type.isAssignableFrom(x.v2().getClass()))
+            .map(p -> ((T)p.v2())).collect(Collectors.toList());
+    }
 }

+ 55 - 0
core/src/main/java/org/elasticsearch/plugins/ScriptPlugin.java

@@ -0,0 +1,55 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.elasticsearch.plugins;
+
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.script.NativeScriptFactory;
+import org.elasticsearch.script.ScriptContext;
+import org.elasticsearch.script.ScriptEngineService;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * An additional extension point to {@link Plugin}. Plugins extending the scripting functionality must implement this inteface
+ * to provide access to script engines or script factories.
+ */
+public interface ScriptPlugin {
+
+    /**
+     * Returns a {@link ScriptEngineService} instance or <code>null</code> if this plugin doesn't add a new script engine
+     */
+    default ScriptEngineService getScriptEngineService(Settings settings) {
+        return null;
+    }
+
+    /**
+     * Returns a list of {@link NativeScriptFactory} instances.
+     */
+    default List<NativeScriptFactory> getNativeScripts() {
+        return Collections.emptyList();
+    }
+
+    /**
+     * Returns a {@link ScriptContext.Plugin} instance or <code>null</code> if this plugin doesn't add a new script context plugin
+     */
+    default ScriptContext.Plugin getCustomScriptContexts() {
+        return null;
+    }
+}

+ 5 - 4
core/src/main/java/org/elasticsearch/script/NativeScriptEngineService.java

@@ -22,13 +22,10 @@ package org.elasticsearch.script;
 import org.apache.lucene.index.LeafReaderContext;
 import org.elasticsearch.common.Nullable;
 import org.elasticsearch.common.component.AbstractComponent;
-import org.elasticsearch.common.inject.Inject;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.search.lookup.SearchLookup;
 
 import java.io.IOException;
-import java.util.Collections;
-import java.util.List;
 import java.util.Map;
 
 import static java.util.Collections.unmodifiableMap;
@@ -42,7 +39,6 @@ public class NativeScriptEngineService extends AbstractComponent implements Scri
 
     private final Map<String, NativeScriptFactory> scripts;
 
-    @Inject
     public NativeScriptEngineService(Settings settings, Map<String, NativeScriptFactory> scripts) {
         super(settings);
         this.scripts = unmodifiableMap(scripts);
@@ -98,4 +94,9 @@ public class NativeScriptEngineService extends AbstractComponent implements Scri
     public void scriptRemoved(CompiledScript script) {
         // Nothing to do here
     }
+
+    @Override
+    public boolean isInlineScriptEnabled() {
+        return true;
+    }
 }

+ 7 - 2
core/src/main/java/org/elasticsearch/script/NativeScriptFactory.java

@@ -43,8 +43,13 @@ public interface NativeScriptFactory {
 
     /**
      * Indicates if document scores may be needed by the produced scripts.
-     * 
+     *
      * @return {@code true} if scores are needed.
      */
     boolean needsScores();
-}
+
+    /**
+     * Returns the name of the script factory
+     */
+    String getName();
+}

+ 4 - 1
core/src/main/java/org/elasticsearch/script/ScriptContextRegistry.java

@@ -19,6 +19,8 @@
 
 package org.elasticsearch.script;
 
+import org.elasticsearch.common.settings.Settings;
+
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -30,7 +32,8 @@ import static java.util.Collections.unmodifiableSet;
 
 /**
  * Registry for operations that use scripts as part of their execution. Can be standard operations of custom defined ones (via plugin).
- * Allows plugins to register custom operations that they use scripts for, via {@link ScriptModule#registerScriptContext(org.elasticsearch.script.ScriptContext.Plugin)}.
+ * Allows plugins to register custom operations that they use scripts for,
+ * via {@link org.elasticsearch.plugins.ScriptPlugin}
  * Scripts can be enabled/disabled via fine-grained settings for each single registered operation.
  */
 public final class ScriptContextRegistry {

+ 15 - 55
core/src/main/java/org/elasticsearch/script/ScriptEngineRegistry.java

@@ -29,29 +29,29 @@ import org.elasticsearch.common.Strings;
 public class ScriptEngineRegistry {
 
     private final Map<Class<? extends ScriptEngineService>, String> registeredScriptEngineServices;
-    private final Map<String, Class<? extends ScriptEngineService>> registeredLanguages;
+    private final Map<String, ScriptEngineService> registeredLanguages;
     private final Map<String, Boolean> defaultInlineScriptEnableds;
 
-    public ScriptEngineRegistry(Iterable<ScriptEngineRegistration> registrations) {
+    public ScriptEngineRegistry(Iterable<ScriptEngineService> registrations) {
         Objects.requireNonNull(registrations);
         Map<Class<? extends ScriptEngineService>, String> registeredScriptEngineServices = new HashMap<>();
-        Map<String, Class<? extends ScriptEngineService>> registeredLanguages = new HashMap<>();
+        Map<String, ScriptEngineService> registeredLanguages = new HashMap<>();
         Map<String, Boolean> inlineScriptEnableds = new HashMap<>();
-        for (ScriptEngineRegistration registration : registrations) {
-            String oldLanguage = registeredScriptEngineServices.putIfAbsent(registration.getScriptEngineService(),
-                    registration.getScriptEngineLanguage());
+        for (ScriptEngineService service : registrations) {
+            String oldLanguage = registeredScriptEngineServices.putIfAbsent(service.getClass(),
+                    service.getType());
             if (oldLanguage != null) {
-                throw new IllegalArgumentException("script engine service [" + registration.getScriptEngineService() +
+                throw new IllegalArgumentException("script engine service [" + service.getClass() +
                                 "] already registered for language [" + oldLanguage + "]");
             }
-            String language = registration.getScriptEngineLanguage();
-            Class<? extends ScriptEngineService> scriptEngineServiceClazz =
-                    registeredLanguages.putIfAbsent(language, registration.getScriptEngineService());
-            if (scriptEngineServiceClazz != null) {
+            String language = service.getType();
+            ScriptEngineService scriptEngineService =
+                    registeredLanguages.putIfAbsent(language, service);
+            if (scriptEngineService != null) {
                 throw new IllegalArgumentException("scripting language [" + language + "] already registered for script engine service [" +
-                                scriptEngineServiceClazz.getCanonicalName() + "]");
+                    scriptEngineService.getClass().getCanonicalName() + "]");
             }
-            inlineScriptEnableds.put(language, registration.getDefaultInlineScriptEnabled());
+            inlineScriptEnableds.put(language, service.isInlineScriptEnabled());
         }
 
         this.registeredScriptEngineServices = Collections.unmodifiableMap(registeredScriptEngineServices);
@@ -68,52 +68,12 @@ public class ScriptEngineRegistry {
         return registeredScriptEngineServices.get(scriptEngineService);
     }
 
-    Map<String, Class<? extends ScriptEngineService>> getRegisteredLanguages() {
+    public Map<String, ScriptEngineService> getRegisteredLanguages() {
         return registeredLanguages;
     }
 
-    Map<String, Boolean> getDefaultInlineScriptEnableds() {
+    public Map<String, Boolean> getDefaultInlineScriptEnableds() {
         return this.defaultInlineScriptEnableds;
     }
 
-    public static class ScriptEngineRegistration {
-        private final Class<? extends ScriptEngineService> scriptEngineService;
-        private final String scriptEngineLanguage;
-        private final boolean defaultInlineScriptEnabled;
-
-        /**
-         * Register a script engine service with the default of inline scripts disabled
-         */
-        public ScriptEngineRegistration(Class<? extends ScriptEngineService> scriptEngineService, String scriptEngineLanguage) {
-            this(scriptEngineService, scriptEngineLanguage, false);
-        }
-
-        /**
-         * Register a script engine service with the given default mode for inline scripts
-         */
-        public ScriptEngineRegistration(Class<? extends ScriptEngineService> scriptEngineService, String scriptEngineLanguage,
-                                        boolean defaultInlineScriptEnabled) {
-            Objects.requireNonNull(scriptEngineService);
-            if (Strings.hasText(scriptEngineLanguage) == false) {
-                throw new IllegalArgumentException("languages for script engine service [" +
-                                scriptEngineService.getCanonicalName() + "] should be a non-empty string");
-            }
-            this.scriptEngineService = scriptEngineService;
-            this.scriptEngineLanguage = scriptEngineLanguage;
-            this.defaultInlineScriptEnabled = defaultInlineScriptEnabled;
-        }
-
-        Class<? extends ScriptEngineService> getScriptEngineService() {
-            return scriptEngineService;
-        }
-
-        String getScriptEngineLanguage() {
-            return scriptEngineLanguage;
-        }
-
-        boolean getDefaultInlineScriptEnabled() {
-            return defaultInlineScriptEnabled;
-        }
-    }
-
 }

+ 8 - 1
core/src/main/java/org/elasticsearch/script/ScriptEngineService.java

@@ -37,7 +37,7 @@ public interface ScriptEngineService extends Closeable {
 
     /**
      * Compiles a script.
-     * @param scriptName name of the script. {@code null} if it is anonymous (inline). 
+     * @param scriptName name of the script. {@code null} if it is anonymous (inline).
      *                                        For a file script, its the file name (with extension).
      *                                        For a stored script, its the identifier.
      * @param scriptSource actual source of the script
@@ -55,4 +55,11 @@ public interface ScriptEngineService extends Closeable {
      * The passed script may be null if it has already been garbage collected.
      * */
     void scriptRemoved(@Nullable CompiledScript script);
+
+    /**
+     * Returns <code>true</code> if this scripting engine can safely accept inline scripts by default. The default is <code>false</code>
+     */
+    default boolean isInlineScriptEnabled() {
+        return false;
+    }
 }

+ 27 - 50
core/src/main/java/org/elasticsearch/script/ScriptModule.java

@@ -20,16 +20,17 @@
 package org.elasticsearch.script;
 
 import org.elasticsearch.common.inject.AbstractModule;
-import org.elasticsearch.common.inject.multibindings.MapBinder;
-import org.elasticsearch.common.inject.multibindings.Multibinder;
-import org.elasticsearch.common.settings.Setting;
+import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.common.settings.SettingsModule;
+import org.elasticsearch.plugins.ScriptPlugin;
 
-import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 
 /**
  * An {@link org.elasticsearch.common.inject.Module} which manages {@link ScriptEngineService}s, as well
@@ -37,33 +38,19 @@ import java.util.Objects;
  */
 public class ScriptModule extends AbstractModule {
 
-    private final List<ScriptEngineRegistry.ScriptEngineRegistration> scriptEngineRegistrations = new ArrayList<>();
+    protected final ScriptContextRegistry scriptContextRegistry;
+    protected final ScriptEngineRegistry scriptEngineRegistry;
+    protected final ScriptSettings scriptSettings;
 
-    {
-        scriptEngineRegistrations.add(new ScriptEngineRegistry.ScriptEngineRegistration(NativeScriptEngineService.class,
-                        NativeScriptEngineService.NAME, true));
+    public ScriptModule(ScriptEngineService... services) {
+        this(Arrays.asList(services), Collections.emptyList());
     }
 
-    private final Map<String, Class<? extends NativeScriptFactory>> scripts = new HashMap<>();
-
-    private final List<ScriptContext.Plugin> customScriptContexts = new ArrayList<>();
-
-
-    public void addScriptEngine(ScriptEngineRegistry.ScriptEngineRegistration scriptEngineRegistration) {
-        Objects.requireNonNull(scriptEngineRegistration);
-        scriptEngineRegistrations.add(scriptEngineRegistration);
-    }
-
-    public void registerScript(String name, Class<? extends NativeScriptFactory> script) {
-        scripts.put(name, script);
-    }
-
-    /**
-     * Registers a custom script context that can be used by plugins to categorize the different operations that they use scripts for.
-     * Fine-grained settings allow to enable/disable scripts per context.
-     */
-    public void registerScriptContext(ScriptContext.Plugin scriptContext) {
-        customScriptContexts.add(scriptContext);
+    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);
     }
 
     /**
@@ -71,10 +58,6 @@ public class ScriptModule extends AbstractModule {
      * script extensions to add all their settings.
      */
     public void prepareSettings(SettingsModule settingsModule) {
-        ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(customScriptContexts);
-        ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(scriptEngineRegistrations);
-        ScriptSettings scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
-
         scriptSettings.getScriptTypeSettings().forEach(settingsModule::registerSetting);
         scriptSettings.getScriptContextSettings().forEach(settingsModule::registerSetting);
         scriptSettings.getScriptLanguageSettings().forEach(settingsModule::registerSetting);
@@ -83,27 +66,21 @@ public class ScriptModule extends AbstractModule {
 
     @Override
     protected void configure() {
-        MapBinder<String, NativeScriptFactory> scriptsBinder
-                = MapBinder.newMapBinder(binder(), String.class, NativeScriptFactory.class);
-        for (Map.Entry<String, Class<? extends NativeScriptFactory>> entry : scripts.entrySet()) {
-            scriptsBinder.addBinding(entry.getKey()).to(entry.getValue()).asEagerSingleton();
-        }
-
-        Multibinder<ScriptEngineService> multibinder = Multibinder.newSetBinder(binder(), ScriptEngineService.class);
-        multibinder.addBinding().to(NativeScriptEngineService.class);
-
-        for (ScriptEngineRegistry.ScriptEngineRegistration scriptEngineRegistration : scriptEngineRegistrations) {
-            multibinder.addBinding().to(scriptEngineRegistration.getScriptEngineService()).asEagerSingleton();
-        }
-
-
-        ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(customScriptContexts);
-        ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(scriptEngineRegistrations);
         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) {
+        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()));
+    }
 }

+ 4 - 3
core/src/main/java/org/elasticsearch/script/ScriptService.java

@@ -66,6 +66,7 @@ import java.io.InputStreamReader;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Locale;
@@ -91,7 +92,7 @@ public class ScriptService extends AbstractComponent implements Closeable {
 
     private final String defaultLang;
 
-    private final Set<ScriptEngineService> scriptEngines;
+    private final Collection<ScriptEngineService> scriptEngines;
     private final Map<String, ScriptEngineService> scriptEnginesByLang;
     private final Map<String, ScriptEngineService> scriptEnginesByExt;
 
@@ -132,7 +133,7 @@ public class ScriptService extends AbstractComponent implements Closeable {
     public static final ParseField SCRIPT_INLINE = new ParseField("script");
 
     @Inject
-    public ScriptService(Settings settings, Environment env, Set<ScriptEngineService> scriptEngines,
+    public ScriptService(Settings settings, Environment env,
                          ResourceWatcherService resourceWatcherService, ScriptEngineRegistry scriptEngineRegistry,
                          ScriptContextRegistry scriptContextRegistry, ScriptSettings scriptSettings) throws IOException {
         super(settings);
@@ -145,7 +146,7 @@ public class ScriptService extends AbstractComponent implements Closeable {
                     "Dynamic scripts can be enabled for all languages and all operations by replacing `script.disable_dynamic: false` with `script.inline: true` and `script.stored: true` in elasticsearch.yml");
         }
 
-        this.scriptEngines = scriptEngines;
+        this.scriptEngines = scriptEngineRegistry.getRegisteredLanguages().values();
         this.scriptContextRegistry = scriptContextRegistry;
         int cacheMaxSize = SCRIPT_CACHE_SIZE_SETTING.get(settings);
 

+ 2 - 4
core/src/test/java/org/elasticsearch/index/IndexModuleTests.java

@@ -114,12 +114,10 @@ public class IndexModuleTests extends ESTestCase {
         ThreadPool threadPool = new TestThreadPool("test");
         CircuitBreakerService circuitBreakerService = new NoneCircuitBreakerService();
         BigArrays bigArrays = new BigArrays(settings, circuitBreakerService);
-        Set<ScriptEngineService> scriptEngines = Collections.emptySet();
-        scriptEngines.addAll(Arrays.asList(scriptEngineServices));
-        ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(Collections.emptyList());
+        ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(Arrays.asList(scriptEngineServices));
         ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(Collections.emptyList());
         ScriptSettings scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
-        ScriptService scriptService = new ScriptService(settings, environment, scriptEngines, new ResourceWatcherService(settings, threadPool), scriptEngineRegistry, scriptContextRegistry, scriptSettings);
+        ScriptService scriptService = new ScriptService(settings, environment, new ResourceWatcherService(settings, threadPool), scriptEngineRegistry, scriptContextRegistry, scriptSettings);
         IndicesQueriesRegistry indicesQueriesRegistry = new IndicesQueriesRegistry();
         ClusterService clusterService = ClusterServiceUtils.createClusterService(threadPool);
         return new NodeServicesProvider(threadPool, bigArrays, client, scriptService, indicesQueriesRegistry, circuitBreakerService, clusterService);

+ 12 - 3
core/src/test/java/org/elasticsearch/index/WaitUntilRefreshIT.java

@@ -30,6 +30,7 @@ import org.elasticsearch.action.update.UpdateResponse;
 import org.elasticsearch.common.network.NetworkModule;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.plugins.Plugin;
+import org.elasticsearch.plugins.ScriptPlugin;
 import org.elasticsearch.rest.RestStatus;
 import org.elasticsearch.script.ExecutableScript;
 import org.elasticsearch.script.NativeScriptFactory;
@@ -40,6 +41,8 @@ import org.elasticsearch.test.ESIntegTestCase;
 import org.junit.Before;
 
 import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ExecutionException;
 
@@ -171,7 +174,7 @@ public class WaitUntilRefreshIT extends ESIntegTestCase {
         return singleton(DeletePlzPlugin.class);
     }
 
-    public static class DeletePlzPlugin extends Plugin {
+    public static class DeletePlzPlugin extends Plugin implements ScriptPlugin {
         @Override
         public String name() {
             return "delete_please";
@@ -182,8 +185,9 @@ public class WaitUntilRefreshIT extends ESIntegTestCase {
             return "adds a script that converts any update into a delete for testing";
         }
 
-        public void onModule(ScriptModule scriptModule) {
-            scriptModule.registerScript("delete_plz", DeletePlzFactory.class);
+        @Override
+        public List<NativeScriptFactory> getNativeScripts() {
+            return Collections.singletonList(new DeletePlzFactory());
         }
     }
 
@@ -213,5 +217,10 @@ public class WaitUntilRefreshIT extends ESIntegTestCase {
         public boolean needsScores() {
             return false;
         }
+
+        @Override
+        public String getName() {
+            return "delete_plz";
+        }
     }
 }

+ 26 - 0
core/src/test/java/org/elasticsearch/plugins/PluginsServiceTests.java

@@ -29,6 +29,7 @@ import org.elasticsearch.test.ESTestCase;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.Arrays;
+import java.util.List;
 
 public class PluginsServiceTests extends ESTestCase {
     public static class AdditionalSettingsPlugin1 extends Plugin {
@@ -75,6 +76,20 @@ public class PluginsServiceTests extends ESTestCase {
         }
     }
 
+    public static class FilterablePlugin extends Plugin implements ScriptPlugin {
+        @Override
+        public String name() {
+            return "filter-plugin";
+        }
+        @Override
+        public String description() {
+            return "is filterable";
+        }
+
+    }
+
+
+
     public static class BrokenModule extends AbstractModule {
 
         @Override
@@ -136,4 +151,15 @@ public class PluginsServiceTests extends ESTestCase {
             assertTrue(e.getMessage(), e.getMessage().contains("Could not load plugin descriptor for existing plugin"));
         }
     }
+
+    public void testFilterPlugins() {
+        Settings settings = Settings.builder()
+            .put(Environment.PATH_HOME_SETTING.getKey(), createTempDir())
+            .put("my.setting", "test")
+            .put(IndexModule.INDEX_STORE_TYPE_SETTING.getKey(), IndexModule.Type.SIMPLEFS.getSettingsKey()).build();
+        PluginsService service = newPluginsService(settings, AdditionalSettingsPlugin1.class, FilterablePlugin.class);
+        List<ScriptPlugin> scriptPlugins = service.filterPlugins(ScriptPlugin.class);
+        assertEquals(1, scriptPlugins.size());
+        assertEquals(FilterablePlugin.class, scriptPlugins.get(0).getClass());
+    }
 }

+ 2 - 3
core/src/test/java/org/elasticsearch/script/FileScriptTests.java

@@ -44,11 +44,10 @@ public class FileScriptTests extends ESTestCase {
             .put(ScriptService.SCRIPT_AUTO_RELOAD_ENABLED_SETTING.getKey(), false)
             .put(settings)
             .build();
-        Set<ScriptEngineService> engines = new HashSet<>(Collections.singletonList(new MockScriptEngine()));
-        ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(Collections.singletonList(new ScriptEngineRegistry.ScriptEngineRegistration(MockScriptEngine.class, MockScriptEngine.NAME, true)));
+        ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(Collections.singleton(new MockScriptEngine()));
         ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(Collections.emptyList());
         ScriptSettings scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
-        return new ScriptService(settings, new Environment(settings), engines, null, scriptEngineRegistry, scriptContextRegistry, scriptSettings);
+        return new ScriptService(settings, new Environment(settings), null, scriptEngineRegistry, scriptContextRegistry, scriptSettings);
     }
 
     public void testFileScriptFound() throws Exception {

+ 11 - 5
core/src/test/java/org/elasticsearch/script/NativeScriptTests.java

@@ -52,9 +52,9 @@ public class NativeScriptTests extends ESTestCase {
                 .put(Environment.PATH_HOME_SETTING.getKey(), createTempDir())
                 .build();
         SettingsModule settingsModule = new SettingsModule(settings);
-        ScriptModule scriptModule = new ScriptModule();
+        ScriptModule scriptModule = new ScriptModule(new NativeScriptEngineService(settings,
+            Collections.singletonMap("my", new MyNativeScriptFactory())));
         scriptModule.prepareSettings(settingsModule);
-        scriptModule.registerScript("my", MyNativeScriptFactory.class);
         final ThreadPool threadPool = new ThreadPool(settings);
         Injector injector = new ModulesBuilder().add(
                 new EnvironmentModule(new Environment(settings)),
@@ -85,11 +85,12 @@ public class NativeScriptTests extends ESTestCase {
         ResourceWatcherService resourceWatcherService = new ResourceWatcherService(settings, null);
         Map<String, NativeScriptFactory> nativeScriptFactoryMap = new HashMap<>();
         nativeScriptFactoryMap.put("my", new MyNativeScriptFactory());
-        Set<ScriptEngineService> scriptEngineServices = singleton(new NativeScriptEngineService(settings, nativeScriptFactoryMap));
-        ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(Collections.singletonList(new ScriptEngineRegistry.ScriptEngineRegistration(NativeScriptEngineService.class, NativeScriptEngineService.NAME, true)));
+        ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(Collections.singleton(new NativeScriptEngineService(settings,
+            nativeScriptFactoryMap)));
         ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(new ArrayList<>());
         ScriptSettings scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
-        ScriptService scriptService = new ScriptService(settings, environment, scriptEngineServices, resourceWatcherService, scriptEngineRegistry, scriptContextRegistry, scriptSettings);
+        ScriptService scriptService = new ScriptService(settings, environment, resourceWatcherService, scriptEngineRegistry,
+            scriptContextRegistry, scriptSettings);
 
         for (ScriptContext scriptContext : scriptContextRegistry.scriptContexts()) {
             assertThat(scriptService.compile(new Script("my", ScriptType.INLINE, NativeScriptEngineService.NAME, null), scriptContext,
@@ -107,6 +108,11 @@ public class NativeScriptTests extends ESTestCase {
         public boolean needsScores() {
             return false;
         }
+
+        @Override
+        public String getName() {
+            return "my";
+        }
     }
 
     static class MyScript extends AbstractExecutableScript {

+ 2 - 5
core/src/test/java/org/elasticsearch/script/ScriptContextTests.java

@@ -43,10 +43,7 @@ public class ScriptContextTests extends ESTestCase {
             .put("script." + PLUGIN_NAME + "_custom_globally_disabled_op", "false")
             .put("script.engine." + MockScriptEngine.NAME + ".inline." + PLUGIN_NAME + "_custom_exp_disabled_op", "false")
             .build();
-        Set<ScriptEngineService> engines = new HashSet<>(Collections.singletonList(new MockScriptEngine()));
-        ScriptEngineRegistry.ScriptEngineRegistration registration =
-                new ScriptEngineRegistry.ScriptEngineRegistration(MockScriptEngine.class, MockScriptEngine.NAME, true);
-        ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(Collections.singletonList(registration));
+        ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(Collections.singletonList(new MockScriptEngine()));
         List<ScriptContext.Plugin> customContexts = Arrays.asList(
             new ScriptContext.Plugin(PLUGIN_NAME, "custom_op"),
             new ScriptContext.Plugin(PLUGIN_NAME, "custom_exp_disabled_op"),
@@ -54,7 +51,7 @@ public class ScriptContextTests extends ESTestCase {
         ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(customContexts);
         ScriptSettings scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
 
-        return new ScriptService(settings, new Environment(settings), engines, null, scriptEngineRegistry, scriptContextRegistry, scriptSettings);
+        return new ScriptService(settings, new Environment(settings), null, scriptEngineRegistry, scriptContextRegistry, scriptSettings);
     }
 
     public void testCustomGlobalScriptContextSettings() throws Exception {

+ 28 - 7
core/src/test/java/org/elasticsearch/script/ScriptFieldIT.java

@@ -23,13 +23,16 @@ import org.elasticsearch.action.search.SearchResponse;
 import org.elasticsearch.common.Nullable;
 import org.elasticsearch.index.query.QueryBuilders;
 import org.elasticsearch.plugins.Plugin;
+import org.elasticsearch.plugins.ScriptPlugin;
 import org.elasticsearch.script.ScriptService.ScriptType;
 import org.elasticsearch.search.SearchHit;
 import org.elasticsearch.test.ESIntegTestCase;
 import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
 import org.elasticsearch.test.ESIntegTestCase.Scope;
 
+import java.util.Arrays;
 import java.util.Collection;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ExecutionException;
 
@@ -85,6 +88,11 @@ public class ScriptFieldIT extends ESIntegTestCase {
         public boolean needsScores() {
             return false;
         }
+
+        @Override
+        public String getName() {
+            return "int";
+        }
     }
 
     static class IntScript extends AbstractSearchScript {
@@ -104,6 +112,11 @@ public class ScriptFieldIT extends ESIntegTestCase {
         public boolean needsScores() {
             return false;
         }
+
+        @Override
+        public String getName() {
+            return "long";
+        }
     }
 
     static class LongScript extends AbstractSearchScript {
@@ -123,6 +136,11 @@ public class ScriptFieldIT extends ESIntegTestCase {
         public boolean needsScores() {
             return false;
         }
+
+        @Override
+        public String getName() {
+            return "float";
+        }
     }
 
     static class FloatScript extends AbstractSearchScript {
@@ -142,6 +160,11 @@ public class ScriptFieldIT extends ESIntegTestCase {
         public boolean needsScores() {
             return false;
         }
+
+        @Override
+        public String getName() {
+            return "double";
+        }
     }
 
     static class DoubleScript extends AbstractSearchScript {
@@ -151,7 +174,7 @@ public class ScriptFieldIT extends ESIntegTestCase {
         }
     }
 
-    public static class CustomScriptPlugin extends Plugin {
+    public static class CustomScriptPlugin extends Plugin implements ScriptPlugin {
 
         @Override
         public String name() {
@@ -163,12 +186,10 @@ public class ScriptFieldIT extends ESIntegTestCase {
             return "script ";
         }
 
-        public void onModule(ScriptModule scriptModule) {
-            scriptModule.registerScript("int", IntArrayScriptFactory.class);
-            scriptModule.registerScript("long", LongArrayScriptFactory.class);
-            scriptModule.registerScript("float", FloatArrayScriptFactory.class);
-            scriptModule.registerScript("double", DoubleArrayScriptFactory.class);
+        @Override
+        public List<NativeScriptFactory> getNativeScripts() {
+            return Arrays.asList(new IntArrayScriptFactory(), new LongArrayScriptFactory(), new FloatArrayScriptFactory(),
+                new DoubleArrayScriptFactory());
         }
-
     }
 }

+ 1 - 6
core/src/test/java/org/elasticsearch/script/ScriptModesTests.java

@@ -27,16 +27,13 @@ import org.elasticsearch.test.ESTestCase;
 import org.junit.After;
 import org.junit.Before;
 
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 import static java.util.Collections.unmodifiableMap;
-import static java.util.Collections.unmodifiableSet;
 import static org.elasticsearch.common.util.set.Sets.newHashSet;
 import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.CoreMatchers.notNullValue;
@@ -71,9 +68,7 @@ public class ScriptModesTests extends ESTestCase {
                 //add the native engine just to make sure it gets filtered out
                 new NativeScriptEngineService(Settings.EMPTY, Collections.<String, NativeScriptFactory>emptyMap()),
                 new CustomScriptEngineService()));
-        ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(Arrays.asList(
-            new ScriptEngineRegistry.ScriptEngineRegistration(NativeScriptEngineService.class, NativeScriptEngineService.NAME),
-            new ScriptEngineRegistry.ScriptEngineRegistration(CustomScriptEngineService.class, CustomScriptEngineService.NAME)));
+        ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(scriptEngines.values());
         scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
         checkedSettings = new HashSet<>();
         assertAllSettingsWereChecked = true;

+ 7 - 12
core/src/test/java/org/elasticsearch/script/ScriptServiceTests.java

@@ -41,14 +41,11 @@ import org.junit.Before;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.Matchers.equalTo;
@@ -61,7 +58,6 @@ public class ScriptServiceTests extends ESTestCase {
     private ResourceWatcherService resourceWatcherService;
     private ScriptEngineService scriptEngineService;
     private ScriptEngineService dangerousScriptEngineService;
-    private Set<ScriptEngineService> services;
     private Map<String, ScriptEngineService> scriptEnginesByLangMap;
     private ScriptEngineRegistry scriptEngineRegistry;
     private ScriptContextRegistry scriptContextRegistry;
@@ -89,9 +85,6 @@ public class ScriptServiceTests extends ESTestCase {
         resourceWatcherService = new ResourceWatcherService(baseSettings, null);
         scriptEngineService = new TestEngineService();
         dangerousScriptEngineService = new TestDangerousEngineService();
-        services = new HashSet<>(2);
-        services.add(scriptEngineService);
-        services.add(dangerousScriptEngineService);
         scriptEnginesByLangMap = ScriptModesTests.buildScriptEnginesByLangMap(Collections.singleton(scriptEngineService));
         //randomly register custom script contexts
         int randomInt = randomIntBetween(0, 3);
@@ -109,10 +102,7 @@ public class ScriptServiceTests extends ESTestCase {
             String context = plugin + "_" + operation;
             contexts.put(context, new ScriptContext.Plugin(plugin, operation));
         }
-        List<ScriptEngineRegistry.ScriptEngineRegistration> registries = new ArrayList<>(2);
-        registries.add(new ScriptEngineRegistry.ScriptEngineRegistration(TestEngineService.class, TestEngineService.NAME, true));
-        registries.add(new ScriptEngineRegistry.ScriptEngineRegistration(TestDangerousEngineService.class, TestDangerousEngineService.NAME));
-        scriptEngineRegistry = new ScriptEngineRegistry(registries);
+        scriptEngineRegistry = new ScriptEngineRegistry(Arrays.asList(scriptEngineService, dangerousScriptEngineService));
         scriptContextRegistry = new ScriptContextRegistry(contexts.values());
         scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
         scriptContexts = scriptContextRegistry.scriptContexts().toArray(new ScriptContext[scriptContextRegistry.scriptContexts().size()]);
@@ -124,7 +114,7 @@ public class ScriptServiceTests extends ESTestCase {
     private void buildScriptService(Settings additionalSettings) throws IOException {
         Settings finalSettings = Settings.builder().put(baseSettings).put(additionalSettings).build();
         Environment environment = new Environment(finalSettings);
-        scriptService = new ScriptService(finalSettings, environment, services, resourceWatcherService, scriptEngineRegistry, scriptContextRegistry, scriptSettings) {
+        scriptService = new ScriptService(finalSettings, environment, resourceWatcherService, scriptEngineRegistry, scriptContextRegistry, scriptSettings) {
             @Override
             String getScriptFromClusterState(ClusterState state, String scriptLang, String id) {
                 //mock the script that gets retrieved from an index
@@ -532,6 +522,11 @@ public class ScriptServiceTests extends ESTestCase {
         public void scriptRemoved(CompiledScript script) {
             // Nothing to do here
         }
+
+        @Override
+        public boolean isInlineScriptEnabled() {
+            return true;
+        }
     }
 
     public static class TestDangerousEngineService implements ScriptEngineService {

+ 3 - 7
core/src/test/java/org/elasticsearch/script/ScriptSettingsTests.java

@@ -20,17 +20,13 @@
 package org.elasticsearch.script;
 
 import org.elasticsearch.common.Nullable;
-import org.elasticsearch.common.settings.Setting;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.search.lookup.SearchLookup;
 import org.elasticsearch.test.ESTestCase;
 
-import java.util.Arrays;
 import java.util.Collections;
-import java.util.List;
 import java.util.Map;
 
-import static org.hamcrest.Matchers.anyOf;
 import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.equalTo;
 
@@ -38,7 +34,7 @@ public class ScriptSettingsTests extends ESTestCase {
 
     public void testDefaultLanguageIsGroovy() {
         ScriptEngineRegistry scriptEngineRegistry =
-                new ScriptEngineRegistry(Collections.singletonList(new ScriptEngineRegistry.ScriptEngineRegistration(CustomScriptEngineService.class, CustomScriptEngineService.NAME, true)));
+                new ScriptEngineRegistry(Collections.singletonList(new CustomScriptEngineService()));
         ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(Collections.emptyList());
         ScriptSettings scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
         assertThat(scriptSettings.getDefaultScriptLanguageSetting().get(Settings.EMPTY), equalTo("groovy"));
@@ -46,7 +42,7 @@ public class ScriptSettingsTests extends ESTestCase {
 
     public void testCustomDefaultLanguage() {
         ScriptEngineRegistry scriptEngineRegistry =
-            new ScriptEngineRegistry(Collections.singletonList(new ScriptEngineRegistry.ScriptEngineRegistration(CustomScriptEngineService.class, CustomScriptEngineService.NAME, true)));
+            new ScriptEngineRegistry(Collections.singletonList(new CustomScriptEngineService()));
         ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(Collections.emptyList());
         ScriptSettings scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
         String defaultLanguage = CustomScriptEngineService.NAME;
@@ -56,7 +52,7 @@ public class ScriptSettingsTests extends ESTestCase {
 
     public void testInvalidDefaultLanguage() {
         ScriptEngineRegistry scriptEngineRegistry =
-            new ScriptEngineRegistry(Collections.singletonList(new ScriptEngineRegistry.ScriptEngineRegistration(CustomScriptEngineService.class, CustomScriptEngineService.NAME, true)));
+            new ScriptEngineRegistry(Collections.singletonList(new CustomScriptEngineService()));
         ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(Collections.emptyList());
         ScriptSettings scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
         Settings settings = Settings.builder().put("script.default_lang", "C++").build();

+ 11 - 3
core/src/test/java/org/elasticsearch/search/SearchTimeoutIT.java

@@ -23,6 +23,7 @@ import org.elasticsearch.action.search.SearchResponse;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.common.unit.TimeValue;
 import org.elasticsearch.plugins.Plugin;
+import org.elasticsearch.plugins.ScriptPlugin;
 import org.elasticsearch.script.AbstractSearchScript;
 import org.elasticsearch.script.ExecutableScript;
 import org.elasticsearch.script.NativeScriptFactory;
@@ -33,6 +34,7 @@ import org.elasticsearch.test.ESIntegTestCase;
 
 import java.util.Collection;
 import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
@@ -64,7 +66,7 @@ public class SearchTimeoutIT extends ESIntegTestCase {
         assertThat(searchResponse.isTimedOut(), equalTo(true));
     }
 
-    public static class ScriptedTimeoutPlugin extends Plugin {
+    public static class ScriptedTimeoutPlugin extends Plugin implements ScriptPlugin {
         @Override
         public String name() {
             return "test-scripted-search-timeout";
@@ -75,8 +77,9 @@ public class SearchTimeoutIT extends ESIntegTestCase {
             return "Test for scripted timeouts on searches";
         }
 
-        public void onModule(ScriptModule module) {
-            module.registerScript(NativeTestScriptedTimeout.TEST_NATIVE_SCRIPT_TIMEOUT, NativeTestScriptedTimeout.Factory.class);
+        @Override
+        public List<NativeScriptFactory> getNativeScripts() {
+            return Collections.singletonList(new NativeTestScriptedTimeout.Factory());
         }
     }
 
@@ -95,6 +98,11 @@ public class SearchTimeoutIT extends ESIntegTestCase {
             public boolean needsScores() {
                 return false;
             }
+
+            @Override
+            public String getName() {
+                return TEST_NATIVE_SCRIPT_TIMEOUT;
+            }
         }
 
         @Override

+ 1 - 32
core/src/test/java/org/elasticsearch/search/aggregations/AggregatorParsingTests.java

@@ -117,38 +117,7 @@ public class AggregatorParsingTests extends ESTestCase {
                 .put(new IndexMetaData.Builder(index.getName()).settings(indexSettings).numberOfShards(1).numberOfReplicas(0))));
         SettingsModule settingsModule = new SettingsModule(settings);
         settingsModule.registerSetting(InternalSettingsPlugin.VERSION_CREATED);
-        ScriptModule scriptModule = new ScriptModule() {
-            @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();
-                MockScriptEngine mockScriptEngine = new MockScriptEngine();
-                Multibinder<ScriptEngineService> multibinder = Multibinder.newSetBinder(binder(), ScriptEngineService.class);
-                multibinder.addBinding().toInstance(mockScriptEngine);
-                Set<ScriptEngineService> engines = new HashSet<>();
-                engines.add(mockScriptEngine);
-                List<ScriptContext.Plugin> customContexts = new ArrayList<>();
-                ScriptEngineRegistry scriptEngineRegistry =
-                        new ScriptEngineRegistry(Collections
-                                .singletonList(new ScriptEngineRegistry.ScriptEngineRegistration(MockScriptEngine.class,
-                                                                                                 MockScriptEngine.NAME,
-                                                                                                 true)));
-                bind(ScriptEngineRegistry.class).toInstance(scriptEngineRegistry);
-                ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(customContexts);
-                bind(ScriptContextRegistry.class).toInstance(scriptContextRegistry);
-                ScriptSettings scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
-                bind(ScriptSettings.class).toInstance(scriptSettings);
-                try {
-                    ScriptService scriptService = new ScriptService(settings, new Environment(settings), engines, null,
-                            scriptEngineRegistry, scriptContextRegistry, scriptSettings);
-                    bind(ScriptService.class).toInstance(scriptService);
-                } catch (IOException e) {
-                    throw new IllegalStateException("error while binding ScriptService", e);
-                }
-            }
-        };
+        ScriptModule scriptModule = newTestScriptModule();
         scriptModule.prepareSettings(settingsModule);
         injector = new ModulesBuilder().add(new EnvironmentModule(new Environment(settings)), settingsModule,
                 new ThreadPoolModule(threadPool), scriptModule, new IndicesModule() {

+ 1 - 32
core/src/test/java/org/elasticsearch/search/aggregations/BaseAggregationTestCase.java

@@ -131,38 +131,7 @@ public abstract class BaseAggregationTestCase<AB extends AbstractAggregationBuil
                 .put(new IndexMetaData.Builder(index.getName()).settings(indexSettings).numberOfShards(1).numberOfReplicas(0))));
         SettingsModule settingsModule = new SettingsModule(settings);
         settingsModule.registerSetting(InternalSettingsPlugin.VERSION_CREATED);
-        ScriptModule scriptModule = new ScriptModule() {
-            @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();
-                MockScriptEngine mockScriptEngine = new MockScriptEngine();
-                Multibinder<ScriptEngineService> multibinder = Multibinder.newSetBinder(binder(), ScriptEngineService.class);
-                multibinder.addBinding().toInstance(mockScriptEngine);
-                Set<ScriptEngineService> engines = new HashSet<>();
-                engines.add(mockScriptEngine);
-                List<ScriptContext.Plugin> customContexts = new ArrayList<>();
-                ScriptEngineRegistry scriptEngineRegistry =
-                        new ScriptEngineRegistry(Collections
-                                .singletonList(new ScriptEngineRegistry.ScriptEngineRegistration(MockScriptEngine.class,
-                                                                                                 MockScriptEngine.NAME,
-                                                                                                 true)));
-                bind(ScriptEngineRegistry.class).toInstance(scriptEngineRegistry);
-                ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(customContexts);
-                bind(ScriptContextRegistry.class).toInstance(scriptContextRegistry);
-                ScriptSettings scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
-                bind(ScriptSettings.class).toInstance(scriptSettings);
-                try {
-                    ScriptService scriptService = new ScriptService(settings, new Environment(settings), engines, null,
-                            scriptEngineRegistry, scriptContextRegistry, scriptSettings);
-                    bind(ScriptService.class).toInstance(scriptService);
-                } catch (IOException e) {
-                    throw new IllegalStateException("error while binding ScriptService", e);
-                }
-            }
-        };
+        ScriptModule scriptModule = newTestScriptModule();
         scriptModule.prepareSettings(settingsModule);
         injector = new ModulesBuilder().add(
                 new EnvironmentModule(new Environment(settings)),

+ 1 - 31
core/src/test/java/org/elasticsearch/search/aggregations/BasePipelineAggregationTestCase.java

@@ -131,37 +131,7 @@ public abstract class BasePipelineAggregationTestCase<AF extends AbstractPipelin
                 .put(new IndexMetaData.Builder(index.getName()).settings(indexSettings).numberOfShards(1).numberOfReplicas(0))));
         SettingsModule settingsModule = new SettingsModule(settings);
         settingsModule.registerSetting(InternalSettingsPlugin.VERSION_CREATED);
-        ScriptModule scriptModule = new ScriptModule() {
-            @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();
-                MockScriptEngine mockScriptEngine = new MockScriptEngine();
-                Multibinder<ScriptEngineService> multibinder = Multibinder.newSetBinder(binder(), ScriptEngineService.class);
-                multibinder.addBinding().toInstance(mockScriptEngine);
-                Set<ScriptEngineService> engines = new HashSet<>();
-                engines.add(mockScriptEngine);
-                List<ScriptContext.Plugin> customContexts = new ArrayList<>();
-                ScriptEngineRegistry scriptEngineRegistry =
-                        new ScriptEngineRegistry(Collections
-                                .singletonList(new ScriptEngineRegistry.ScriptEngineRegistration(MockScriptEngine.class,
-                                                                                                 MockScriptEngine.NAME, true)));
-                bind(ScriptEngineRegistry.class).toInstance(scriptEngineRegistry);
-                ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(customContexts);
-                bind(ScriptContextRegistry.class).toInstance(scriptContextRegistry);
-                ScriptSettings scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
-                bind(ScriptSettings.class).toInstance(scriptSettings);
-                try {
-                    ScriptService scriptService = new ScriptService(settings, new Environment(settings), engines, null,
-                            scriptEngineRegistry, scriptContextRegistry, scriptSettings);
-                    bind(ScriptService.class).toInstance(scriptService);
-                } catch (IOException e) {
-                    throw new IllegalStateException("error while binding ScriptService", e);
-                }
-            }
-        };
+        ScriptModule scriptModule = newTestScriptModule();
         scriptModule.prepareSettings(settingsModule);
         injector = new ModulesBuilder().add(
                 new EnvironmentModule(new Environment(settings)),

+ 17 - 4
core/src/test/java/org/elasticsearch/search/aggregations/bucket/DateScriptMocks.java

@@ -21,6 +21,7 @@ package org.elasticsearch.search.aggregations.bucket;
 
 import org.elasticsearch.common.inject.internal.Nullable;
 import org.elasticsearch.plugins.Plugin;
+import org.elasticsearch.plugins.ScriptPlugin;
 import org.elasticsearch.script.AbstractSearchScript;
 import org.elasticsearch.script.ExecutableScript;
 import org.elasticsearch.script.NativeScriptFactory;
@@ -28,7 +29,9 @@ import org.elasticsearch.script.ScriptModule;
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 
+import java.util.Arrays;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -39,7 +42,7 @@ public class DateScriptMocks {
     /**
      * Mock plugin for the {@link DateScriptMocks.ExtractFieldScript} and {@link DateScriptMocks.PlusOneMonthScript}
      */
-    public static class DateScriptsMockPlugin extends Plugin {
+    public static class DateScriptsMockPlugin extends Plugin implements ScriptPlugin {
 
         @Override
         public String name() {
@@ -51,9 +54,9 @@ public class DateScriptMocks {
             return "A mock script plugin.";
         }
 
-        public void onModule(ScriptModule module) {
-            module.registerScript(ExtractFieldScript.NAME, ExtractFieldScriptFactory.class);
-            module.registerScript(PlusOneMonthScript.NAME, PlusOneMonthScriptFactory.class);
+        @Override
+        public List<NativeScriptFactory> getNativeScripts() {
+            return Arrays.asList(new ExtractFieldScriptFactory(), new PlusOneMonthScriptFactory());
         }
     }
 
@@ -66,6 +69,11 @@ public class DateScriptMocks {
         public boolean needsScores() {
             return false;
         }
+
+        @Override
+        public String getName() {
+            return ExtractFieldScript.NAME;
+        }
     }
 
     public static class ExtractFieldScript extends AbstractSearchScript {
@@ -94,6 +102,11 @@ public class DateScriptMocks {
         public boolean needsScores() {
             return false;
         }
+
+        @Override
+        public String getName() {
+            return PlusOneMonthScript.NAME;
+        }
     }
 
     /**

+ 11 - 3
core/src/test/java/org/elasticsearch/search/aggregations/bucket/IpRangeIT.java

@@ -25,11 +25,13 @@ import static org.hamcrest.Matchers.containsString;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 
 import org.elasticsearch.action.search.SearchResponse;
 import org.elasticsearch.common.inject.internal.Nullable;
 import org.elasticsearch.plugins.Plugin;
+import org.elasticsearch.plugins.ScriptPlugin;
 import org.elasticsearch.script.AbstractSearchScript;
 import org.elasticsearch.script.ExecutableScript;
 import org.elasticsearch.script.NativeScriptFactory;
@@ -216,7 +218,7 @@ public class IpRangeIT extends ESIntegTestCase {
         assertThat(e.getMessage(), containsString("[ip_range] does not support scripts"));
     }
 
-    public static class DummyScriptPlugin extends Plugin {
+    public static class DummyScriptPlugin extends Plugin implements ScriptPlugin {
 
         @Override
         public String name() {
@@ -228,8 +230,9 @@ public class IpRangeIT extends ESIntegTestCase {
             return "A mock script plugin.";
         }
 
-        public void onModule(ScriptModule module) {
-            module.registerScript(DummyScript.NAME, DummyScriptFactory.class);
+        @Override
+        public List<NativeScriptFactory> getNativeScripts() {
+            return Collections.singletonList(new DummyScriptFactory());
         }
     }
 
@@ -243,6 +246,11 @@ public class IpRangeIT extends ESIntegTestCase {
         public boolean needsScores() {
             return false;
         }
+
+        @Override
+        public String getName() {
+            return DummyScript.NAME;
+        }
     }
 
     private static class DummyScript extends AbstractSearchScript {

+ 7 - 4
core/src/test/java/org/elasticsearch/search/aggregations/bucket/SignificantTermsSignificanceScoreIT.java

@@ -30,6 +30,8 @@ import org.elasticsearch.common.xcontent.XContentParser;
 import org.elasticsearch.index.query.QueryBuilders;
 import org.elasticsearch.index.query.QueryShardException;
 import org.elasticsearch.plugins.Plugin;
+import org.elasticsearch.plugins.ScriptPlugin;
+import org.elasticsearch.script.NativeScriptFactory;
 import org.elasticsearch.script.Script;
 import org.elasticsearch.script.ScriptModule;
 import org.elasticsearch.script.ScriptService.ScriptType;
@@ -52,6 +54,7 @@ import org.elasticsearch.test.search.aggregations.bucket.SharedSignificantTermsT
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -164,7 +167,7 @@ public class SignificantTermsSignificanceScoreIT extends ESIntegTestCase {
         }
     }
 
-    public static class CustomSignificanceHeuristicPlugin extends Plugin {
+    public static class CustomSignificanceHeuristicPlugin extends Plugin implements ScriptPlugin {
         @Override
         public String name() {
             return "test-plugin-significance-heuristic";
@@ -179,9 +182,9 @@ public class SignificantTermsSignificanceScoreIT extends ESIntegTestCase {
             searchModule.registerSignificanceHeuristic(SimpleHeuristic.NAMES_FIELD, SimpleHeuristic::new, SimpleHeuristic::parse);
         }
 
-        public void onModule(ScriptModule module) {
-            module.registerScript(NativeSignificanceScoreScriptNoParams.NATIVE_SIGNIFICANCE_SCORE_SCRIPT_NO_PARAMS, NativeSignificanceScoreScriptNoParams.Factory.class);
-            module.registerScript(NativeSignificanceScoreScriptWithParams.NATIVE_SIGNIFICANCE_SCORE_SCRIPT_WITH_PARAMS, NativeSignificanceScoreScriptWithParams.Factory.class);
+        @Override
+        public List<NativeScriptFactory> getNativeScripts() {
+            return Arrays.asList(new NativeSignificanceScoreScriptNoParams.Factory(), new NativeSignificanceScoreScriptWithParams.Factory());
         }
     }
 

+ 15 - 10
core/src/test/java/org/elasticsearch/search/aggregations/metrics/AvgIT.java

@@ -21,14 +21,14 @@ package org.elasticsearch.search.aggregations.metrics;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.search.Scorer;
 import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.plugins.Plugin;
+import org.elasticsearch.plugins.ScriptPlugin;
 import org.elasticsearch.script.CompiledScript;
 import org.elasticsearch.script.ExecutableScript;
 import org.elasticsearch.script.LeafSearchScript;
 import org.elasticsearch.script.Script;
-import org.elasticsearch.script.ScriptEngineRegistry;
 import org.elasticsearch.script.ScriptEngineService;
-import org.elasticsearch.script.ScriptModule;
 import org.elasticsearch.script.ScriptService.ScriptType;
 import org.elasticsearch.script.SearchScript;
 import org.elasticsearch.search.aggregations.bucket.filter.Filter;
@@ -356,7 +356,7 @@ public class AvgIT extends AbstractNumericTestCase {
     /**
      * Mock plugin for the {@link ExtractFieldScriptEngine}
      */
-    public static class ExtractFieldScriptPlugin extends Plugin {
+    public static class ExtractFieldScriptPlugin extends Plugin implements ScriptPlugin {
 
         @Override
         public String name() {
@@ -368,10 +368,10 @@ public class AvgIT extends AbstractNumericTestCase {
             return "Mock script engine for " + AvgIT.class;
         }
 
-        public void onModule(ScriptModule module) {
-            module.addScriptEngine(new ScriptEngineRegistry.ScriptEngineRegistration(ExtractFieldScriptEngine.class, ExtractFieldScriptEngine.NAME, true));
+        @Override
+        public ScriptEngineService getScriptEngineService(Settings settings) {
+            return new ExtractFieldScriptEngine();
         }
-
     }
 
     /**
@@ -476,7 +476,7 @@ public class AvgIT extends AbstractNumericTestCase {
     /**
      * Mock plugin for the {@link FieldValueScriptEngine}
      */
-    public static class FieldValueScriptPlugin extends Plugin {
+    public static class FieldValueScriptPlugin extends Plugin implements ScriptPlugin {
 
         @Override
         public String name() {
@@ -488,10 +488,10 @@ public class AvgIT extends AbstractNumericTestCase {
             return "Mock script engine for " + AvgIT.class;
         }
 
-        public void onModule(ScriptModule module) {
-            module.addScriptEngine(new ScriptEngineRegistry.ScriptEngineRegistration(FieldValueScriptEngine.class, FieldValueScriptEngine.NAME, true));
+        @Override
+        public ScriptEngineService getScriptEngineService(Settings settings) {
+            return new FieldValueScriptEngine();
         }
-
     }
 
     /**
@@ -589,5 +589,10 @@ public class AvgIT extends AbstractNumericTestCase {
         @Override
         public void scriptRemoved(CompiledScript script) {
         }
+
+        @Override
+        public boolean isInlineScriptEnabled() {
+            return true;
+        }
     }
 }

+ 20 - 11
core/src/test/java/org/elasticsearch/search/aggregations/metrics/SumIT.java

@@ -21,14 +21,14 @@ package org.elasticsearch.search.aggregations.metrics;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.search.Scorer;
 import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.plugins.Plugin;
+import org.elasticsearch.plugins.ScriptPlugin;
 import org.elasticsearch.script.CompiledScript;
 import org.elasticsearch.script.ExecutableScript;
 import org.elasticsearch.script.LeafSearchScript;
 import org.elasticsearch.script.Script;
-import org.elasticsearch.script.ScriptEngineRegistry;
 import org.elasticsearch.script.ScriptEngineService;
-import org.elasticsearch.script.ScriptModule;
 import org.elasticsearch.script.ScriptService.ScriptType;
 import org.elasticsearch.script.SearchScript;
 import org.elasticsearch.search.aggregations.bucket.filter.Filter;
@@ -44,7 +44,6 @@ import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -351,7 +350,7 @@ public class SumIT extends AbstractNumericTestCase {
     /**
      * Mock plugin for the {@link ExtractFieldScriptEngine}
      */
-    public static class ExtractFieldScriptPlugin extends Plugin {
+    public static class ExtractFieldScriptPlugin extends Plugin implements ScriptPlugin {
 
         @Override
         public String name() {
@@ -363,10 +362,10 @@ public class SumIT extends AbstractNumericTestCase {
             return "Mock script engine for " + SumIT.class;
         }
 
-        public void onModule(ScriptModule module) {
-            module.addScriptEngine(new ScriptEngineRegistry.ScriptEngineRegistration(ExtractFieldScriptEngine.class, ExtractFieldScriptEngine.NAME, true));
+        @Override
+        public ScriptEngineService getScriptEngineService(Settings settings) {
+            return new ExtractFieldScriptEngine();
         }
-
     }
 
     /**
@@ -468,12 +467,17 @@ public class SumIT extends AbstractNumericTestCase {
         @Override
         public void scriptRemoved(CompiledScript script) {
         }
+
+        @Override
+        public boolean isInlineScriptEnabled() {
+            return true;
+        }
     }
 
     /**
      * Mock plugin for the {@link FieldValueScriptEngine}
      */
-    public static class FieldValueScriptPlugin extends Plugin {
+    public static class FieldValueScriptPlugin extends Plugin implements ScriptPlugin {
 
         @Override
         public String name() {
@@ -485,10 +489,10 @@ public class SumIT extends AbstractNumericTestCase {
             return "Mock script engine for " + SumIT.class;
         }
 
-        public void onModule(ScriptModule module) {
-            module.addScriptEngine(new ScriptEngineRegistry.ScriptEngineRegistration(FieldValueScriptEngine.class, FieldValueScriptEngine.NAME, true));
+        @Override
+        public ScriptEngineService getScriptEngineService(Settings settings) {
+            return new FieldValueScriptEngine();
         }
-
     }
 
     /**
@@ -594,5 +598,10 @@ public class SumIT extends AbstractNumericTestCase {
         @Override
         public void scriptRemoved(CompiledScript script) {
         }
+
+        @Override
+        public boolean isInlineScriptEnabled() {
+            return true;
+        }
     }
 }

+ 11 - 4
core/src/test/java/org/elasticsearch/search/aggregations/metrics/ValueCountIT.java

@@ -21,7 +21,9 @@ package org.elasticsearch.search.aggregations.metrics;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.search.Scorer;
 import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.plugins.Plugin;
+import org.elasticsearch.plugins.ScriptPlugin;
 import org.elasticsearch.script.CompiledScript;
 import org.elasticsearch.script.ExecutableScript;
 import org.elasticsearch.script.LeafSearchScript;
@@ -210,7 +212,7 @@ public class ValueCountIT extends ESIntegTestCase {
     /**
      * Mock plugin for the {@link FieldValueScriptEngine}
      */
-    public static class FieldValueScriptPlugin extends Plugin {
+    public static class FieldValueScriptPlugin extends Plugin implements ScriptPlugin {
 
         @Override
         public String name() {
@@ -222,10 +224,10 @@ public class ValueCountIT extends ESIntegTestCase {
             return "Mock script engine for " + ValueCountIT.class;
         }
 
-        public void onModule(ScriptModule module) {
-            module.addScriptEngine(new ScriptEngineRegistry.ScriptEngineRegistration(FieldValueScriptEngine.class, FieldValueScriptEngine.NAME, true));
+        @Override
+        public ScriptEngineService getScriptEngineService(Settings settings) {
+            return new FieldValueScriptEngine();
         }
-
     }
 
     /**
@@ -330,5 +332,10 @@ public class ValueCountIT extends ESIntegTestCase {
         @Override
         public void scriptRemoved(CompiledScript script) {
         }
+
+        @Override
+        public boolean isInlineScriptEnabled() {
+            return true;
+        }
     }
 }

+ 1 - 31
core/src/test/java/org/elasticsearch/search/builder/SearchSourceBuilderTests.java

@@ -138,37 +138,7 @@ public class SearchSourceBuilderTests extends ESTestCase {
                 .put(new IndexMetaData.Builder(index.getName()).settings(indexSettings).numberOfShards(1).numberOfReplicas(0))));
         SettingsModule settingsModule = new SettingsModule(settings);
         settingsModule.registerSetting(InternalSettingsPlugin.VERSION_CREATED);
-        ScriptModule scriptModule = new ScriptModule() {
-            @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();
-                MockScriptEngine mockScriptEngine = new MockScriptEngine();
-                Multibinder<ScriptEngineService> multibinder = Multibinder.newSetBinder(binder(), ScriptEngineService.class);
-                multibinder.addBinding().toInstance(mockScriptEngine);
-                Set<ScriptEngineService> engines = new HashSet<>();
-                engines.add(mockScriptEngine);
-                List<ScriptContext.Plugin> customContexts = new ArrayList<>();
-                ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(Collections
-                        .singletonList(new ScriptEngineRegistry.ScriptEngineRegistration(MockScriptEngine.class,
-                                                                                         MockScriptEngine.NAME,
-                                                                                         true)));
-                bind(ScriptEngineRegistry.class).toInstance(scriptEngineRegistry);
-                ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(customContexts);
-                bind(ScriptContextRegistry.class).toInstance(scriptContextRegistry);
-                ScriptSettings scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
-                bind(ScriptSettings.class).toInstance(scriptSettings);
-                try {
-                    ScriptService scriptService = new ScriptService(settings, new Environment(settings), engines, null,
-                            scriptEngineRegistry, scriptContextRegistry, scriptSettings);
-                    bind(ScriptService.class).toInstance(scriptService);
-                } catch (IOException e) {
-                    throw new IllegalStateException("error while binding ScriptService", e);
-                }
-            }
-        };
+        ScriptModule scriptModule = newTestScriptModule();
         scriptModule.prepareSettings(settingsModule);
         injector = new ModulesBuilder().add(
                 new EnvironmentModule(new Environment(settings)), settingsModule,

+ 5 - 0
core/src/test/java/org/elasticsearch/search/functionscore/ExplainableScriptIT.java

@@ -101,6 +101,11 @@ public class ExplainableScriptIT extends ESIntegTestCase {
         public boolean needsScores() {
             return true;
         }
+
+        @Override
+        public String getName() {
+            return "native_explainable_script";
+        }
     }
 
     static class MyScript extends AbstractDoubleSearchScript implements ExplainableSearchScript, ExecutableScript {

+ 10 - 3
core/src/test/java/org/elasticsearch/search/functionscore/ExplainableScriptPlugin.java

@@ -20,9 +20,14 @@
 package org.elasticsearch.search.functionscore;
 
 import org.elasticsearch.plugins.Plugin;
+import org.elasticsearch.plugins.ScriptPlugin;
+import org.elasticsearch.script.NativeScriptFactory;
 import org.elasticsearch.script.ScriptModule;
 
-public class ExplainableScriptPlugin extends Plugin {
+import java.util.Collections;
+import java.util.List;
+
+public class ExplainableScriptPlugin extends Plugin implements ScriptPlugin {
 
     public ExplainableScriptPlugin() {}
     @Override
@@ -35,7 +40,9 @@ public class ExplainableScriptPlugin extends Plugin {
         return "Native explainable script";
     }
 
-    public void onModule(ScriptModule module) {
-        module.registerScript("native_explainable_script", ExplainableScriptIT.MyNativeScriptFactory.class);
+
+    @Override
+    public List<NativeScriptFactory> getNativeScripts() {
+        return Collections.singletonList(new ExplainableScriptIT.MyNativeScriptFactory());
     }
 }

+ 2 - 3
core/src/test/java/org/elasticsearch/search/sort/AbstractSortTestCase.java

@@ -95,10 +95,9 @@ public abstract class AbstractSortTestCase<T extends SortBuilder<T>> extends EST
                 .build();
         Environment environment = new Environment(baseSettings);
         ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(Collections.emptyList());
-        ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(Collections.singletonList(new ScriptEngineRegistry
-                .ScriptEngineRegistration(TestEngineService.class, TestEngineService.NAME)));
+        ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(Collections.singletonList(new TestEngineService()));
         ScriptSettings scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
-        scriptService = new ScriptService(baseSettings, environment, Collections.singleton(new TestEngineService()),
+        scriptService = new ScriptService(baseSettings, environment,
                 new ResourceWatcherService(baseSettings, null), scriptEngineRegistry, scriptContextRegistry, scriptSettings) {
             @Override
             public CompiledScript compile(Script script, ScriptContext scriptContext, Map<String, String> params, ClusterState state) {

+ 13 - 4
core/src/test/java/org/elasticsearch/update/UpdateByNativeScriptIT.java

@@ -20,6 +20,7 @@ package org.elasticsearch.update;
 
 import org.elasticsearch.common.Nullable;
 import org.elasticsearch.plugins.Plugin;
+import org.elasticsearch.plugins.ScriptPlugin;
 import org.elasticsearch.script.AbstractExecutableScript;
 import org.elasticsearch.script.ExecutableScript;
 import org.elasticsearch.script.NativeScriptEngineService;
@@ -32,7 +33,9 @@ import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
 import org.elasticsearch.test.ESIntegTestCase.Scope;
 
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import static org.hamcrest.Matchers.hasKey;
@@ -65,8 +68,8 @@ public class UpdateByNativeScriptIT extends ESIntegTestCase {
         assertThat(data.get("foo").toString(), is("SETVALUE"));
     }
 
-    public static class CustomNativeScriptFactory implements NativeScriptFactory {
-        public static class TestPlugin extends Plugin {
+    public static class CustomNativeScriptFactory implements NativeScriptFactory  {
+        public static class TestPlugin extends Plugin implements ScriptPlugin {
             @Override
             public String name() {
                 return "mock-native-script";
@@ -75,8 +78,9 @@ public class UpdateByNativeScriptIT extends ESIntegTestCase {
             public String description() {
                 return "a mock native script for testing";
             }
-            public void onModule(ScriptModule scriptModule) {
-                scriptModule.registerScript("custom", CustomNativeScriptFactory.class);
+            @Override
+            public List<NativeScriptFactory> getNativeScripts() {
+                return Collections.singletonList(new CustomNativeScriptFactory());
             }
         }
         @Override
@@ -87,6 +91,11 @@ public class UpdateByNativeScriptIT extends ESIntegTestCase {
         public boolean needsScores() {
             return false;
         }
+
+        @Override
+        public String getName() {
+            return "custom";
+        }
     }
 
     static class CustomScript extends AbstractExecutableScript {

+ 35 - 18
core/src/test/java/org/elasticsearch/update/UpdateIT.java

@@ -38,12 +38,11 @@ import org.elasticsearch.index.VersionType;
 import org.elasticsearch.index.engine.DocumentMissingException;
 import org.elasticsearch.index.engine.VersionConflictEngineException;
 import org.elasticsearch.plugins.Plugin;
+import org.elasticsearch.plugins.ScriptPlugin;
 import org.elasticsearch.script.CompiledScript;
 import org.elasticsearch.script.ExecutableScript;
 import org.elasticsearch.script.Script;
-import org.elasticsearch.script.ScriptEngineRegistry;
 import org.elasticsearch.script.ScriptEngineService;
-import org.elasticsearch.script.ScriptModule;
 import org.elasticsearch.script.ScriptService;
 import org.elasticsearch.script.SearchScript;
 import org.elasticsearch.search.lookup.SearchLookup;
@@ -78,7 +77,7 @@ import static org.hamcrest.Matchers.nullValue;
 
 public class UpdateIT extends ESIntegTestCase {
 
-    public static class PutFieldValuesScriptPlugin extends Plugin {
+    public static class PutFieldValuesScriptPlugin extends Plugin implements ScriptPlugin {
 
         public PutFieldValuesScriptPlugin() {
         }
@@ -93,10 +92,10 @@ public class UpdateIT extends ESIntegTestCase {
             return "Mock script engine for " + UpdateIT.class;
         }
 
-        public void onModule(ScriptModule module) {
-            module.addScriptEngine(new ScriptEngineRegistry.ScriptEngineRegistration(PutFieldValuesScriptEngine.class, PutFieldValuesScriptEngine.NAME, true));
+        @Override
+        public ScriptEngineService getScriptEngineService(Settings settings) {
+            return new PutFieldValuesScriptEngine();
         }
-
     }
 
     public static class PutFieldValuesScriptEngine implements ScriptEngineService {
@@ -163,9 +162,13 @@ public class UpdateIT extends ESIntegTestCase {
         public void scriptRemoved(CompiledScript script) {
         }
 
+        @Override
+        public boolean isInlineScriptEnabled() {
+            return true;
+        }
     }
 
-    public static class FieldIncrementScriptPlugin extends Plugin {
+    public static class FieldIncrementScriptPlugin extends Plugin implements ScriptPlugin {
 
         public FieldIncrementScriptPlugin() {
         }
@@ -180,10 +183,10 @@ public class UpdateIT extends ESIntegTestCase {
             return "Mock script engine for " + UpdateIT.class;
         }
 
-        public void onModule(ScriptModule module) {
-            module.addScriptEngine(new ScriptEngineRegistry.ScriptEngineRegistration(FieldIncrementScriptEngine.class, FieldIncrementScriptEngine.NAME, true));
+        @Override
+        public ScriptEngineService getScriptEngineService(Settings settings) {
+            return new FieldIncrementScriptEngine();
         }
-
     }
 
     public static class FieldIncrementScriptEngine implements ScriptEngineService {
@@ -243,9 +246,14 @@ public class UpdateIT extends ESIntegTestCase {
         public void scriptRemoved(CompiledScript script) {
         }
 
+        @Override
+        public boolean isInlineScriptEnabled() {
+            return true;
+        }
+
     }
 
-    public static class ScriptedUpsertScriptPlugin extends Plugin {
+    public static class ScriptedUpsertScriptPlugin extends Plugin implements ScriptPlugin {
 
         public ScriptedUpsertScriptPlugin() {
         }
@@ -260,10 +268,10 @@ public class UpdateIT extends ESIntegTestCase {
             return "Mock script engine for " + UpdateIT.class + ".testScriptedUpsert";
         }
 
-        public void onModule(ScriptModule module) {
-            module.addScriptEngine(new ScriptEngineRegistry.ScriptEngineRegistration(ScriptedUpsertScriptEngine.class, ScriptedUpsertScriptEngine.NAME, true));
+        @Override
+        public ScriptEngineService getScriptEngineService(Settings settings) {
+            return new ScriptedUpsertScriptEngine();
         }
-
     }
 
     public static class ScriptedUpsertScriptEngine implements ScriptEngineService {
@@ -323,9 +331,14 @@ public class UpdateIT extends ESIntegTestCase {
         public void scriptRemoved(CompiledScript script) {
         }
 
+        @Override
+        public boolean isInlineScriptEnabled() {
+            return true;
+        }
+
     }
 
-    public static class ExtractContextInSourceScriptPlugin extends Plugin {
+    public static class ExtractContextInSourceScriptPlugin extends Plugin implements ScriptPlugin {
 
         public ExtractContextInSourceScriptPlugin() {
         }
@@ -340,10 +353,10 @@ public class UpdateIT extends ESIntegTestCase {
             return "Mock script engine for " + UpdateIT.class;
         }
 
-        public void onModule(ScriptModule module) {
-            module.addScriptEngine(new ScriptEngineRegistry.ScriptEngineRegistration(ExtractContextInSourceScriptEngine.class, ExtractContextInSourceScriptEngine.NAME, true));
+        @Override
+        public ScriptEngineService getScriptEngineService(Settings settings) {
+            return new ExtractContextInSourceScriptEngine();
         }
-
     }
 
     public static class ExtractContextInSourceScriptEngine implements ScriptEngineService {
@@ -404,6 +417,10 @@ public class UpdateIT extends ESIntegTestCase {
         public void scriptRemoved(CompiledScript script) {
         }
 
+        @Override
+        public boolean isInlineScriptEnabled() {
+            return true;
+        }
     }
 
     @Override

+ 7 - 4
modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionPlugin.java

@@ -19,11 +19,14 @@
 
 package org.elasticsearch.script.expression;
 
+import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.plugins.Plugin;
+import org.elasticsearch.plugins.ScriptPlugin;
 import org.elasticsearch.script.ScriptEngineRegistry;
+import org.elasticsearch.script.ScriptEngineService;
 import org.elasticsearch.script.ScriptModule;
 
-public class ExpressionPlugin extends Plugin {
+public class ExpressionPlugin extends Plugin implements ScriptPlugin {
 
     @Override
     public String name() {
@@ -35,8 +38,8 @@ public class ExpressionPlugin extends Plugin {
         return "Lucene expressions integration for Elasticsearch";
     }
 
-    public void onModule(ScriptModule module) {
-        module.addScriptEngine(new ScriptEngineRegistry.ScriptEngineRegistration(ExpressionScriptEngineService.class,
-                        ExpressionScriptEngineService.NAME, true));
+    @Override
+    public ScriptEngineService getScriptEngineService(Settings settings) {
+        return new ExpressionScriptEngineService(settings);
     }
 }

+ 12 - 10
modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionScriptEngineService.java

@@ -29,7 +29,6 @@ import org.apache.lucene.search.SortField;
 import org.elasticsearch.SpecialPermission;
 import org.elasticsearch.common.Nullable;
 import org.elasticsearch.common.component.AbstractComponent;
-import org.elasticsearch.common.inject.Inject;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.index.fielddata.IndexFieldData;
 import org.elasticsearch.index.fielddata.IndexNumericFieldData;
@@ -51,7 +50,6 @@ import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.text.ParseException;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 
@@ -63,7 +61,6 @@ public class ExpressionScriptEngineService extends AbstractComponent implements
 
     public static final String NAME = "expression";
 
-    @Inject
     public ExpressionScriptEngineService(Settings settings) {
         super(settings);
     }
@@ -122,7 +119,7 @@ public class ExpressionScriptEngineService extends AbstractComponent implements
         // instead of complicating SimpleBindings (which should stay simple)
         SimpleBindings bindings = new SimpleBindings();
         ReplaceableConstValueSource specialValue = null;
-        
+
         for (String variable : expr.variables) {
             try {
                 if (variable.equals("_score")) {
@@ -191,10 +188,10 @@ public class ExpressionScriptEngineService extends AbstractComponent implements
                     }
 
                     IndexFieldData<?> fieldData = lookup.doc().fieldDataService().getForField(fieldType);
-                    
+
                     // delegate valuesource creation based on field's type
                     // there are three types of "fields" to expressions, and each one has a different "api" of variables and methods.
-                    
+
                     final ValueSource valueSource;
                     if (fieldType instanceof BaseGeoPointFieldMapper.GeoPointFieldType) {
                         // geo
@@ -203,7 +200,7 @@ public class ExpressionScriptEngineService extends AbstractComponent implements
                         } else {
                             valueSource = GeoField.getMethod(fieldData, fieldname, methodname);
                         }
-                    } else if (fieldType instanceof LegacyDateFieldMapper.DateFieldType || 
+                    } else if (fieldType instanceof LegacyDateFieldMapper.DateFieldType ||
                             fieldType instanceof DateFieldMapper.DateFieldType) {
                         if (dateAccessor) {
                             // date object
@@ -230,7 +227,7 @@ public class ExpressionScriptEngineService extends AbstractComponent implements
                     } else {
                         throw new ParseException("Field [" + fieldname + "] must be numeric, date, or geopoint", 5);
                     }
-                    
+
                     bindings.add(variable, valueSource);
                 }
             } catch (Exception e) {
@@ -238,11 +235,11 @@ public class ExpressionScriptEngineService extends AbstractComponent implements
                 throw convertToScriptException("link error", expr.sourceText, variable, e);
             }
         }
-        
+
         final boolean needsScores = expr.getSortField(bindings, false).needsScores();
         return new ExpressionSearchScript(compiledScript, bindings, specialValue, needsScores);
     }
-    
+
     /**
      * converts a ParseException at compile-time or link-time to a ScriptException
      */
@@ -273,4 +270,9 @@ public class ExpressionScriptEngineService extends AbstractComponent implements
     public void scriptRemoved(CompiledScript script) {
         // Nothing to do
     }
+
+    @Override
+    public boolean isInlineScriptEnabled() {
+        return true;
+    }
 }

+ 7 - 3
modules/lang-groovy/src/main/java/org/elasticsearch/script/groovy/GroovyPlugin.java

@@ -19,11 +19,14 @@
 
 package org.elasticsearch.script.groovy;
 
+import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.plugins.Plugin;
+import org.elasticsearch.plugins.ScriptPlugin;
 import org.elasticsearch.script.ScriptEngineRegistry;
+import org.elasticsearch.script.ScriptEngineService;
 import org.elasticsearch.script.ScriptModule;
 
-public class GroovyPlugin extends Plugin {
+public class GroovyPlugin extends Plugin implements ScriptPlugin {
 
     @Override
     public String name() {
@@ -35,7 +38,8 @@ public class GroovyPlugin extends Plugin {
         return "Groovy scripting integration for Elasticsearch";
     }
 
-    public void onModule(ScriptModule module) {
-        module.addScriptEngine(new ScriptEngineRegistry.ScriptEngineRegistration(GroovyScriptEngineService.class, GroovyScriptEngineService.NAME));
+    @Override
+    public ScriptEngineService getScriptEngineService(Settings settings) {
+        return new GroovyScriptEngineService(settings);
     }
 }

+ 0 - 4
modules/lang-groovy/src/main/java/org/elasticsearch/script/groovy/GroovyScriptEngineService.java

@@ -41,7 +41,6 @@ import org.elasticsearch.bootstrap.BootstrapInfo;
 import org.elasticsearch.common.Nullable;
 import org.elasticsearch.common.component.AbstractComponent;
 import org.elasticsearch.common.hash.MessageDigests;
-import org.elasticsearch.common.inject.Inject;
 import org.elasticsearch.common.logging.ESLogger;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.script.ClassPermission;
@@ -61,9 +60,7 @@ import java.nio.charset.StandardCharsets;
 import java.security.AccessControlContext;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
-import java.util.Collections;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
 /**
@@ -83,7 +80,6 @@ public class GroovyScriptEngineService extends AbstractComponent implements Scri
 
     private final GroovyClassLoader loader;
 
-    @Inject
     public GroovyScriptEngineService(Settings settings) {
         super(settings);
 

+ 7 - 4
modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/MustachePlugin.java

@@ -19,11 +19,14 @@
 
 package org.elasticsearch.script.mustache;
 
+import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.plugins.Plugin;
+import org.elasticsearch.plugins.ScriptPlugin;
 import org.elasticsearch.script.ScriptEngineRegistry;
+import org.elasticsearch.script.ScriptEngineService;
 import org.elasticsearch.script.ScriptModule;
 
-public class MustachePlugin extends Plugin {
+public class MustachePlugin extends Plugin implements ScriptPlugin {
 
     @Override
     public String name() {
@@ -35,8 +38,8 @@ public class MustachePlugin extends Plugin {
         return "Mustache scripting integration for Elasticsearch";
     }
 
-    public void onModule(ScriptModule module) {
-        module.addScriptEngine(new ScriptEngineRegistry.ScriptEngineRegistration(MustacheScriptEngineService.class,
-                        MustacheScriptEngineService.NAME, true));
+    @Override
+    public ScriptEngineService getScriptEngineService(Settings settings) {
+        return new MustacheScriptEngineService(settings);
     }
 }

+ 5 - 3
modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/MustacheScriptEngineService.java

@@ -23,7 +23,6 @@ import com.github.mustachejava.Mustache;
 import org.elasticsearch.SpecialPermission;
 import org.elasticsearch.common.Nullable;
 import org.elasticsearch.common.component.AbstractComponent;
-import org.elasticsearch.common.inject.Inject;
 import org.elasticsearch.common.io.FastStringReader;
 import org.elasticsearch.common.io.UTF8StreamWriter;
 import org.elasticsearch.common.io.stream.BytesStreamOutput;
@@ -40,7 +39,6 @@ import java.lang.ref.SoftReference;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.Collections;
-import java.util.List;
 import java.util.Map;
 
 /**
@@ -77,7 +75,6 @@ public final class MustacheScriptEngineService extends AbstractComponent impleme
     /**
      * @param settings automatically wired by Guice.
      * */
-    @Inject
     public MustacheScriptEngineService(Settings settings) {
         super(settings);
     }
@@ -190,4 +187,9 @@ public final class MustacheScriptEngineService extends AbstractComponent impleme
             return result.bytes();
         }
     }
+
+    @Override
+    public boolean isInlineScriptEnabled() {
+        return true;
+    }
 }

+ 2 - 3
modules/lang-mustache/src/test/java/org/elasticsearch/messy/tests/TemplateQueryParserTests.java

@@ -103,10 +103,9 @@ public class TemplateQueryParserTests extends ESTestCase {
         IndexSettings idxSettings = IndexSettingsModule.newIndexSettings("test", settings);
         Index index = idxSettings.getIndex();
         SettingsModule settingsModule = new SettingsModule(settings);
-        ScriptModule scriptModule = new ScriptModule();
-        scriptModule.prepareSettings(settingsModule);
         // TODO: make this use a mock engine instead of mustache and it will no longer be messy!
-        scriptModule.addScriptEngine(new ScriptEngineRegistry.ScriptEngineRegistration(MustacheScriptEngineService.class, MustacheScriptEngineService.NAME, true));
+        ScriptModule scriptModule = new ScriptModule(new MustacheScriptEngineService(settings));
+        scriptModule.prepareSettings(settingsModule);
         settingsModule.registerSetting(InternalSettingsPlugin.VERSION_CREATED);
         final ThreadPool threadPool = new ThreadPool(settings);
         injector = new ModulesBuilder().add(

+ 7 - 4
modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessPlugin.java

@@ -20,14 +20,17 @@
 package org.elasticsearch.painless;
 
 
+import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.plugins.Plugin;
+import org.elasticsearch.plugins.ScriptPlugin;
 import org.elasticsearch.script.ScriptEngineRegistry;
+import org.elasticsearch.script.ScriptEngineService;
 import org.elasticsearch.script.ScriptModule;
 
 /**
  * Registers Painless as a plugin.
  */
-public final class PainlessPlugin extends Plugin {
+public final class PainlessPlugin extends Plugin implements ScriptPlugin {
 
     // force to pare our definition at startup (not on the user's first script)
     static {
@@ -44,8 +47,8 @@ public final class PainlessPlugin extends Plugin {
         return "Painless scripting language for Elasticsearch";
     }
 
-    public void onModule(final ScriptModule module) {
-        module.addScriptEngine(new ScriptEngineRegistry.ScriptEngineRegistration(
-                        PainlessScriptEngineService.class, PainlessScriptEngineService.NAME, true));
+    @Override
+    public ScriptEngineService getScriptEngineService(Settings settings) {
+        return new PainlessScriptEngineService(settings);
     }
 }

+ 9 - 6
modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngineService.java

@@ -22,7 +22,6 @@ package org.elasticsearch.painless;
 import org.apache.lucene.index.LeafReaderContext;
 import org.elasticsearch.SpecialPermission;
 import org.elasticsearch.common.component.AbstractComponent;
-import org.elasticsearch.common.inject.Inject;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.painless.Compiler.Loader;
 import org.elasticsearch.script.CompiledScript;
@@ -79,7 +78,6 @@ public final class PainlessScriptEngineService extends AbstractComponent impleme
      * Constructor.
      * @param settings The settings to initialize the engine with.
      */
-    @Inject
     public PainlessScriptEngineService(final Settings settings) {
         super(settings);
     }
@@ -101,7 +99,7 @@ public final class PainlessScriptEngineService extends AbstractComponent impleme
     public String getExtension() {
         return NAME;
     }
-    
+
     /**
      * When a script is anonymous (inline), we give it this name.
      */
@@ -220,7 +218,7 @@ public final class PainlessScriptEngineService extends AbstractComponent impleme
     public void close() {
         // Nothing to do.
     }
-    
+
     private ScriptException convertToScriptException(String scriptName, String scriptSource, Throwable t) {
         // create a script stack: this is just the script portion
         List<String> scriptStack = new ArrayList<>();
@@ -258,13 +256,18 @@ public final class PainlessScriptEngineService extends AbstractComponent impleme
         }
         throw new ScriptException("compile error", t, scriptStack, scriptSource, PainlessScriptEngineService.NAME);
     }
-    
+
     // very simple heuristic: +/- 25 chars. can be improved later.
     private int getPreviousStatement(String scriptSource, int offset) {
         return Math.max(0, offset - 25);
     }
-    
+
     private int getNextStatement(String scriptSource, int offset) {
         return Math.min(scriptSource.length(), offset + 25);
     }
+
+    @Override
+    public boolean isInlineScriptEnabled() {
+        return true;
+    }
 }

+ 7 - 3
plugins/lang-javascript/src/main/java/org/elasticsearch/plugin/javascript/JavaScriptPlugin.java

@@ -19,15 +19,18 @@
 
 package org.elasticsearch.plugin.javascript;
 
+import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.plugins.Plugin;
+import org.elasticsearch.plugins.ScriptPlugin;
 import org.elasticsearch.script.ScriptEngineRegistry;
+import org.elasticsearch.script.ScriptEngineService;
 import org.elasticsearch.script.ScriptModule;
 import org.elasticsearch.script.javascript.JavaScriptScriptEngineService;
 
 /**
  *
  */
-public class JavaScriptPlugin extends Plugin {
+public class JavaScriptPlugin extends Plugin implements ScriptPlugin {
 
     static {
         // install rhino policy on plugin init
@@ -44,7 +47,8 @@ public class JavaScriptPlugin extends Plugin {
         return "JavaScript plugin allowing to add javascript scripting support";
     }
 
-    public void onModule(ScriptModule module) {
-        module.addScriptEngine(new ScriptEngineRegistry.ScriptEngineRegistration(JavaScriptScriptEngineService.class, JavaScriptScriptEngineService.NAME));
+    @Override
+    public ScriptEngineService getScriptEngineService(Settings settings) {
+        return new JavaScriptScriptEngineService(settings);
     }
 }

+ 0 - 4
plugins/lang-javascript/src/main/java/org/elasticsearch/script/javascript/JavaScriptScriptEngineService.java

@@ -25,7 +25,6 @@ import org.elasticsearch.SpecialPermission;
 import org.elasticsearch.bootstrap.BootstrapInfo;
 import org.elasticsearch.common.Nullable;
 import org.elasticsearch.common.component.AbstractComponent;
-import org.elasticsearch.common.inject.Inject;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.script.ClassPermission;
 import org.elasticsearch.script.CompiledScript;
@@ -57,8 +56,6 @@ import java.security.AccessController;
 import java.security.CodeSource;
 import java.security.PrivilegedAction;
 import java.security.cert.Certificate;
-import java.util.Arrays;
-import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicLong;
@@ -138,7 +135,6 @@ public class JavaScriptScriptEngineService extends AbstractComponent implements
     /** ensures this engine is initialized */
     public static void init() {}
 
-    @Inject
     public JavaScriptScriptEngineService(Settings settings) {
         super(settings);
 

+ 7 - 3
plugins/lang-python/src/main/java/org/elasticsearch/plugin/python/PythonPlugin.java

@@ -19,15 +19,18 @@
 
 package org.elasticsearch.plugin.python;
 
+import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.plugins.Plugin;
+import org.elasticsearch.plugins.ScriptPlugin;
 import org.elasticsearch.script.ScriptEngineRegistry;
+import org.elasticsearch.script.ScriptEngineService;
 import org.elasticsearch.script.ScriptModule;
 import org.elasticsearch.script.python.PythonScriptEngineService;
 
 /**
  *
  */
-public class PythonPlugin extends Plugin {
+public class PythonPlugin extends Plugin implements ScriptPlugin {
 
     @Override
     public String name() {
@@ -39,7 +42,8 @@ public class PythonPlugin extends Plugin {
         return "Adds support for writing scripts in Python";
     }
 
-    public void onModule(ScriptModule module) {
-        module.addScriptEngine(new ScriptEngineRegistry.ScriptEngineRegistration(PythonScriptEngineService.class, PythonScriptEngineService.NAME));
+    @Override
+    public ScriptEngineService getScriptEngineService(Settings settings) {
+        return new PythonScriptEngineService(settings);
     }
 }

+ 0 - 5
plugins/lang-python/src/main/java/org/elasticsearch/script/python/PythonScriptEngineService.java

@@ -24,7 +24,6 @@ import org.apache.lucene.search.Scorer;
 import org.elasticsearch.SpecialPermission;
 import org.elasticsearch.common.Nullable;
 import org.elasticsearch.common.component.AbstractComponent;
-import org.elasticsearch.common.inject.Inject;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.script.ClassPermission;
 import org.elasticsearch.script.CompiledScript;
@@ -47,9 +46,6 @@ import java.security.AccessController;
 import java.security.Permissions;
 import java.security.PrivilegedAction;
 import java.security.ProtectionDomain;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
 import java.util.Map;
 
 /**
@@ -63,7 +59,6 @@ public class PythonScriptEngineService extends AbstractComponent implements Scri
 
     private final PythonInterpreter interp;
 
-    @Inject
     public PythonScriptEngineService(Settings settings) {
         super(settings);
 

+ 2 - 5
qa/smoke-test-ingest-with-all-dependencies/src/test/java/org/elasticsearch/ingest/AbstractScriptTestCase.java

@@ -44,14 +44,11 @@ public abstract class AbstractScriptTestCase extends ESTestCase {
             .put("path.home", createTempDir())
             .put(ScriptService.SCRIPT_AUTO_RELOAD_ENABLED_SETTING.getKey(), false)
             .build();
-        MustacheScriptEngineService mustache = new MustacheScriptEngineService(settings);
-
-        ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(Arrays.asList(
-            new ScriptEngineRegistry.ScriptEngineRegistration(MustacheScriptEngineService.class, MustacheScriptEngineService.NAME, true)));
+        ScriptEngineRegistry scriptEngineRegistry = new ScriptEngineRegistry(Arrays.asList(new MustacheScriptEngineService(settings)));
         ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(Collections.emptyList());
         ScriptSettings scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
 
-        ScriptService scriptService = new ScriptService(settings, new Environment(settings), Sets.newSet(mustache), null,
+        ScriptService scriptService = new ScriptService(settings, new Environment(settings), null,
                 scriptEngineRegistry, scriptContextRegistry, scriptSettings);
         templateService = new InternalTemplateService(scriptService);
     }

+ 14 - 10
test/framework/src/main/java/org/elasticsearch/script/MockScriptEngine.java

@@ -22,16 +22,16 @@ package org.elasticsearch.script;
 import org.apache.lucene.index.LeafReaderContext;
 import org.elasticsearch.common.Nullable;
 import org.elasticsearch.common.bytes.BytesArray;
+import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.plugins.Plugin;
+import org.elasticsearch.plugins.ScriptPlugin;
 import org.elasticsearch.search.lookup.SearchLookup;
 
 import java.io.IOException;
-import java.util.Collections;
-import java.util.List;
 import java.util.Map;
 
 /**
- * A dummy script engine used for testing. Scripts must be a number. Many 
+ * A dummy script engine used for testing. Scripts must be a number. Many
  * tests rely on the fact this thing returns a String as its compiled form.
  * they even try to serialize it over the network!
  */
@@ -51,8 +51,8 @@ public class MockScriptEngine implements ScriptEngineService {
             this.params = params;
         }
     }
-    
-    public static class TestPlugin extends Plugin {
+
+    public static class TestPlugin extends Plugin implements ScriptPlugin {
 
         public TestPlugin() {
         }
@@ -67,11 +67,10 @@ public class MockScriptEngine implements ScriptEngineService {
             return "Mock script engine for integration tests";
         }
 
-        public void onModule(ScriptModule module) {
-            module.addScriptEngine(new ScriptEngineRegistry.ScriptEngineRegistration(MockScriptEngine.class,
-                            MockScriptEngine.NAME, true));
+        @Override
+        public ScriptEngineService getScriptEngineService(Settings settings) {
+            return new MockScriptEngine();
         }
-
     }
 
     @Override
@@ -91,7 +90,7 @@ public class MockScriptEngine implements ScriptEngineService {
 
     @Override
     public ExecutableScript executable(CompiledScript compiledScript, @Nullable Map<String, Object> vars) {
-        assert compiledScript.compiled() instanceof MockCompiledScript 
+        assert compiledScript.compiled() instanceof MockCompiledScript
           : "do NOT pass compiled scripts from other engines to me, I will fail your test, got: " + compiledScript;
         return new AbstractExecutableScript() {
             @Override
@@ -132,4 +131,9 @@ public class MockScriptEngine implements ScriptEngineService {
     @Override
     public void close() throws IOException {
     }
+
+    @Override
+    public boolean isInlineScriptEnabled() {
+        return true;
+    }
 }

+ 5 - 0
test/framework/src/main/java/org/elasticsearch/search/aggregations/bucket/script/NativeSignificanceScoreScriptNoParams.java

@@ -40,6 +40,11 @@ public class NativeSignificanceScoreScriptNoParams extends TestScript {
         public boolean needsScores() {
             return false;
         }
+
+        @Override
+        public String getName() {
+            return NATIVE_SIGNIFICANCE_SCORE_SCRIPT_NO_PARAMS;
+        }
     }
 
     private NativeSignificanceScoreScriptNoParams() {

+ 5 - 0
test/framework/src/main/java/org/elasticsearch/search/aggregations/bucket/script/NativeSignificanceScoreScriptWithParams.java

@@ -42,6 +42,11 @@ public class NativeSignificanceScoreScriptWithParams extends TestScript {
         public boolean needsScores() {
             return false;
         }
+
+        @Override
+        public String getName() {
+            return NATIVE_SIGNIFICANCE_SCORE_SCRIPT_WITH_PARAMS;
+        }
     }
 
     private NativeSignificanceScoreScriptWithParams(Map<String, Object> params) {

+ 1 - 32
test/framework/src/main/java/org/elasticsearch/test/AbstractQueryTestCase.java

@@ -887,38 +887,7 @@ public abstract class AbstractQueryTestCase<QB extends AbstractQueryBuilder<QB>>
                     new Class[]{Client.class},
                     clientInvocationHandler);
             NamedWriteableRegistry namedWriteableRegistry = new NamedWriteableRegistry();
-            ScriptModule scriptModule = new ScriptModule() {
-                @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();
-                    MockScriptEngine mockScriptEngine = new MockScriptEngine();
-                    Multibinder<ScriptEngineService> multibinder = Multibinder.newSetBinder(binder(), ScriptEngineService.class);
-                    multibinder.addBinding().toInstance(mockScriptEngine);
-                    Set<ScriptEngineService> engines = new HashSet<>();
-                    engines.add(mockScriptEngine);
-                    List<ScriptContext.Plugin> customContexts = new ArrayList<>();
-                    ScriptEngineRegistry scriptEngineRegistry =
-                            new ScriptEngineRegistry(Collections
-                                    .singletonList(new ScriptEngineRegistry.ScriptEngineRegistration(MockScriptEngine.class,
-                                            MockScriptEngine.NAME, true)));
-                    bind(ScriptEngineRegistry.class).toInstance(scriptEngineRegistry);
-                    ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(customContexts);
-                    bind(ScriptContextRegistry.class).toInstance(scriptContextRegistry);
-                    ScriptSettings scriptSettings = new ScriptSettings(scriptEngineRegistry, scriptContextRegistry);
-                    bind(ScriptSettings.class).toInstance(scriptSettings);
-                    try {
-                        ScriptService scriptService = new ScriptService(settings, new Environment(settings), engines, null,
-                                scriptEngineRegistry, scriptContextRegistry, scriptSettings);
-                        bind(ScriptService.class).toInstance(scriptService);
-                    } catch (IOException e) {
-                        throw new IllegalStateException("error while binding ScriptService", e);
-                    }
-                }
-            };
+            ScriptModule scriptModule = newTestScriptModule();
             scriptModule.prepareSettings(settingsModule);
             searchModule = new SearchModule(settings, namedWriteableRegistry) {
                 @Override

+ 29 - 0
test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java

@@ -57,6 +57,12 @@ import org.elasticsearch.index.Index;
 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;
@@ -772,4 +778,27 @@ public abstract class ESTestCase extends LuceneTestCase {
         final AnalysisService analysisService = analysisModule.buildRegistry().build(IndexSettingsModule.newIndexSettings(index, indexSettings));
         return analysisService;
     }
+
+    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);
+                }
+            }
+        };
+    }
 }