Painless: Add Imported Static Method (#33440)

Allow static methods to be imported in Painless and called using just the method name.
This commit is contained in:
Jack Conradson 2018-09-07 18:16:07 -07:00 committed by GitHub
parent 9a404f3def
commit facec187bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 282 additions and 58 deletions

View File

@ -61,12 +61,19 @@ public final class Whitelist {
/** The {@link List} of all the whitelisted Painless classes. */
public final List<WhitelistClass> whitelistClasses;
/** The {@link List} of all the whitelisted static Painless methods. */
public final List<WhitelistMethod> whitelistImportedMethods;
/** The {@link List} of all the whitelisted Painless bindings. */
public final List<WhitelistBinding> whitelistBindings;
/** Standard constructor. All values must be not {@code null}. */
public Whitelist(ClassLoader classLoader, List<WhitelistClass> whitelistClasses, List<WhitelistBinding> whitelistBindings) {
public Whitelist(ClassLoader classLoader, List<WhitelistClass> whitelistClasses,
List<WhitelistMethod> whitelistImportedMethods, List<WhitelistBinding> whitelistBindings) {
this.classLoader = Objects.requireNonNull(classLoader);
this.whitelistClasses = Collections.unmodifiableList(Objects.requireNonNull(whitelistClasses));
this.whitelistImportedMethods = Collections.unmodifiableList(Objects.requireNonNull(whitelistImportedMethods));
this.whitelistBindings = Collections.unmodifiableList(Objects.requireNonNull(whitelistBindings));
}
}

View File

@ -133,6 +133,7 @@ public final class WhitelistLoader {
*/
public static Whitelist loadFromResourceFiles(Class<?> resource, String... filepaths) {
List<WhitelistClass> whitelistClasses = new ArrayList<>();
List<WhitelistMethod> whitelistStatics = new ArrayList<>();
List<WhitelistBinding> whitelistBindings = new ArrayList<>();
// Execute a single pass through the whitelist text files. This will gather all the
@ -192,18 +193,18 @@ public final class WhitelistLoader {
whitelistConstructors = new ArrayList<>();
whitelistMethods = new ArrayList<>();
whitelistFields = new ArrayList<>();
} else if (line.startsWith("static ")) {
} else if (line.startsWith("static_import ")) {
// Ensure the final token of the line is '{'.
if (line.endsWith("{") == false) {
throw new IllegalArgumentException(
"invalid static definition: failed to parse static opening bracket [" + line + "]");
"invalid static import definition: failed to parse static import opening bracket [" + line + "]");
}
if (parseType != null) {
throw new IllegalArgumentException("invalid definition: cannot embed static definition [" + line + "]");
throw new IllegalArgumentException("invalid definition: cannot embed static import definition [" + line + "]");
}
parseType = "static";
parseType = "static_import";
// Handle the end of a definition and reset all previously gathered values.
// Expects the following format: '}' '\n'
@ -229,9 +230,9 @@ public final class WhitelistLoader {
// Reset the parseType.
parseType = null;
// Handle static definition types.
// Expects the following format: ID ID '(' ( ID ( ',' ID )* )? ')' 'bound_to' ID '\n'
} else if ("static".equals(parseType)) {
// Handle static import definition types.
// Expects the following format: ID ID '(' ( ID ( ',' ID )* )? ')' ( 'from_class' | 'bound_to' ) ID '\n'
} else if ("static_import".equals(parseType)) {
// Mark the origin of this parsable object.
String origin = "[" + filepath + "]:[" + number + "]";
@ -240,7 +241,7 @@ public final class WhitelistLoader {
if (parameterStartIndex == -1) {
throw new IllegalArgumentException(
"illegal static definition: start of method parameters not found [" + line + "]");
"illegal static import definition: start of method parameters not found [" + line + "]");
}
String[] tokens = line.substring(0, parameterStartIndex).trim().split("\\s+");
@ -261,7 +262,7 @@ public final class WhitelistLoader {
if (parameterEndIndex == -1) {
throw new IllegalArgumentException(
"illegal static definition: end of method parameters not found [" + line + "]");
"illegal static import definition: end of method parameters not found [" + line + "]");
}
String[] canonicalTypeNameParameters =
@ -272,39 +273,37 @@ public final class WhitelistLoader {
canonicalTypeNameParameters = new String[0];
}
// Parse the static type and class.
// Parse the static import type and class.
tokens = line.substring(parameterEndIndex + 1).trim().split("\\s+");
String staticType;
String staticImportType;
String targetJavaClassName;
// Based on the number of tokens, look up the type and class.
if (tokens.length == 2) {
staticType = tokens[0];
staticImportType = tokens[0];
targetJavaClassName = tokens[1];
} else {
throw new IllegalArgumentException("invalid static definition: unexpected format [" + line + "]");
}
// Check the static type is valid.
if ("bound_to".equals(staticType) == false) {
throw new IllegalArgumentException(
"invalid static definition: unexpected static type [" + staticType + "] [" + line + "]");
throw new IllegalArgumentException("invalid static import definition: unexpected format [" + line + "]");
}
// Add a static import method or binding depending on the static import type.
if ("from_class".equals(staticImportType)) {
whitelistStatics.add(new WhitelistMethod(origin, targetJavaClassName,
methodName, returnCanonicalTypeName, Arrays.asList(canonicalTypeNameParameters)));
} else if ("bound_to".equals(staticImportType)) {
whitelistBindings.add(new WhitelistBinding(origin, targetJavaClassName,
methodName, returnCanonicalTypeName, Arrays.asList(canonicalTypeNameParameters)));
} else {
throw new IllegalArgumentException("invalid static import definition: " +
"unexpected static import type [" + staticImportType + "] [" + line + "]");
}
// Handle class definition types.
} else if ("class".equals(parseType)) {
// Mark the origin of this parsable object.
String origin = "[" + filepath + "]:[" + number + "]";
// Ensure we have a defined class before adding any constructors, methods, augmented methods, or fields.
if (parseType == null) {
throw new IllegalArgumentException("invalid definition: expected one of ['class', 'static'] [" + line + "]");
}
// Handle the case for a constructor definition.
// Expects the following format: '(' ( ID ( ',' ID )* )? ')' '\n'
if (line.startsWith("(")) {
@ -393,7 +392,7 @@ public final class WhitelistLoader {
ClassLoader loader = AccessController.doPrivileged((PrivilegedAction<ClassLoader>)resource::getClassLoader);
return new Whitelist(loader, whitelistClasses, whitelistBindings);
return new Whitelist(loader, whitelistClasses, whitelistStatics, whitelistBindings);
}
private WhitelistLoader() {}

View File

@ -24,6 +24,21 @@ import java.util.function.Function;
/** Currently just a dummy class for testing a few features not yet exposed by whitelist! */
public class FeatureTest {
/** static method that returns true */
public static boolean overloadedStatic() {
return true;
}
/** static method that returns what you ask it */
public static boolean overloadedStatic(boolean whatToReturn) {
return whatToReturn;
}
/** static method only whitelisted as a static */
public static float staticAddFloatsTest(float x, float y) {
return x + y;
}
private int x;
private int y;
public int z;
@ -58,21 +73,12 @@ public class FeatureTest {
this.y = y;
}
/** static method that returns true */
public static boolean overloadedStatic() {
return true;
}
/** static method that returns what you ask it */
public static boolean overloadedStatic(boolean whatToReturn) {
return whatToReturn;
}
/** method taking two functions! */
public Object twoFunctionsOfX(Function<Object,Object> f, Function<Object,Object> g) {
return f.apply(g.apply(x));
}
/** method to take in a list */
public void listInput(List<Object> list) {
}

View File

@ -37,16 +37,23 @@ public final class PainlessLookup {
private final Map<String, Class<?>> canonicalClassNamesToClasses;
private final Map<Class<?>, PainlessClass> classesToPainlessClasses;
private final Map<String, PainlessMethod> painlessMethodKeysToImportedPainlessMethods;
private final Map<String, PainlessBinding> painlessMethodKeysToPainlessBindings;
PainlessLookup(Map<String, Class<?>> canonicalClassNamesToClasses, Map<Class<?>, PainlessClass> classesToPainlessClasses,
Map<String, PainlessMethod> painlessMethodKeysToImportedPainlessMethods,
Map<String, PainlessBinding> painlessMethodKeysToPainlessBindings) {
Objects.requireNonNull(canonicalClassNamesToClasses);
Objects.requireNonNull(classesToPainlessClasses);
Objects.requireNonNull(painlessMethodKeysToImportedPainlessMethods);
Objects.requireNonNull(painlessMethodKeysToPainlessBindings);
this.canonicalClassNamesToClasses = Collections.unmodifiableMap(canonicalClassNamesToClasses);
this.classesToPainlessClasses = Collections.unmodifiableMap(classesToPainlessClasses);
this.painlessMethodKeysToImportedPainlessMethods = Collections.unmodifiableMap(painlessMethodKeysToImportedPainlessMethods);
this.painlessMethodKeysToPainlessBindings = Collections.unmodifiableMap(painlessMethodKeysToPainlessBindings);
}
@ -167,6 +174,14 @@ public final class PainlessLookup {
return painlessField;
}
public PainlessMethod lookupImportedPainlessMethod(String methodName, int arity) {
Objects.requireNonNull(methodName);
String painlessMethodKey = buildPainlessMethodKey(methodName, arity);
return painlessMethodKeysToImportedPainlessMethods.get(painlessMethodKey);
}
public PainlessBinding lookupPainlessBinding(String methodName, int arity) {
Objects.requireNonNull(methodName);

View File

@ -243,6 +243,14 @@ public final class PainlessLookupBuilder {
}
}
for (WhitelistMethod whitelistStatic : whitelist.whitelistImportedMethods) {
origin = whitelistStatic.origin;
painlessLookupBuilder.addImportedPainlessMethod(
whitelist.classLoader, whitelistStatic.augmentedCanonicalClassName,
whitelistStatic.methodName, whitelistStatic.returnCanonicalTypeName,
whitelistStatic.canonicalTypeNameParameters);
}
for (WhitelistBinding whitelistBinding : whitelist.whitelistBindings) {
origin = whitelistBinding.origin;
painlessLookupBuilder.addPainlessBinding(
@ -261,12 +269,14 @@ public final class PainlessLookupBuilder {
private final Map<String, Class<?>> canonicalClassNamesToClasses;
private final Map<Class<?>, PainlessClassBuilder> classesToPainlessClassBuilders;
private final Map<String, PainlessMethod> painlessMethodKeysToImportedPainlessMethods;
private final Map<String, PainlessBinding> painlessMethodKeysToPainlessBindings;
public PainlessLookupBuilder() {
canonicalClassNamesToClasses = new HashMap<>();
classesToPainlessClassBuilders = new HashMap<>();
painlessMethodKeysToImportedPainlessMethods = new HashMap<>();
painlessMethodKeysToPainlessBindings = new HashMap<>();
}
@ -513,8 +523,9 @@ public final class PainlessLookupBuilder {
addPainlessMethod(targetClass, augmentedClass, methodName, returnType, typeParameters);
}
public void addPainlessMethod(Class<?> targetClass, Class<?> augmentedClass, String methodName,
Class<?> returnType, List<Class<?>> typeParameters) {
public void addPainlessMethod(Class<?> targetClass, Class<?> augmentedClass,
String methodName, Class<?> returnType, List<Class<?>> typeParameters) {
Objects.requireNonNull(targetClass);
Objects.requireNonNull(methodName);
Objects.requireNonNull(returnType);
@ -573,6 +584,12 @@ public final class PainlessLookupBuilder {
} else {
try {
javaMethod = augmentedClass.getMethod(methodName, javaTypeParameters.toArray(new Class<?>[typeParametersSize]));
if (Modifier.isStatic(javaMethod.getModifiers()) == false) {
throw new IllegalArgumentException("method [[" + targetCanonicalClassName + "], [" + methodName + "], " +
typesToCanonicalTypeNames(typeParameters) + "] with augmented class " +
"[" + typeToCanonicalTypeName(augmentedClass) + "] must be static");
}
} catch (NoSuchMethodException nsme) {
throw new IllegalArgumentException("method reflection object [[" + targetCanonicalClassName + "], " +
"[" + methodName + "], " + typesToCanonicalTypeNames(typeParameters) + "] not found " +
@ -620,7 +637,7 @@ public final class PainlessLookupBuilder {
"with the same arity and different return type or type parameters");
}
} else {
PainlessMethod painlessMethod = painlessClassBuilder.staticMethods.get(painlessMethodKey);
PainlessMethod painlessMethod = painlessClassBuilder.methods.get(painlessMethodKey);
if (painlessMethod == null) {
MethodHandle methodHandle;
@ -788,6 +805,146 @@ public final class PainlessLookupBuilder {
}
}
public void addImportedPainlessMethod(ClassLoader classLoader, String targetCanonicalClassName,
String methodName, String returnCanonicalTypeName, List<String> canonicalTypeNameParameters) {
Objects.requireNonNull(classLoader);
Objects.requireNonNull(targetCanonicalClassName);
Objects.requireNonNull(methodName);
Objects.requireNonNull(returnCanonicalTypeName);
Objects.requireNonNull(canonicalTypeNameParameters);
Class<?> targetClass = canonicalClassNamesToClasses.get(targetCanonicalClassName);
if (targetClass == null) {
throw new IllegalArgumentException("target class [" + targetCanonicalClassName + "] not found for imported method " +
"[[" + targetCanonicalClassName + "], [" + methodName + "], " + canonicalTypeNameParameters + "]");
}
List<Class<?>> typeParameters = new ArrayList<>(canonicalTypeNameParameters.size());
for (String canonicalTypeNameParameter : canonicalTypeNameParameters) {
Class<?> typeParameter = canonicalTypeNameToType(canonicalTypeNameParameter);
if (typeParameter == null) {
throw new IllegalArgumentException("type parameter [" + canonicalTypeNameParameter + "] not found for imported method " +
"[[" + targetCanonicalClassName + "], [" + methodName + "], " + canonicalTypeNameParameters + "]");
}
typeParameters.add(typeParameter);
}
Class<?> returnType = canonicalTypeNameToType(returnCanonicalTypeName);
if (returnType == null) {
throw new IllegalArgumentException("return type [" + returnCanonicalTypeName + "] not found for imported method " +
"[[" + targetCanonicalClassName + "], [" + methodName + "], " + canonicalTypeNameParameters + "]");
}
addImportedPainlessMethod(targetClass, methodName, returnType, typeParameters);
}
public void addImportedPainlessMethod(Class<?> targetClass, String methodName, Class<?> returnType, List<Class<?>> typeParameters) {
Objects.requireNonNull(targetClass);
Objects.requireNonNull(methodName);
Objects.requireNonNull(returnType);
Objects.requireNonNull(typeParameters);
if (targetClass == def.class) {
throw new IllegalArgumentException("cannot add imported method from reserved class [" + DEF_CLASS_NAME + "]");
}
String targetCanonicalClassName = typeToCanonicalTypeName(targetClass);
if (METHOD_NAME_PATTERN.matcher(methodName).matches() == false) {
throw new IllegalArgumentException(
"invalid imported method name [" + methodName + "] for target class [" + targetCanonicalClassName + "].");
}
PainlessClassBuilder painlessClassBuilder = classesToPainlessClassBuilders.get(targetClass);
if (painlessClassBuilder == null) {
throw new IllegalArgumentException("target class [" + targetCanonicalClassName + "] not found for imported method " +
"[[" + targetCanonicalClassName + "], [" + methodName + "], " + typesToCanonicalTypeNames(typeParameters) + "]");
}
int typeParametersSize = typeParameters.size();
List<Class<?>> javaTypeParameters = new ArrayList<>(typeParametersSize);
for (Class<?> typeParameter : typeParameters) {
if (isValidType(typeParameter) == false) {
throw new IllegalArgumentException("type parameter [" + typeToCanonicalTypeName(typeParameter) + "] " +
"not found for imported method [[" + targetCanonicalClassName + "], [" + methodName + "], " +
typesToCanonicalTypeNames(typeParameters) + "]");
}
javaTypeParameters.add(typeToJavaType(typeParameter));
}
if (isValidType(returnType) == false) {
throw new IllegalArgumentException("return type [" + typeToCanonicalTypeName(returnType) + "] not found for imported method " +
"[[" + targetCanonicalClassName + "], [" + methodName + "], " + typesToCanonicalTypeNames(typeParameters) + "]");
}
Method javaMethod;
try {
javaMethod = targetClass.getMethod(methodName, javaTypeParameters.toArray(new Class<?>[typeParametersSize]));
} catch (NoSuchMethodException nsme) {
throw new IllegalArgumentException("imported method reflection object [[" + targetCanonicalClassName + "], " +
"[" + methodName + "], " + typesToCanonicalTypeNames(typeParameters) + "] not found", nsme);
}
if (javaMethod.getReturnType() != typeToJavaType(returnType)) {
throw new IllegalArgumentException("return type [" + typeToCanonicalTypeName(javaMethod.getReturnType()) + "] " +
"does not match the specified returned type [" + typeToCanonicalTypeName(returnType) + "] " +
"for imported method [[" + targetClass.getCanonicalName() + "], [" + methodName + "], " +
typesToCanonicalTypeNames(typeParameters) + "]");
}
if (Modifier.isStatic(javaMethod.getModifiers()) == false) {
throw new IllegalArgumentException("imported method [[" + targetClass.getCanonicalName() + "], [" + methodName + "], " +
typesToCanonicalTypeNames(typeParameters) + "] must be static");
}
String painlessMethodKey = buildPainlessMethodKey(methodName, typeParametersSize);
if (painlessMethodKeysToPainlessBindings.containsKey(painlessMethodKey)) {
throw new IllegalArgumentException("imported method and binding cannot have the same name [" + methodName + "]");
}
PainlessMethod importedPainlessMethod = painlessMethodKeysToImportedPainlessMethods.get(painlessMethodKey);
if (importedPainlessMethod == null) {
MethodHandle methodHandle;
try {
methodHandle = MethodHandles.publicLookup().in(targetClass).unreflect(javaMethod);
} catch (IllegalAccessException iae) {
throw new IllegalArgumentException("imported method handle [[" + targetClass.getCanonicalName() + "], " +
"[" + methodName + "], " + typesToCanonicalTypeNames(typeParameters) + "] not found", iae);
}
MethodType methodType = methodHandle.type();
importedPainlessMethod = painlessMethodCache.computeIfAbsent(
new PainlessMethodCacheKey(targetClass, methodName, returnType, typeParameters),
key -> new PainlessMethod(javaMethod, targetClass, returnType, typeParameters, methodHandle, methodType));
painlessMethodKeysToImportedPainlessMethods.put(painlessMethodKey, importedPainlessMethod);
} else if (importedPainlessMethod.returnType == returnType &&
importedPainlessMethod.typeParameters.equals(typeParameters) == false) {
throw new IllegalArgumentException("cannot have imported methods " +
"[[" + targetCanonicalClassName + "], [" + methodName + "], " +
"[" + typeToCanonicalTypeName(returnType) + "], " +
typesToCanonicalTypeNames(typeParameters) + "] and " +
"[[" + targetCanonicalClassName + "], [" + methodName + "], " +
"[" + typeToCanonicalTypeName(importedPainlessMethod.returnType) + "], " +
typesToCanonicalTypeNames(importedPainlessMethod.typeParameters) + "] " +
"with the same arity and different return type or type parameters");
}
}
public void addPainlessBinding(ClassLoader classLoader, String targetJavaClassName,
String methodName, String returnCanonicalTypeName, List<String> canonicalTypeNameParameters) {
@ -937,6 +1094,11 @@ public final class PainlessLookupBuilder {
}
String painlessMethodKey = buildPainlessMethodKey(methodName, constructorTypeParametersSize + methodTypeParametersSize);
if (painlessMethodKeysToImportedPainlessMethods.containsKey(painlessMethodKey)) {
throw new IllegalArgumentException("binding and imported method cannot have the same name [" + methodName + "]");
}
PainlessBinding painlessBinding = painlessMethodKeysToPainlessBindings.get(painlessMethodKey);
if (painlessBinding == null) {
@ -976,7 +1138,8 @@ public final class PainlessLookupBuilder {
classesToPainlessClasses.put(painlessClassBuilderEntry.getKey(), painlessClassBuilderEntry.getValue().build());
}
return new PainlessLookup(canonicalClassNamesToClasses, classesToPainlessClasses, painlessMethodKeysToPainlessBindings);
return new PainlessLookup(canonicalClassNamesToClasses, classesToPainlessClasses,
painlessMethodKeysToImportedPainlessMethods, painlessMethodKeysToPainlessBindings);
}
private void copyPainlessClassMembers() {

View File

@ -25,6 +25,7 @@ import org.elasticsearch.painless.Locals.LocalMethod;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.lookup.PainlessBinding;
import org.elasticsearch.painless.lookup.PainlessMethod;
import org.objectweb.asm.Label;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.Method;
@ -45,6 +46,7 @@ public final class ECallLocal extends AExpression {
private final List<AExpression> arguments;
private LocalMethod method = null;
private PainlessMethod imported = null;
private PainlessBinding binding = null;
public ECallLocal(Location location, String name, List<AExpression> arguments) {
@ -65,16 +67,33 @@ public final class ECallLocal extends AExpression {
void analyze(Locals locals) {
method = locals.getMethod(name, arguments.size());
if (method == null) {
imported = locals.getPainlessLookup().lookupImportedPainlessMethod(name, arguments.size());
if (imported == null) {
binding = locals.getPainlessLookup().lookupPainlessBinding(name, arguments.size());
if (binding == null) {
throw createError(new IllegalArgumentException("Unknown call [" + name + "] with [" + arguments.size() + "] arguments."));
throw createError(
new IllegalArgumentException("Unknown call [" + name + "] with [" + arguments.size() + "] arguments."));
}
}
}
List<Class<?>> typeParameters = new ArrayList<>(method == null ? binding.typeParameters : method.typeParameters);
List<Class<?>> typeParameters;
if (method != null) {
typeParameters = new ArrayList<>(method.typeParameters);
actual = method.returnType;
} else if (imported != null) {
typeParameters = new ArrayList<>(imported.typeParameters);
actual = imported.returnType;
} else if (binding != null) {
typeParameters = new ArrayList<>(binding.typeParameters);
actual = binding.returnType;
} else {
throw new IllegalStateException("Illegal tree structure.");
}
for (int argument = 0; argument < arguments.size(); ++argument) {
AExpression expression = arguments.get(argument);
@ -86,14 +105,26 @@ public final class ECallLocal extends AExpression {
}
statement = true;
actual = method == null ? binding.returnType : method.returnType;
}
@Override
void write(MethodWriter writer, Globals globals) {
writer.writeDebugInfo(location);
if (method == null) {
if (method != null) {
for (AExpression argument : arguments) {
argument.write(writer, globals);
}
writer.invokeStatic(CLASS_TYPE, new Method(method.name, method.methodType.toMethodDescriptorString()));
} else if (imported != null) {
for (AExpression argument : arguments) {
argument.write(writer, globals);
}
writer.invokeStatic(Type.getType(imported.targetClass),
new Method(imported.javaMethod.getName(), imported.methodType.toMethodDescriptorString()));
} else if (binding != null) {
String name = globals.addBinding(binding.javaConstructor.getDeclaringClass());
Type type = Type.getType(binding.javaConstructor.getDeclaringClass());
int javaConstructorParameterCount = binding.javaConstructor.getParameterCount();
@ -124,11 +155,7 @@ public final class ECallLocal extends AExpression {
writer.invokeVirtual(type, Method.getMethod(binding.javaMethod));
} else {
for (AExpression argument : arguments) {
argument.write(writer, globals);
}
writer.invokeStatic(CLASS_TYPE, new Method(method.name, method.methodType.toMethodDescriptorString()));
throw new IllegalStateException("Illegal tree structure.");
}
}

View File

@ -176,6 +176,7 @@ class org.elasticsearch.painless.FeatureTest no_import {
}
# for testing
static {
static_import {
float staticAddFloatsTest(float, float) from_class org.elasticsearch.painless.FeatureTest
int testAddWithState(int, int, int, double) bound_to org.elasticsearch.painless.BindingTest
}

View File

@ -133,4 +133,8 @@ public class BasicAPITests extends ScriptTestCase {
public void testNoSemicolon() {
assertEquals(true, exec("def x = true; if (x) return x"));
}
public void testStatic() {
assertEquals(15.5f, exec("staticAddFloatsTest(6.5f, 9.0f)"));
}
}

View File

@ -47,6 +47,8 @@ import static org.hamcrest.Matchers.hasSize;
* Typically just asserts the output of {@code exec()}
*/
public abstract class ScriptTestCase extends ESTestCase {
private static final PainlessLookup PAINLESS_LOOKUP = PainlessLookupBuilder.buildFromWhitelists(Whitelist.BASE_WHITELISTS);
protected PainlessScriptEngine scriptEngine;
@Before
@ -92,12 +94,12 @@ public abstract class ScriptTestCase extends ESTestCase {
public Object exec(String script, Map<String, Object> vars, Map<String,String> compileParams, Scorer scorer, boolean picky) {
// test for ambiguity errors before running the actual script if picky is true
if (picky) {
PainlessLookup painlessLookup = PainlessLookupBuilder.buildFromWhitelists(Whitelist.BASE_WHITELISTS);
ScriptClassInfo scriptClassInfo = new ScriptClassInfo(painlessLookup, GenericElasticsearchScript.class);
ScriptClassInfo scriptClassInfo = new ScriptClassInfo(PAINLESS_LOOKUP, GenericElasticsearchScript.class);
CompilerSettings pickySettings = new CompilerSettings();
pickySettings.setPicky(true);
pickySettings.setRegexesEnabled(CompilerSettings.REGEX_ENABLED.get(scriptEngineSettings()));
Walker.buildPainlessTree(scriptClassInfo, new MainMethodReserved(), getTestName(), script, pickySettings, painlessLookup, null);
Walker.buildPainlessTree(
scriptClassInfo, new MainMethodReserved(), getTestName(), script, pickySettings, PAINLESS_LOOKUP, null);
}
// test actual script execution
ExecutableScript.Factory factory = scriptEngine.compile(null, script, ExecutableScript.CONTEXT, compileParams);