From ae05ce0551f23c7709e30b3ce26ed0ce4223ebdb Mon Sep 17 00:00:00 2001 From: kimchy Date: Thu, 14 Oct 2010 16:14:23 +0200 Subject: [PATCH] Scripting: Allow to define scripts within `config/scripts`, automatically compiled and can be referenced by name, closes #429. --- .../script/ScriptEngineService.java | 2 + .../elasticsearch/script/ScriptService.java | 59 ++++++++++++++++++- .../script/mvel/MvelScriptEngineService.java | 4 ++ .../groovy/GroovyScriptEngineService.java | 4 ++ .../JavaScriptScriptEngineService.java | 4 ++ .../python/PythonScriptEngineService.java | 4 ++ 6 files changed, 74 insertions(+), 3 deletions(-) diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/script/ScriptEngineService.java b/modules/elasticsearch/src/main/java/org/elasticsearch/script/ScriptEngineService.java index fe5e67f0410..6bf27e54712 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/script/ScriptEngineService.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/script/ScriptEngineService.java @@ -28,6 +28,8 @@ public interface ScriptEngineService { String[] types(); + String[] extensions(); + Object compile(String script); ExecutableScript executable(Object compiledScript, Map vars); diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/script/ScriptService.java b/modules/elasticsearch/src/main/java/org/elasticsearch/script/ScriptService.java index e0405db98ec..245cc0d817c 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/script/ScriptService.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/script/ScriptService.java @@ -25,9 +25,15 @@ import org.elasticsearch.common.collect.ImmutableSet; import org.elasticsearch.common.collect.MapMaker; import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.io.Streams; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ConcurrentCollections; +import org.elasticsearch.env.Environment; import org.elasticsearch.script.mvel.MvelScriptEngineService; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStreamReader; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentMap; @@ -41,16 +47,18 @@ public class ScriptService extends AbstractComponent { private final ImmutableMap scriptEngines; + private final ConcurrentMap staticCache = ConcurrentCollections.newConcurrentMap(); + private final ConcurrentMap cache = new MapMaker().softValues().makeMap(); public ScriptService(Settings settings) { - this(settings, ImmutableSet.builder() + this(settings, new Environment(), ImmutableSet.builder() .add(new MvelScriptEngineService(settings)) .build() ); } - @Inject public ScriptService(Settings settings, Set scriptEngines) { + @Inject public ScriptService(Settings settings, Environment env, Set scriptEngines) { super(settings); this.defaultLang = componentSettings.get("default_lang", "mvel"); @@ -62,6 +70,47 @@ public class ScriptService extends AbstractComponent { } } this.scriptEngines = builder.build(); + + // compile static scripts + File scriptsFile = new File(env.configFile(), "scripts"); + if (scriptsFile.exists()) { + processScriptsDirectory("", scriptsFile); + } + } + + private void processScriptsDirectory(String prefix, File dir) { + for (File file : dir.listFiles()) { + if (file.isDirectory()) { + processScriptsDirectory(prefix + file.getName() + "_", file); + } else { + int extIndex = file.getName().lastIndexOf('.'); + if (extIndex != -1) { + String ext = file.getName().substring(extIndex + 1); + String scriptName = prefix + file.getName().substring(0, extIndex); + boolean found = false; + for (ScriptEngineService engineService : scriptEngines.values()) { + for (String s : engineService.extensions()) { + if (s.equals(ext)) { + found = true; + try { + String script = Streams.copyToString(new InputStreamReader(new FileInputStream(file), "UTF-8")); + staticCache.put(scriptName, new CompiledScript(engineService.types()[0], engineService.compile(script))); + } catch (Exception e) { + logger.warn("failed to load/compile script [{}]", e, scriptName); + } + break; + } + } + if (found) { + break; + } + } + if (!found) { + logger.warn("no script engine found for [{}]", ext); + } + } + } + } } public void close() { @@ -75,7 +124,11 @@ public class ScriptService extends AbstractComponent { } public CompiledScript compile(String lang, String script) { - CompiledScript compiled = cache.get(script); + CompiledScript compiled = staticCache.get(script); + if (compiled != null) { + return compiled; + } + compiled = cache.get(script); if (compiled != null) { return compiled; } diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/script/mvel/MvelScriptEngineService.java b/modules/elasticsearch/src/main/java/org/elasticsearch/script/mvel/MvelScriptEngineService.java index d1fa3e6baf7..dc8dc26b475 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/script/mvel/MvelScriptEngineService.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/script/mvel/MvelScriptEngineService.java @@ -63,6 +63,10 @@ public class MvelScriptEngineService extends AbstractComponent implements Script return new String[]{"mvel"}; } + @Override public String[] extensions() { + return new String[]{"mvel"}; + } + @Override public Object compile(String script) { return MVEL.compileExpression(script, parserContext); } diff --git a/plugins/lang/groovy/src/main/java/org/elasticsearch/script/groovy/GroovyScriptEngineService.java b/plugins/lang/groovy/src/main/java/org/elasticsearch/script/groovy/GroovyScriptEngineService.java index 5f9dd970f32..ad28d489310 100644 --- a/plugins/lang/groovy/src/main/java/org/elasticsearch/script/groovy/GroovyScriptEngineService.java +++ b/plugins/lang/groovy/src/main/java/org/elasticsearch/script/groovy/GroovyScriptEngineService.java @@ -54,6 +54,10 @@ public class GroovyScriptEngineService extends AbstractComponent implements Scri return new String[]{"groovy"}; } + @Override public String[] extensions() { + return new String[]{"groovy"}; + } + @Override public Object compile(String script) { return loader.parseClass(script, generateScriptName()); } diff --git a/plugins/lang/javascript/src/main/java/org/elasticsearch/script/javascript/JavaScriptScriptEngineService.java b/plugins/lang/javascript/src/main/java/org/elasticsearch/script/javascript/JavaScriptScriptEngineService.java index 858b0edb082..0db21eeb99d 100644 --- a/plugins/lang/javascript/src/main/java/org/elasticsearch/script/javascript/JavaScriptScriptEngineService.java +++ b/plugins/lang/javascript/src/main/java/org/elasticsearch/script/javascript/JavaScriptScriptEngineService.java @@ -68,6 +68,10 @@ public class JavaScriptScriptEngineService extends AbstractComponent implements return new String[]{"js", "javascript"}; } + @Override public String[] extensions() { + return new String[]{"js"}; + } + @Override public Object compile(String script) { Context ctx = Context.enter(); try { diff --git a/plugins/lang/python/src/main/java/org/elasticsearch/script/python/PythonScriptEngineService.java b/plugins/lang/python/src/main/java/org/elasticsearch/script/python/PythonScriptEngineService.java index 30365460bfe..0df71259244 100644 --- a/plugins/lang/python/src/main/java/org/elasticsearch/script/python/PythonScriptEngineService.java +++ b/plugins/lang/python/src/main/java/org/elasticsearch/script/python/PythonScriptEngineService.java @@ -50,6 +50,10 @@ public class PythonScriptEngineService extends AbstractComponent implements Scri return new String[]{"python"}; } + @Override public String[] extensions() { + return new String[]{"py"}; + } + @Override public Object compile(String script) { return interp.compile(script); }