Skip to content

Commit bf59c6d

Browse files
committed
Painless: Decouple PainlessLookupBuilder and Whitelists (#32346)
Implements a static function in PainlessLookupBuilder that contains all the logic related to Whitelist. PainlessLookupBuilder is available for use in loading from methods beyond Whitelist now.
1 parent dd6b26d commit bf59c6d

14 files changed

+75
-92
lines changed

modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngine.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,10 @@ public PainlessScriptEngine(Settings settings, Map<ScriptContext<?>, List<Whitel
103103
ScriptContext<?> context = entry.getKey();
104104
if (context.instanceClazz.equals(SearchScript.class) || context.instanceClazz.equals(ExecutableScript.class)) {
105105
contextsToCompilers.put(context, new Compiler(GenericElasticsearchScript.class,
106-
new PainlessLookupBuilder(entry.getValue()).build()));
106+
PainlessLookupBuilder.buildFromWhitelists(entry.getValue())));
107107
} else {
108108
contextsToCompilers.put(context, new Compiler(context.instanceClazz,
109-
new PainlessLookupBuilder(entry.getValue()).build()));
109+
PainlessLookupBuilder.buildFromWhitelists(entry.getValue())));
110110
}
111111
}
112112

modules/lang-painless/src/main/java/org/elasticsearch/painless/lookup/PainlessLookupBuilder.java

Lines changed: 45 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -126,14 +126,55 @@ public int hashCode() {
126126
private static final Pattern METHOD_NAME_PATTERN = Pattern.compile("^[_a-zA-Z][_a-zA-Z0-9]*$");
127127
private static final Pattern FIELD_NAME_PATTERN = Pattern.compile("^[_a-zA-Z][_a-zA-Z0-9]*$");
128128

129-
private final List<Whitelist> whitelists;
129+
public static PainlessLookup buildFromWhitelists(List<Whitelist> whitelists) {
130+
PainlessLookupBuilder painlessLookupBuilder = new PainlessLookupBuilder();
131+
String origin = "internal error";
132+
133+
try {
134+
for (Whitelist whitelist : whitelists) {
135+
for (WhitelistClass whitelistClass : whitelist.whitelistStructs) {
136+
origin = whitelistClass.origin;
137+
painlessLookupBuilder.addPainlessClass(
138+
whitelist.javaClassLoader, whitelistClass.javaClassName, whitelistClass.onlyFQNJavaClassName == false);
139+
}
140+
}
141+
142+
for (Whitelist whitelist : whitelists) {
143+
for (WhitelistClass whitelistClass : whitelist.whitelistStructs) {
144+
String targetCanonicalClassName = whitelistClass.javaClassName.replace('$', '.');
145+
146+
for (WhitelistConstructor whitelistConstructor : whitelistClass.whitelistConstructors) {
147+
origin = whitelistConstructor.origin;
148+
painlessLookupBuilder.addPainlessConstructor(
149+
targetCanonicalClassName, whitelistConstructor.painlessParameterTypeNames);
150+
}
151+
152+
for (WhitelistMethod whitelistMethod : whitelistClass.whitelistMethods) {
153+
origin = whitelistMethod.origin;
154+
painlessLookupBuilder.addPainlessMethod(
155+
whitelist.javaClassLoader, targetCanonicalClassName, whitelistMethod.javaAugmentedClassName,
156+
whitelistMethod.javaMethodName, whitelistMethod.painlessReturnTypeName,
157+
whitelistMethod.painlessParameterTypeNames);
158+
}
159+
160+
for (WhitelistField whitelistField : whitelistClass.whitelistFields) {
161+
origin = whitelistField.origin;
162+
painlessLookupBuilder.addPainlessField(
163+
targetCanonicalClassName, whitelistField.javaFieldName, whitelistField.painlessFieldTypeName);
164+
}
165+
}
166+
}
167+
} catch (Exception exception) {
168+
throw new IllegalArgumentException("error loading whitelist(s) " + origin, exception);
169+
}
170+
171+
return painlessLookupBuilder.build();
172+
}
130173

131174
private final Map<String, Class<?>> canonicalClassNamesToClasses;
132175
private final Map<Class<?>, PainlessClassBuilder> classesToPainlessClassBuilders;
133176

134-
public PainlessLookupBuilder(List<Whitelist> whitelists) {
135-
this.whitelists = whitelists;
136-
177+
public PainlessLookupBuilder() {
137178
canonicalClassNamesToClasses = new HashMap<>();
138179
classesToPainlessClassBuilders = new HashMap<>();
139180

@@ -666,60 +707,6 @@ public void addPainlessField(Class<?> targetClass, String fieldName, Class<?> ty
666707
}
667708

668709
public PainlessLookup build() {
669-
String origin = "internal error";
670-
671-
try {
672-
// first iteration collects all the Painless type names that
673-
// are used for validation during the second iteration
674-
for (Whitelist whitelist : whitelists) {
675-
for (WhitelistClass whitelistStruct : whitelist.whitelistStructs) {
676-
String painlessTypeName = whitelistStruct.javaClassName.replace('$', '.');
677-
PainlessClassBuilder painlessStruct =
678-
classesToPainlessClassBuilders.get(canonicalClassNamesToClasses.get(painlessTypeName));
679-
680-
if (painlessStruct != null && painlessStruct.clazz.getName().equals(whitelistStruct.javaClassName) == false) {
681-
throw new IllegalArgumentException("struct [" + painlessStruct.name + "] cannot represent multiple classes " +
682-
"[" + painlessStruct.clazz.getName() + "] and [" + whitelistStruct.javaClassName + "]");
683-
}
684-
685-
origin = whitelistStruct.origin;
686-
addPainlessClass(
687-
whitelist.javaClassLoader, whitelistStruct.javaClassName, whitelistStruct.onlyFQNJavaClassName == false);
688-
689-
painlessStruct = classesToPainlessClassBuilders.get(canonicalClassNamesToClasses.get(painlessTypeName));
690-
classesToPainlessClassBuilders.put(painlessStruct.clazz, painlessStruct);
691-
}
692-
}
693-
694-
// second iteration adds all the constructors, methods, and fields that will
695-
// be available in Painless along with validating they exist and all their types have
696-
// been white-listed during the first iteration
697-
for (Whitelist whitelist : whitelists) {
698-
for (WhitelistClass whitelistStruct : whitelist.whitelistStructs) {
699-
String painlessTypeName = whitelistStruct.javaClassName.replace('$', '.');
700-
701-
for (WhitelistConstructor whitelistConstructor : whitelistStruct.whitelistConstructors) {
702-
origin = whitelistConstructor.origin;
703-
addPainlessConstructor(painlessTypeName, whitelistConstructor.painlessParameterTypeNames);
704-
}
705-
706-
for (WhitelistMethod whitelistMethod : whitelistStruct.whitelistMethods) {
707-
origin = whitelistMethod.origin;
708-
addPainlessMethod(whitelist.javaClassLoader, painlessTypeName, whitelistMethod.javaAugmentedClassName,
709-
whitelistMethod.javaMethodName, whitelistMethod.painlessReturnTypeName,
710-
whitelistMethod.painlessParameterTypeNames);
711-
}
712-
713-
for (WhitelistField whitelistField : whitelistStruct.whitelistFields) {
714-
origin = whitelistField.origin;
715-
addPainlessField(painlessTypeName, whitelistField.javaFieldName, whitelistField.painlessFieldTypeName);
716-
}
717-
}
718-
}
719-
} catch (Exception exception) {
720-
throw new IllegalArgumentException("error loading whitelist(s) " + origin, exception);
721-
}
722-
723710
copyPainlessClassMembers();
724711
cacheRuntimeHandles();
725712
setFunctionalInterfaceMethods();

modules/lang-painless/src/test/java/org/elasticsearch/painless/AnalyzerCasterTests.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
package org.elasticsearch.painless;
2121

2222
import org.elasticsearch.painless.lookup.PainlessCast;
23-
2423
import org.elasticsearch.test.ESTestCase;
2524

2625
public class AnalyzerCasterTests extends ESTestCase {

modules/lang-painless/src/test/java/org/elasticsearch/painless/BaseClassTests.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@
1919

2020
package org.elasticsearch.painless;
2121

22-
import java.util.Collections;
23-
import java.util.HashMap;
24-
import java.util.Map;
25-
2622
import org.elasticsearch.painless.lookup.PainlessLookup;
2723
import org.elasticsearch.painless.lookup.PainlessLookupBuilder;
2824
import org.elasticsearch.painless.spi.Whitelist;
2925

26+
import java.util.Collections;
27+
import java.util.HashMap;
28+
import java.util.Map;
29+
3030
import static java.util.Collections.emptyMap;
3131
import static java.util.Collections.singletonMap;
3232
import static org.hamcrest.Matchers.containsString;
@@ -38,7 +38,7 @@
3838
*/
3939
public class BaseClassTests extends ScriptTestCase {
4040

41-
private final PainlessLookup painlessLookup = new PainlessLookupBuilder(Whitelist.BASE_WHITELISTS).build();
41+
private final PainlessLookup painlessLookup = PainlessLookupBuilder.buildFromWhitelists(Whitelist.BASE_WHITELISTS);
4242

4343
public abstract static class Gets {
4444

modules/lang-painless/src/test/java/org/elasticsearch/painless/BasicStatementTests.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
import java.util.ArrayList;
44
import java.util.Collections;
5+
import java.util.HashMap;
6+
import java.util.List;
7+
import java.util.Map;
58

69
/*
710
* Licensed to Elasticsearch under one or more contributor
@@ -22,10 +25,6 @@
2225
* under the License.
2326
*/
2427

25-
import java.util.HashMap;
26-
import java.util.List;
27-
import java.util.Map;
28-
2928
public class BasicStatementTests extends ScriptTestCase {
3029

3130
public void testIfStatement() {

modules/lang-painless/src/test/java/org/elasticsearch/painless/DebugTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
import static org.hamcrest.Matchers.not;
3838

3939
public class DebugTests extends ScriptTestCase {
40-
private final PainlessLookup painlessLookup = new PainlessLookupBuilder(Whitelist.BASE_WHITELISTS).build();
40+
private final PainlessLookup painlessLookup = PainlessLookupBuilder.buildFromWhitelists(Whitelist.BASE_WHITELISTS);
4141

4242
public void testExplain() {
4343
// Debug.explain can explain an object

modules/lang-painless/src/test/java/org/elasticsearch/painless/Debugger.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ static String toString(Class<?> iface, String source, CompilerSettings settings)
4040
PrintWriter outputWriter = new PrintWriter(output);
4141
Textifier textifier = new Textifier();
4242
try {
43-
new Compiler(iface, new PainlessLookupBuilder(Whitelist.BASE_WHITELISTS).build())
43+
new Compiler(iface, PainlessLookupBuilder.buildFromWhitelists(Whitelist.BASE_WHITELISTS))
4444
.compile("<debugging>", source, settings, textifier);
4545
} catch (RuntimeException e) {
4646
textifier.print(outputWriter);

modules/lang-painless/src/test/java/org/elasticsearch/painless/DefBootstrapTests.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@
1919

2020
package org.elasticsearch.painless;
2121

22+
import org.elasticsearch.painless.lookup.PainlessLookup;
23+
import org.elasticsearch.painless.lookup.PainlessLookupBuilder;
24+
import org.elasticsearch.painless.spi.Whitelist;
25+
import org.elasticsearch.test.ESTestCase;
26+
2227
import java.lang.invoke.CallSite;
2328
import java.lang.invoke.MethodHandle;
2429
import java.lang.invoke.MethodHandles;
@@ -27,13 +32,8 @@
2732
import java.util.Collections;
2833
import java.util.HashMap;
2934

30-
import org.elasticsearch.painless.lookup.PainlessLookup;
31-
import org.elasticsearch.painless.lookup.PainlessLookupBuilder;
32-
import org.elasticsearch.painless.spi.Whitelist;
33-
import org.elasticsearch.test.ESTestCase;
34-
3535
public class DefBootstrapTests extends ESTestCase {
36-
private final PainlessLookup painlessLookup = new PainlessLookupBuilder(Whitelist.BASE_WHITELISTS).build();
36+
private final PainlessLookup painlessLookup = PainlessLookupBuilder.buildFromWhitelists(Whitelist.BASE_WHITELISTS);
3737

3838
/** calls toString() on integers, twice */
3939
public void testOneType() throws Throwable {

modules/lang-painless/src/test/java/org/elasticsearch/painless/LangPainlessClientYamlTestSuiteIT.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121

2222
import com.carrotsearch.randomizedtesting.annotations.Name;
2323
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
24-
2524
import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
2625
import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
2726

modules/lang-painless/src/test/java/org/elasticsearch/painless/PainlessDocGenerator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
*/
5353
public class PainlessDocGenerator {
5454

55-
private static final PainlessLookup PAINLESS_LOOKUP = new PainlessLookupBuilder(Whitelist.BASE_WHITELISTS).build();
55+
private static final PainlessLookup PAINLESS_LOOKUP = PainlessLookupBuilder.buildFromWhitelists(Whitelist.BASE_WHITELISTS);
5656
private static final Logger logger = ESLoggerFactory.getLogger(PainlessDocGenerator.class);
5757
private static final Comparator<PainlessField> FIELD_NAME = comparing(f -> f.name);
5858
private static final Comparator<PainlessMethod> METHOD_NAME = comparing(m -> m.name);

0 commit comments

Comments
 (0)