Merge branch 'master' into index-lifecycle

This commit is contained in:
Colin Goodheart-Smithe 2018-07-20 07:56:57 +01:00
commit 573a9e6443
No known key found for this signature in database
GPG Key ID: F975E7BDD739B3C7
46 changed files with 619 additions and 765 deletions

View File

@ -25,8 +25,8 @@ plugins {
group = 'org.elasticsearch.gradle'
if (GradleVersion.current() < GradleVersion.version('3.3')) {
throw new GradleException('Gradle 3.3+ is required to build elasticsearch')
if (GradleVersion.current() < GradleVersion.version('4.9')) {
throw new GradleException('Gradle 4.9+ is required to build elasticsearch')
}
if (JavaVersion.current() < JavaVersion.VERSION_1_8) {

View File

@ -67,6 +67,9 @@ class BuildPlugin implements Plugin<Project> {
+ 'elasticearch.standalone-rest-test, and elasticsearch.build '
+ 'are mutually exclusive')
}
if (GradleVersion.current() < GradleVersion.version('4.9')) {
throw new GradleException('Gradle 4.9+ is required to use elasticsearch.build plugin')
}
project.pluginManager.apply('java')
project.pluginManager.apply('carrotsearch.randomized-testing')
// these plugins add lots of info to our jars
@ -750,7 +753,6 @@ class BuildPlugin implements Plugin<Project> {
systemProperty 'tests.task', path
systemProperty 'tests.security.manager', 'true'
systemProperty 'jna.nosys', 'true'
systemProperty 'es.scripting.exception_for_missing_value', 'true'
// TODO: remove setting logging level via system property
systemProperty 'tests.logger.level', 'WARN'
for (Map.Entry<String, String> property : System.properties.entrySet()) {

View File

@ -123,21 +123,8 @@ GET hockey/_search
[float]
===== Missing values
If you request the value from a field `field` that isnt in
the document, `doc['field'].value` for this document returns:
- `0` if a `field` has a numeric datatype (long, double etc.)
- `false` is a `field` has a boolean datatype
- epoch date if a `field` has a date datatype
- `null` if a `field` has a string datatype
- `null` if a `field` has a geo datatype
- `""` if a `field` has a binary datatype
IMPORTANT: Starting in 7.0, `doc['field'].value` throws an exception if
the field is missing in a document. To enable this behavior now,
set a {ref}/jvm-options.html[`jvm.option`]
`-Des.scripting.exception_for_missing_value=true` on a node. If you do not enable
this behavior, a deprecation warning is logged on start up.
`doc['field'].value` throws an exception if
the field is missing in a document.
To check if a document is missing a value, you can call
`doc['field'].size() == 0`.

View File

@ -466,8 +466,8 @@ public final class AnalyzerCaster {
return PainlessCast.standard(actual, expected, explicit);
} else {
throw location.createError(new ClassCastException("Cannot cast from " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(actual) + "] to " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(expected) + "]."));
"[" + PainlessLookupUtility.typeToCanonicalTypeName(actual) + "] to " +
"[" + PainlessLookupUtility.typeToCanonicalTypeName(expected) + "]."));
}
}

View File

@ -302,7 +302,7 @@ public final class Def {
nestedType,
0,
DefBootstrap.REFERENCE,
PainlessLookupUtility.anyTypeToPainlessTypeName(interfaceType));
PainlessLookupUtility.typeToCanonicalTypeName(interfaceType));
filter = nested.dynamicInvoker();
} else {
throw new AssertionError();
@ -334,7 +334,7 @@ public final class Def {
int arity = interfaceMethod.arguments.size();
PainlessMethod implMethod = lookupMethodInternal(painlessLookup, receiverClass, name, arity);
return lookupReferenceInternal(painlessLookup, methodHandlesLookup, interfaceType,
PainlessLookupUtility.anyTypeToPainlessTypeName(implMethod.target), implMethod.name, receiverClass);
PainlessLookupUtility.typeToCanonicalTypeName(implMethod.target), implMethod.name, receiverClass);
}
/** Returns a method handle to an implementation of clazz, given method reference signature. */
@ -347,7 +347,7 @@ public final class Def {
PainlessMethod interfaceMethod = painlessLookup.getPainlessStructFromJavaClass(clazz).functionalMethod;
if (interfaceMethod == null) {
throw new IllegalArgumentException("Cannot convert function reference [" + type + "::" + call + "] " +
"to [" + PainlessLookupUtility.anyTypeToPainlessTypeName(clazz) + "], not a functional interface");
"to [" + PainlessLookupUtility.typeToCanonicalTypeName(clazz) + "], not a functional interface");
}
int arity = interfaceMethod.arguments.size() + captures.length;
final MethodHandle handle;

View File

@ -168,7 +168,7 @@ public class FunctionRef {
PainlessMethod method = painlessLookup.getPainlessStructFromJavaClass(expected).functionalMethod;
if (method == null) {
throw new IllegalArgumentException("Cannot convert function reference [" + type + "::" + call + "] " +
"to [" + PainlessLookupUtility.anyTypeToPainlessTypeName(expected) + "], not a functional interface");
"to [" + PainlessLookupUtility.typeToCanonicalTypeName(expected) + "], not a functional interface");
}
// lookup requested method

View File

@ -292,7 +292,7 @@ public final class Locals {
@Override
public String toString() {
StringBuilder b = new StringBuilder();
b.append("Variable[type=").append(PainlessLookupUtility.anyTypeToPainlessTypeName(clazz));
b.append("Variable[type=").append(PainlessLookupUtility.typeToCanonicalTypeName(clazz));
b.append(",name=").append(name);
b.append(",slot=").append(slot);
if (readonly) {

View File

@ -183,7 +183,7 @@ public class ScriptClassInfo {
private static Class<?> definitionTypeForClass(PainlessLookup painlessLookup, Class<?> type,
Function<Class<?>, String> unknownErrorMessageSource) {
type = PainlessLookupUtility.javaObjectTypeToPainlessDefType(type);
type = PainlessLookupUtility.javaTypeToType(type);
Class<?> componentType = type;
while (componentType.isArray()) {

View File

@ -54,6 +54,6 @@ public final class PainlessLookup {
}
public Class<?> getJavaClassFromPainlessType(String painlessType) {
return PainlessLookupUtility.painlessTypeNameToPainlessType(painlessType, painlessTypesToJavaClasses);
return PainlessLookupUtility.canonicalTypeNameToType(painlessType, painlessTypesToJavaClasses);
}
}

View File

@ -30,7 +30,6 @@ import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@ -39,22 +38,21 @@ import java.util.Objects;
import java.util.Stack;
import java.util.regex.Pattern;
import static org.elasticsearch.painless.lookup.PainlessLookupUtility.DEF_PAINLESS_CLASS_NAME;
import static org.elasticsearch.painless.lookup.PainlessLookupUtility.anyTypeNameToPainlessTypeName;
import static org.elasticsearch.painless.lookup.PainlessLookupUtility.DEF_TYPE_NAME;
import static org.elasticsearch.painless.lookup.PainlessLookupUtility.buildPainlessMethodKey;
public class PainlessLookupBuilder {
private static class PainlessMethodCacheKey {
private final Class<?> javaClass;
private final Class<?> targetType;
private final String methodName;
private final List<Class<?>> painlessTypeParameters;
private final List<Class<?>> typeParameters;
private PainlessMethodCacheKey(Class<?> javaClass, String methodName, List<Class<?>> painlessTypeParameters) {
this.javaClass = javaClass;
private PainlessMethodCacheKey(Class<?> targetType, String methodName, List<Class<?>> typeParameters) {
this.targetType = targetType;
this.methodName = methodName;
this.painlessTypeParameters = Collections.unmodifiableList(painlessTypeParameters);
this.typeParameters = Collections.unmodifiableList(typeParameters);
}
@Override
@ -69,27 +67,27 @@ public class PainlessLookupBuilder {
PainlessMethodCacheKey that = (PainlessMethodCacheKey)object;
return Objects.equals(javaClass, that.javaClass) &&
return Objects.equals(targetType, that.targetType) &&
Objects.equals(methodName, that.methodName) &&
Objects.equals(painlessTypeParameters, that.painlessTypeParameters);
Objects.equals(typeParameters, that.typeParameters);
}
@Override
public int hashCode() {
return Objects.hash(javaClass, methodName, painlessTypeParameters);
return Objects.hash(targetType, methodName, typeParameters);
}
}
private static class PainlessFieldCacheKey {
private final Class<?> javaClass;
private final Class<?> targetType;
private final String fieldName;
private final Class<?> painlessType;
private final Class<?> typeParameter;
private PainlessFieldCacheKey(Class<?> javaClass, String fieldName, Class<?> painlessType) {
this.javaClass = javaClass;
private PainlessFieldCacheKey(Class<?> targetType, String fieldName, Class<?> typeParameter) {
this.targetType = targetType;
this.fieldName = fieldName;
this.painlessType = painlessType;
this.typeParameter = typeParameter;
}
@Override
@ -104,14 +102,14 @@ public class PainlessLookupBuilder {
PainlessFieldCacheKey that = (PainlessFieldCacheKey) object;
return Objects.equals(javaClass, that.javaClass) &&
Objects.equals(fieldName, that.fieldName) &&
Objects.equals(painlessType, that.painlessType);
return Objects.equals(targetType, that.targetType) &&
Objects.equals(fieldName, that.fieldName) &&
Objects.equals(typeParameter, that.typeParameter);
}
@Override
public int hashCode() {
return Objects.hash(javaClass, fieldName, painlessType);
return Objects.hash(targetType, fieldName, typeParameter);
}
}
@ -122,157 +120,115 @@ public class PainlessLookupBuilder {
private static final Pattern METHOD_NAME_PATTERN = Pattern.compile("^[_a-zA-Z][_a-zA-Z0-9]*$");
private static final Pattern FIELD_NAME_PATTERN = Pattern.compile("^[_a-zA-Z][_a-zA-Z0-9]*$");
private static String anyTypesArrayToCanonicalString(Class<?>[] anyTypesArray, boolean toPainlessTypes) {
return anyTypesListToCanonicalString(Arrays.asList(anyTypesArray), toPainlessTypes);
}
private static String anyTypesListToCanonicalString(List<Class<?>> anyTypesList, boolean toPainlessTypes) {
StringBuilder anyTypesCanonicalStringBuilder = new StringBuilder("[");
int anyTypesSize = anyTypesList.size();
int anyTypesIndex = 0;
for (Class<?> anyType : anyTypesList) {
String anyTypeCanonicalName = anyType.getCanonicalName();
if (toPainlessTypes) {
anyTypeCanonicalName = anyTypeNameToPainlessTypeName(anyTypeCanonicalName);
}
anyTypesCanonicalStringBuilder.append(anyTypeCanonicalName);
if (++anyTypesIndex < anyTypesSize) {
anyTypesCanonicalStringBuilder.append(",");
}
}
anyTypesCanonicalStringBuilder.append("]");
return anyTypesCanonicalStringBuilder.toString();
}
private final List<Whitelist> whitelists;
private final Map<String, Class<?>> painlessClassNamesToJavaClasses;
private final Map<Class<?>, PainlessClassBuilder> javaClassesToPainlessClassBuilders;
private final Map<String, Class<?>> canonicalClassNamesToClasses;
private final Map<Class<?>, PainlessClassBuilder> classesToPainlessClasses;
public PainlessLookupBuilder(List<Whitelist> whitelists) {
this.whitelists = whitelists;
painlessClassNamesToJavaClasses = new HashMap<>();
javaClassesToPainlessClassBuilders = new HashMap<>();
canonicalClassNamesToClasses = new HashMap<>();
classesToPainlessClasses = new HashMap<>();
painlessClassNamesToJavaClasses.put(DEF_PAINLESS_CLASS_NAME, def.class);
javaClassesToPainlessClassBuilders.put(def.class,
new PainlessClassBuilder(DEF_PAINLESS_CLASS_NAME, Object.class, Type.getType(Object.class)));
canonicalClassNamesToClasses.put(DEF_TYPE_NAME, def.class);
classesToPainlessClasses.put(def.class,
new PainlessClassBuilder(DEF_TYPE_NAME, Object.class, Type.getType(Object.class)));
}
private Class<?> painlessTypeNameToPainlessType(String painlessTypeName) {
return PainlessLookupUtility.painlessTypeNameToPainlessType(painlessTypeName, painlessClassNamesToJavaClasses);
private Class<?> canonicalTypeNameToType(String canonicalTypeName) {
return PainlessLookupUtility.canonicalTypeNameToType(canonicalTypeName, canonicalClassNamesToClasses);
}
private void validatePainlessType(Class<?> painlessType) {
PainlessLookupUtility.validatePainlessType(painlessType, javaClassesToPainlessClassBuilders.keySet());
private void validateType(Class<?> type) {
PainlessLookupUtility.validateType(type, classesToPainlessClasses.keySet());
}
public void addPainlessClass(ClassLoader classLoader, String javaClassName, boolean importPainlessClassName) {
public void addPainlessClass(ClassLoader classLoader, String javaClassName, boolean importClassName) {
Objects.requireNonNull(classLoader);
Objects.requireNonNull(javaClassName);
String painlessClassName = anyTypeNameToPainlessTypeName(javaClassName);
Class<?> clazz;
if (CLASS_NAME_PATTERN.matcher(painlessClassName).matches() == false) {
throw new IllegalArgumentException("invalid painless class name [" + painlessClassName + "]");
}
String importedPainlessClassName = anyTypeNameToPainlessTypeName(javaClassName.substring(javaClassName.lastIndexOf('.') + 1));
Class<?> javaClass;
if ("void".equals(javaClassName)) javaClass = void.class;
else if ("boolean".equals(javaClassName)) javaClass = boolean.class;
else if ("byte".equals(javaClassName)) javaClass = byte.class;
else if ("short".equals(javaClassName)) javaClass = short.class;
else if ("char".equals(javaClassName)) javaClass = char.class;
else if ("int".equals(javaClassName)) javaClass = int.class;
else if ("long".equals(javaClassName)) javaClass = long.class;
else if ("float".equals(javaClassName)) javaClass = float.class;
else if ("double".equals(javaClassName)) javaClass = double.class;
if ("void".equals(javaClassName)) clazz = void.class;
else if ("boolean".equals(javaClassName)) clazz = boolean.class;
else if ("byte".equals(javaClassName)) clazz = byte.class;
else if ("short".equals(javaClassName)) clazz = short.class;
else if ("char".equals(javaClassName)) clazz = char.class;
else if ("int".equals(javaClassName)) clazz = int.class;
else if ("long".equals(javaClassName)) clazz = long.class;
else if ("float".equals(javaClassName)) clazz = float.class;
else if ("double".equals(javaClassName)) clazz = double.class;
else {
try {
javaClass = Class.forName(javaClassName, true, classLoader);
if (javaClass == def.class) {
throw new IllegalArgumentException("cannot add reserved painless class [" + DEF_PAINLESS_CLASS_NAME + "]");
}
if (javaClass.isArray()) {
throw new IllegalArgumentException("cannot add an array type java class [" + javaClassName + "] as a painless class");
}
clazz = Class.forName(javaClassName, true, classLoader);
} catch (ClassNotFoundException cnfe) {
throw new IllegalArgumentException("java class [" + javaClassName + "] not found", cnfe);
throw new IllegalArgumentException("class [" + javaClassName + "] not found", cnfe);
}
}
addPainlessClass(painlessClassName, importedPainlessClassName, javaClass, importPainlessClassName);
addPainlessClass(clazz, importClassName);
}
public void addPainlessClass(Class<?> javaClass, boolean importPainlessClassName) {
Objects.requireNonNull(javaClass);
public void addPainlessClass(Class<?> clazz, boolean importClassName) {
Objects.requireNonNull(clazz);
if (javaClass == def.class) {
throw new IllegalArgumentException("cannot specify reserved painless class [" + DEF_PAINLESS_CLASS_NAME + "]");
if (clazz == def.class) {
throw new IllegalArgumentException("cannot add reserved class [" + DEF_TYPE_NAME + "]");
}
String javaClassName = javaClass.getCanonicalName();
String painlessClassName = anyTypeNameToPainlessTypeName(javaClassName);
String importedPainlessClassName = anyTypeNameToPainlessTypeName(javaClassName.substring(javaClassName.lastIndexOf('.') + 1));
String canonicalClassName = clazz.getCanonicalName();
addPainlessClass(painlessClassName, importedPainlessClassName, javaClass, importPainlessClassName);
}
if (clazz.isArray()) {
throw new IllegalArgumentException("cannot add array type [" + canonicalClassName + "] as a class");
}
private void addPainlessClass(
String painlessClassName, String importedPainlessClassName, Class<?> javaClass, boolean importPainlessClassName) {
PainlessClassBuilder existingPainlessClassBuilder = javaClassesToPainlessClassBuilders.get(javaClass);
if (CLASS_NAME_PATTERN.matcher(canonicalClassName).matches() == false) {
throw new IllegalArgumentException("invalid class name [" + canonicalClassName + "]");
}
PainlessClassBuilder existingPainlessClassBuilder = classesToPainlessClasses.get(clazz);
if (existingPainlessClassBuilder == null) {
PainlessClassBuilder painlessClassBuilder = new PainlessClassBuilder(painlessClassName, javaClass, Type.getType(javaClass));
painlessClassNamesToJavaClasses.put(painlessClassName, javaClass);
javaClassesToPainlessClassBuilders.put(javaClass, painlessClassBuilder);
} else if (existingPainlessClassBuilder.clazz.equals(javaClass) == false) {
throw new IllegalArgumentException("painless class [" + painlessClassName + "] illegally represents multiple java classes " +
"[" + javaClass.getCanonicalName() + "] and [" + existingPainlessClassBuilder.clazz.getCanonicalName() + "]");
PainlessClassBuilder painlessClassBuilder = new PainlessClassBuilder(canonicalClassName, clazz, Type.getType(clazz));
canonicalClassNamesToClasses.put(canonicalClassName, clazz);
classesToPainlessClasses.put(clazz, painlessClassBuilder);
} else if (existingPainlessClassBuilder.clazz.equals(clazz) == false) {
throw new IllegalArgumentException("class [" + canonicalClassName + "] " +
"cannot represent multiple java classes with the same name from different class loaders");
}
if (painlessClassName.equals(importedPainlessClassName)) {
if (importPainlessClassName == true) {
throw new IllegalArgumentException(
"must use only_fqn parameter on painless class [" + painlessClassName + "] with no package");
String javaClassName = clazz.getName();
String importedCanonicalClassName = javaClassName.substring(javaClassName.lastIndexOf('.') + 1).replace('$', '.');
if (canonicalClassName.equals(importedCanonicalClassName)) {
if (importClassName == true) {
throw new IllegalArgumentException("must use only_fqn parameter on class [" + canonicalClassName + "] with no package");
}
} else {
Class<?> importedJavaClass = painlessClassNamesToJavaClasses.get(importedPainlessClassName);
Class<?> importedPainlessType = canonicalClassNamesToClasses.get(importedCanonicalClassName);
if (importedJavaClass == null) {
if (importPainlessClassName) {
if (importedPainlessType == null) {
if (importClassName) {
if (existingPainlessClassBuilder != null) {
throw new IllegalArgumentException(
"inconsistent only_fqn parameters found for painless class [" + painlessClassName + "]");
"inconsistent only_fqn parameters found for painless type [" + canonicalClassName + "]");
}
painlessClassNamesToJavaClasses.put(importedPainlessClassName, javaClass);
canonicalClassNamesToClasses.put(importedCanonicalClassName, clazz);
}
} else if (importedJavaClass.equals(javaClass) == false) {
throw new IllegalArgumentException("painless class [" + importedPainlessClassName + "] illegally represents multiple " +
"java classes [" + javaClass.getCanonicalName() + "] and [" + importedJavaClass.getCanonicalName() + "]");
} else if (importPainlessClassName == false) {
throw new IllegalArgumentException(
"inconsistent only_fqn parameters found for painless class [" + painlessClassName + "]");
} else if (importedPainlessType.equals(clazz) == false) {
throw new IllegalArgumentException("painless type [" + importedCanonicalClassName + "] illegally represents multiple " +
"java types [" + clazz.getCanonicalName() + "] and [" + importedPainlessType.getCanonicalName() + "]");
} else if (importClassName == false) {
throw new IllegalArgumentException("inconsistent only_fqn parameters found for painless type [" + canonicalClassName + "]");
}
}
}
private void addConstructor(String ownerStructName, WhitelistConstructor whitelistConstructor) {
PainlessClassBuilder ownerStruct = javaClassesToPainlessClassBuilders.get(painlessClassNamesToJavaClasses.get(ownerStructName));
PainlessClassBuilder ownerStruct = classesToPainlessClasses.get(canonicalClassNamesToClasses.get(ownerStructName));
if (ownerStruct == null) {
throw new IllegalArgumentException("owner struct [" + ownerStructName + "] not defined for constructor with " +
@ -286,10 +242,10 @@ public class PainlessLookupBuilder {
String painlessParameterTypeName = whitelistConstructor.painlessParameterTypeNames.get(parameterCount);
try {
Class<?> painlessParameterClass = painlessTypeNameToPainlessType(painlessParameterTypeName);
Class<?> painlessParameterClass = canonicalTypeNameToType(painlessParameterTypeName);
painlessParametersTypes.add(painlessParameterClass);
javaClassParameters[parameterCount] = PainlessLookupUtility.painlessDefTypeToJavaObjectType(painlessParameterClass);
javaClassParameters[parameterCount] = PainlessLookupUtility.typeToJavaType(painlessParameterClass);
} catch (IllegalArgumentException iae) {
throw new IllegalArgumentException("struct not defined for constructor parameter [" + painlessParameterTypeName + "] " +
"with owner struct [" + ownerStructName + "] and constructor parameters " +
@ -333,7 +289,7 @@ public class PainlessLookupBuilder {
}
private void addMethod(ClassLoader whitelistClassLoader, String ownerStructName, WhitelistMethod whitelistMethod) {
PainlessClassBuilder ownerStruct = javaClassesToPainlessClassBuilders.get(painlessClassNamesToJavaClasses.get(ownerStructName));
PainlessClassBuilder ownerStruct = classesToPainlessClasses.get(canonicalClassNamesToClasses.get(ownerStructName));
if (ownerStruct == null) {
throw new IllegalArgumentException("owner struct [" + ownerStructName + "] not defined for method with " +
@ -372,11 +328,11 @@ public class PainlessLookupBuilder {
String painlessParameterTypeName = whitelistMethod.painlessParameterTypeNames.get(parameterCount);
try {
Class<?> painlessParameterClass = painlessTypeNameToPainlessType(painlessParameterTypeName);
Class<?> painlessParameterClass = canonicalTypeNameToType(painlessParameterTypeName);
painlessParametersTypes.add(painlessParameterClass);
javaClassParameters[parameterCount + augmentedOffset] =
PainlessLookupUtility.painlessDefTypeToJavaObjectType(painlessParameterClass);
PainlessLookupUtility.typeToJavaType(painlessParameterClass);
} catch (IllegalArgumentException iae) {
throw new IllegalArgumentException("struct not defined for method parameter [" + painlessParameterTypeName + "] " +
"with owner struct [" + ownerStructName + "] and method with name [" + whitelistMethod.javaMethodName + "] " +
@ -398,14 +354,14 @@ public class PainlessLookupBuilder {
Class<?> painlessReturnClass;
try {
painlessReturnClass = painlessTypeNameToPainlessType(whitelistMethod.painlessReturnTypeName);
painlessReturnClass = canonicalTypeNameToType(whitelistMethod.painlessReturnTypeName);
} catch (IllegalArgumentException iae) {
throw new IllegalArgumentException("struct not defined for return type [" + whitelistMethod.painlessReturnTypeName + "] " +
"with owner struct [" + ownerStructName + "] and method with name [" + whitelistMethod.javaMethodName + "] " +
"and parameters " + whitelistMethod.painlessParameterTypeNames, iae);
}
if (javaMethod.getReturnType() != PainlessLookupUtility.painlessDefTypeToJavaObjectType(painlessReturnClass)) {
if (javaMethod.getReturnType() != PainlessLookupUtility.typeToJavaType(painlessReturnClass)) {
throw new IllegalArgumentException("specified return type class [" + painlessReturnClass + "] " +
"does not match the return type class [" + javaMethod.getReturnType() + "] for the " +
"method with name [" + whitelistMethod.javaMethodName + "] " +
@ -471,7 +427,7 @@ public class PainlessLookupBuilder {
}
private void addField(String ownerStructName, WhitelistField whitelistField) {
PainlessClassBuilder ownerStruct = javaClassesToPainlessClassBuilders.get(painlessClassNamesToJavaClasses.get(ownerStructName));
PainlessClassBuilder ownerStruct = classesToPainlessClasses.get(canonicalClassNamesToClasses.get(ownerStructName));
if (ownerStruct == null) {
throw new IllegalArgumentException("owner struct [" + ownerStructName + "] not defined for method with " +
@ -495,7 +451,7 @@ public class PainlessLookupBuilder {
Class<?> painlessFieldClass;
try {
painlessFieldClass = painlessTypeNameToPainlessType(whitelistField.painlessFieldTypeName);
painlessFieldClass = canonicalTypeNameToType(whitelistField.painlessFieldTypeName);
} catch (IllegalArgumentException iae) {
throw new IllegalArgumentException("struct not defined for return type [" + whitelistField.painlessFieldTypeName + "] " +
"with owner struct [" + ownerStructName + "] and field with name [" + whitelistField.javaFieldName + "]", iae);
@ -552,7 +508,7 @@ public class PainlessLookupBuilder {
}
private void copyStruct(String struct, List<String> children) {
final PainlessClassBuilder owner = javaClassesToPainlessClassBuilders.get(painlessClassNamesToJavaClasses.get(struct));
final PainlessClassBuilder owner = classesToPainlessClasses.get(canonicalClassNamesToClasses.get(struct));
if (owner == null) {
throw new IllegalArgumentException("Owner struct [" + struct + "] not defined for copy.");
@ -560,7 +516,7 @@ public class PainlessLookupBuilder {
for (int count = 0; count < children.size(); ++count) {
final PainlessClassBuilder child =
javaClassesToPainlessClassBuilders.get(painlessClassNamesToJavaClasses.get(children.get(count)));
classesToPainlessClasses.get(canonicalClassNamesToClasses.get(children.get(count)));
if (child == null) {
throw new IllegalArgumentException("Child struct [" + children.get(count) + "]" +
@ -734,7 +690,7 @@ public class PainlessLookupBuilder {
for (WhitelistClass whitelistStruct : whitelist.whitelistStructs) {
String painlessTypeName = whitelistStruct.javaClassName.replace('$', '.');
PainlessClassBuilder painlessStruct =
javaClassesToPainlessClassBuilders.get(painlessClassNamesToJavaClasses.get(painlessTypeName));
classesToPainlessClasses.get(canonicalClassNamesToClasses.get(painlessTypeName));
if (painlessStruct != null && painlessStruct.clazz.getName().equals(whitelistStruct.javaClassName) == false) {
throw new IllegalArgumentException("struct [" + painlessStruct.name + "] cannot represent multiple classes " +
@ -745,8 +701,8 @@ public class PainlessLookupBuilder {
addPainlessClass(
whitelist.javaClassLoader, whitelistStruct.javaClassName, whitelistStruct.onlyFQNJavaClassName == false);
painlessStruct = javaClassesToPainlessClassBuilders.get(painlessClassNamesToJavaClasses.get(painlessTypeName));
javaClassesToPainlessClassBuilders.put(painlessStruct.clazz, painlessStruct);
painlessStruct = classesToPainlessClasses.get(canonicalClassNamesToClasses.get(painlessTypeName));
classesToPainlessClasses.put(painlessStruct.clazz, painlessStruct);
}
}
@ -779,8 +735,8 @@ public class PainlessLookupBuilder {
// goes through each Painless struct and determines the inheritance list,
// and then adds all inherited types to the Painless struct's whitelist
for (Class<?> javaClass : javaClassesToPainlessClassBuilders.keySet()) {
PainlessClassBuilder painlessStruct = javaClassesToPainlessClassBuilders.get(javaClass);
for (Class<?> javaClass : classesToPainlessClasses.keySet()) {
PainlessClassBuilder painlessStruct = classesToPainlessClasses.get(javaClass);
List<String> painlessSuperStructs = new ArrayList<>();
Class<?> javaSuperClass = painlessStruct.clazz.getSuperclass();
@ -791,7 +747,7 @@ public class PainlessLookupBuilder {
// adds super classes to the inheritance list
if (javaSuperClass != null && javaSuperClass.isInterface() == false) {
while (javaSuperClass != null) {
PainlessClassBuilder painlessSuperStruct = javaClassesToPainlessClassBuilders.get(javaSuperClass);
PainlessClassBuilder painlessSuperStruct = classesToPainlessClasses.get(javaSuperClass);
if (painlessSuperStruct != null) {
painlessSuperStructs.add(painlessSuperStruct.name);
@ -807,7 +763,7 @@ public class PainlessLookupBuilder {
Class<?> javaInterfaceLookup = javaInteraceLookups.pop();
for (Class<?> javaSuperInterface : javaInterfaceLookup.getInterfaces()) {
PainlessClassBuilder painlessInterfaceStruct = javaClassesToPainlessClassBuilders.get(javaSuperInterface);
PainlessClassBuilder painlessInterfaceStruct = classesToPainlessClasses.get(javaSuperInterface);
if (painlessInterfaceStruct != null) {
String painlessInterfaceStructName = painlessInterfaceStruct.name;
@ -828,7 +784,7 @@ public class PainlessLookupBuilder {
// copies methods and fields from Object into interface types
if (painlessStruct.clazz.isInterface() || (def.class.getSimpleName()).equals(painlessStruct.name)) {
PainlessClassBuilder painlessObjectStruct = javaClassesToPainlessClassBuilders.get(Object.class);
PainlessClassBuilder painlessObjectStruct = classesToPainlessClasses.get(Object.class);
if (painlessObjectStruct != null) {
copyStruct(painlessStruct.name, Collections.singletonList(painlessObjectStruct.name));
@ -837,18 +793,18 @@ public class PainlessLookupBuilder {
}
// precompute runtime classes
for (PainlessClassBuilder painlessStruct : javaClassesToPainlessClassBuilders.values()) {
for (PainlessClassBuilder painlessStruct : classesToPainlessClasses.values()) {
addRuntimeClass(painlessStruct);
}
Map<Class<?>, PainlessClass> javaClassesToPainlessClasses = new HashMap<>();
// copy all structs to make them unmodifiable for outside users:
for (Map.Entry<Class<?>,PainlessClassBuilder> entry : javaClassesToPainlessClassBuilders.entrySet()) {
for (Map.Entry<Class<?>,PainlessClassBuilder> entry : classesToPainlessClasses.entrySet()) {
entry.getValue().functionalMethod = computeFunctionalInterfaceMethod(entry.getValue());
javaClassesToPainlessClasses.put(entry.getKey(), entry.getValue().build());
}
return new PainlessLookup(painlessClassNamesToJavaClasses, javaClassesToPainlessClasses);
return new PainlessLookup(canonicalClassNamesToClasses, javaClassesToPainlessClasses);
}
}

View File

@ -19,35 +19,177 @@
package org.elasticsearch.painless.lookup;
import org.objectweb.asm.Type;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* This class contains methods shared by {@link PainlessLookupBuilder}, {@link PainlessLookup}, and other classes within
* PainlessLookupUtility contains methods shared by {@link PainlessLookupBuilder}, {@link PainlessLookup}, and other classes within
* Painless for conversion between type names and types along with some other various utility methods.
*
* The following terminology is used for variable names throughout the lookup package:
*
* - javaClass (Class) - a java class including def and excluding array type java classes
* - javaClassName (String) - the fully qualified java class name for a javaClass
* - painlessClassName (String) - the fully qualified painless name or imported painless name for a painlessClass
* - anyClassName (String) - either a javaClassName or a painlessClassName
* - javaType (Class) - a java class excluding def and array type java classes
* - painlessType (Class) - a java class including def and array type java classes
* - javaTypeName (String) - the fully qualified java Type name for a javaType
* - painlessTypeName (String) - the fully qualified painless name or imported painless name for a painlessType
* - anyTypeName (String) - either a javaTypeName or a painlessTypeName
* - painlessClass (PainlessClass) - a painless class object
* A class is a set of methods and fields under a specific class name. A type is either a class or an array under a specific type name.
* Note the distinction between class versus type is class means that no array classes will be be represented whereas type allows array
* classes to be represented. The set of available classes will always be a subset of the available types.
*
* Under ambiguous circumstances most variable names are prefixed with asm, java, or painless.
* If the variable name is the same for asm, java, and painless, no prefix is used.
* Under ambiguous circumstances most variable names are prefixed with asm, java, or painless. If the variable value is the same for asm,
* java, and painless, no prefix is used.
*
* <ul>
* <li> - javaClassName (String) - the fully qualified java class name where '$' tokens represent inner classes excluding
* def and array types </li>
*
* <li> - javaClass (Class) - a java class excluding def and array types </li>
*
* <li> - javaType (Class) - a java class excluding def and including array types </li>
*
* <li> - importedClassName (String) - the imported painless class name where the java canonical class name is used without
* the package qualifier
*
* <li> - canonicalClassName (String) - the fully qualified painless class name equivalent to the fully
* qualified java canonical class name or imported painless class name for a class
* including def and excluding array types where '.' tokens represent inner classes <li>
*
* <li> - canonicalTypeName (String) - the fully qualified painless type name equivalent to the fully
* qualified java canonical type name or imported painless type name for a type
* including def where '.' tokens represent inner classes and each set of '[]' tokens
* at the end of the type name represent a single dimension for an array type <li>
*
* <li> - class/clazz (Class) - a painless class represented by a java class including def and excluding array
* types </li>
*
* <li> - type (Class) - a painless type represented by a java class including def and array types </li>
*
* <li> - painlessClass (PainlessClass) - a painless class object </li>
*
* <li> - painlessMethod (PainlessMethod) - a painless method object </li>
*
* <li> - painlessField (PainlessField) - a painless field object </li>
* </ul>
*/
public final class PainlessLookupUtility {
public static Class<?> javaObjectTypeToPainlessDefType(Class<?> javaType) {
/**
* Converts a canonical type name to a type based on the terminology specified as part of the documentation for
* {@link PainlessLookupUtility}. Since canonical class names are a subset of canonical type names, this method will
* safely convert a canonical class name to a class as well.
*/
public static Class<?> canonicalTypeNameToType(String canonicalTypeName, Map<String, Class<?>> canonicalClassNamesToClasses) {
Objects.requireNonNull(canonicalTypeName);
Objects.requireNonNull(canonicalClassNamesToClasses);
Class<?> type = canonicalClassNamesToClasses.get(canonicalTypeName);
if (type != null) {
return type;
}
int arrayDimensions = 0;
int arrayIndex = canonicalTypeName.indexOf('[');
if (arrayIndex != -1) {
int typeNameLength = canonicalTypeName.length();
while (arrayIndex < typeNameLength) {
if (canonicalTypeName.charAt(arrayIndex) == '[' &&
++arrayIndex < typeNameLength &&
canonicalTypeName.charAt(arrayIndex++) == ']') {
++arrayDimensions;
} else {
throw new IllegalArgumentException("type [" + canonicalTypeName + "] not found");
}
}
canonicalTypeName = canonicalTypeName.substring(0, canonicalTypeName.indexOf('['));
type = canonicalClassNamesToClasses.get(canonicalTypeName);
char arrayBraces[] = new char[arrayDimensions];
Arrays.fill(arrayBraces, '[');
String javaTypeName = new String(arrayBraces);
if (type == boolean.class) {
javaTypeName += "Z";
} else if (type == byte.class) {
javaTypeName += "B";
} else if (type == short.class) {
javaTypeName += "S";
} else if (type == char.class) {
javaTypeName += "C";
} else if (type == int.class) {
javaTypeName += "I";
} else if (type == long.class) {
javaTypeName += "J";
} else if (type == float.class) {
javaTypeName += "F";
} else if (type == double.class) {
javaTypeName += "D";
} else {
javaTypeName += "L" + type.getName() + ";";
}
try {
return Class.forName(javaTypeName);
} catch (ClassNotFoundException cnfe) {
throw new IllegalArgumentException("type [" + canonicalTypeName + "] not found", cnfe);
}
}
throw new IllegalArgumentException("type [" + canonicalTypeName + "] not found");
}
/**
* Converts a type to a canonical type name based on the terminology specified as part of the documentation for
* {@link PainlessLookupUtility}. Since classes are a subset of types, this method will safely convert a class
* to a canonical class name as well.
*/
public static String typeToCanonicalTypeName(Class<?> type) {
Objects.requireNonNull(type);
String canonicalTypeName = type.getCanonicalName();
if (canonicalTypeName.startsWith(def.class.getName())) {
canonicalTypeName = canonicalTypeName.replace(def.class.getName(), DEF_TYPE_NAME);
}
return canonicalTypeName;
}
/**
* Converts a list of types to a list of canonical type names as a string based on the terminology specified as part of the
* documentation for {@link PainlessLookupUtility}. Since classes are a subset of types, this method will safely convert a list
* of classes or a mixed list of classes and types to a list of canonical type names as a string as well.
*/
public static String typesToCanonicalTypeNames(List<Class<?>> types) {
StringBuilder typesStringBuilder = new StringBuilder("[");
int anyTypesSize = types.size();
int anyTypesIndex = 0;
for (Class<?> painlessType : types) {
String canonicalTypeName = typeToCanonicalTypeName(painlessType);
typesStringBuilder.append(canonicalTypeName);
if (++anyTypesIndex < anyTypesSize) {
typesStringBuilder.append(",");
}
}
typesStringBuilder.append("]");
return typesStringBuilder.toString();
}
/**
* Converts a java type to a type based on the terminology specified as part of {@link PainlessLookupUtility} where if a type is an
* object class or object array, the returned type will be the equivalent def class or def array. Otherwise, this behaves as an
* identity function.
*/
public static Class<?> javaTypeToType(Class<?> javaType) {
Objects.requireNonNull(javaType);
if (javaType.isArray()) {
Class<?> javaTypeComponent = javaType.getComponentType();
int arrayDimensions = 1;
@ -58,14 +200,11 @@ public final class PainlessLookupUtility {
}
if (javaTypeComponent == Object.class) {
char[] asmDescriptorBraces = new char[arrayDimensions];
Arrays.fill(asmDescriptorBraces, '[');
String asmDescriptor = new String(asmDescriptorBraces) + Type.getType(def.class).getDescriptor();
Type asmType = Type.getType(asmDescriptor);
char[] arrayBraces = new char[arrayDimensions];
Arrays.fill(arrayBraces, '[');
try {
return Class.forName(asmType.getInternalName().replace('/', '.'));
return Class.forName(new String(arrayBraces) + "L" + def.class.getName() + ";");
} catch (ClassNotFoundException cnfe) {
throw new IllegalStateException("internal error", cnfe);
}
@ -77,206 +216,147 @@ public final class PainlessLookupUtility {
return javaType;
}
public static Class<?> painlessDefTypeToJavaObjectType(Class<?> painlessType) {
if (painlessType.isArray()) {
Class<?> painlessTypeComponent = painlessType.getComponentType();
/**
* Converts a type to a java type based on the terminology specified as part of {@link PainlessLookupUtility} where if a type is a
* def class or def array, the returned type will be the equivalent object class or object array. Otherwise, this behaves as an
* identity function.
*/
public static Class<?> typeToJavaType(Class<?> type) {
Objects.requireNonNull(type);
if (type.isArray()) {
Class<?> typeComponent = type.getComponentType();
int arrayDimensions = 1;
while (painlessTypeComponent.isArray()) {
painlessTypeComponent = painlessTypeComponent.getComponentType();
while (typeComponent.isArray()) {
typeComponent = typeComponent.getComponentType();
++arrayDimensions;
}
if (painlessTypeComponent == def.class) {
char[] asmDescriptorBraces = new char[arrayDimensions];
Arrays.fill(asmDescriptorBraces, '[');
String asmDescriptor = new String(asmDescriptorBraces) + Type.getType(Object.class).getDescriptor();
Type asmType = Type.getType(asmDescriptor);
if (typeComponent == def.class) {
char[] arrayBraces = new char[arrayDimensions];
Arrays.fill(arrayBraces, '[');
try {
return Class.forName(asmType.getInternalName().replace('/', '.'));
} catch (ClassNotFoundException exception) {
throw new IllegalStateException("internal error", exception);
return Class.forName(new String(arrayBraces) + "L" + Object.class.getName() + ";");
} catch (ClassNotFoundException cnfe) {
throw new IllegalStateException("internal error", cnfe);
}
}
} else if (painlessType == def.class) {
} else if (type == def.class) {
return Object.class;
}
return painlessType;
return type;
}
public static String anyTypeNameToPainlessTypeName(String anyTypeName) {
return anyTypeName.replace(def.class.getName(), DEF_PAINLESS_CLASS_NAME).replace('$', '.');
}
/**
* Ensures a type exists based on the terminology specified as part of {@link PainlessLookupUtility}. Throws an
* {@link IllegalArgumentException} if the type does not exist.
*/
public static void validateType(Class<?> type, Collection<Class<?>> classes) {
String canonicalTypeName = typeToCanonicalTypeName(type);
public static String anyTypeToPainlessTypeName(Class<?> anyType) {
if (anyType.isLocalClass() || anyType.isAnonymousClass()) {
return null;
} else if (anyType.isArray()) {
Class<?> anyTypeComponent = anyType.getComponentType();
int arrayDimensions = 1;
while (anyTypeComponent.isArray()) {
anyTypeComponent = anyTypeComponent.getComponentType();
++arrayDimensions;
}
if (anyTypeComponent == def.class) {
StringBuilder painlessDefTypeNameArrayBuilder = new StringBuilder(DEF_PAINLESS_CLASS_NAME);
for (int dimension = 0; dimension < arrayDimensions; dimension++) {
painlessDefTypeNameArrayBuilder.append("[]");
}
return painlessDefTypeNameArrayBuilder.toString();
}
} else if (anyType == def.class) {
return DEF_PAINLESS_CLASS_NAME;
while (type.getComponentType() != null) {
type = type.getComponentType();
}
return anyType.getCanonicalName().replace('$', '.');
}
public static Class<?> painlessTypeNameToPainlessType(String painlessTypeName, Map<String, Class<?>> painlessClassNamesToJavaClasses) {
Class<?> javaClass = painlessClassNamesToJavaClasses.get(painlessTypeName);
if (javaClass != null) {
return javaClass;
}
int arrayDimensions = 0;
int arrayIndex = painlessTypeName.indexOf('[');
if (arrayIndex != -1) {
int painlessTypeNameLength = painlessTypeName.length();
while (arrayIndex < painlessTypeNameLength) {
if (painlessTypeName.charAt(arrayIndex) == '[' &&
++arrayIndex < painlessTypeNameLength &&
painlessTypeName.charAt(arrayIndex++) == ']') {
++arrayDimensions;
} else {
throw new IllegalArgumentException("painless type [" + painlessTypeName + "] not found");
}
}
painlessTypeName = painlessTypeName.substring(0, painlessTypeName.indexOf('['));
javaClass = painlessClassNamesToJavaClasses.get(painlessTypeName);
char javaDescriptorBraces[] = new char[arrayDimensions];
Arrays.fill(javaDescriptorBraces, '[');
String javaDescriptor = new String(javaDescriptorBraces);
if (javaClass == boolean.class) {
javaDescriptor += "Z";
} else if (javaClass == byte.class) {
javaDescriptor += "B";
} else if (javaClass == short.class) {
javaDescriptor += "S";
} else if (javaClass == char.class) {
javaDescriptor += "C";
} else if (javaClass == int.class) {
javaDescriptor += "I";
} else if (javaClass == long.class) {
javaDescriptor += "J";
} else if (javaClass == float.class) {
javaDescriptor += "F";
} else if (javaClass == double.class) {
javaDescriptor += "D";
} else {
javaDescriptor += "L" + javaClass.getName() + ";";
}
try {
return Class.forName(javaDescriptor);
} catch (ClassNotFoundException cnfe) {
throw new IllegalArgumentException("painless type [" + painlessTypeName + "] not found", cnfe);
}
}
throw new IllegalArgumentException("painless type [" + painlessTypeName + "] not found");
}
public static void validatePainlessType(Class<?> painlessType, Collection<Class<?>> javaClasses) {
String painlessTypeName = anyTypeNameToPainlessTypeName(painlessType.getName());
while (painlessType.getComponentType() != null) {
painlessType = painlessType.getComponentType();
}
if (javaClasses.contains(painlessType) == false) {
throw new IllegalArgumentException("painless type [" + painlessTypeName + "] not found");
if (classes.contains(type) == false) {
throw new IllegalArgumentException("type [" + canonicalTypeName + "] not found");
}
}
/**
* Converts a type to its boxed type equivalent if one exists based on the terminology specified as part of
* {@link PainlessLookupUtility}. Otherwise, this behaves as an identity function.
*/
public static Class<?> typeToBoxedType(Class<?> type) {
if (type == boolean.class) {
return Boolean.class;
} else if (type == byte.class) {
return Byte.class;
} else if (type == short.class) {
return Short.class;
} else if (type == char.class) {
return Character.class;
} else if (type == int.class) {
return Integer.class;
} else if (type == long.class) {
return Long.class;
} else if (type == float.class) {
return Float.class;
} else if (type == double.class) {
return Double.class;
}
return type;
}
/**
* Converts a type to its unboxed type equivalent if one exists based on the terminology specified as part of
* {@link PainlessLookupUtility}. Otherwise, this behaves as an identity function.
*/
public static Class<?> typeToUnboxedType(Class<?> type) {
if (type == Boolean.class) {
return boolean.class;
} else if (type == Byte.class) {
return byte.class;
} else if (type == Short.class) {
return short.class;
} else if (type == Character.class) {
return char.class;
} else if (type == Integer.class) {
return int.class;
} else if (type == Long.class) {
return long.class;
} else if (type == Float.class) {
return float.class;
} else if (type == Double.class) {
return double.class;
}
return type;
}
/**
* Checks if a type based on the terminology specified as part of {@link PainlessLookupUtility} is available as a constant type
* where {@code true} is returned if the type is a constant type and {@code false} otherwise.
*/
public static boolean isConstantType(Class<?> type) {
return type == boolean.class ||
type == byte.class ||
type == short.class ||
type == char.class ||
type == int.class ||
type == long.class ||
type == float.class ||
type == double.class ||
type == String.class;
}
/**
* Constructs a painless method key used to lookup painless methods from a painless class.
*/
public static String buildPainlessMethodKey(String methodName, int methodArity) {
return methodName + "/" + methodArity;
}
/**
* Constructs a painless field key used to lookup painless fields from a painless class.
*/
public static String buildPainlessFieldKey(String fieldName) {
return fieldName;
}
public static Class<?> getBoxedAnyType(Class<?> anyType) {
if (anyType == boolean.class) {
return Boolean.class;
} else if (anyType == byte.class) {
return Byte.class;
} else if (anyType == short.class) {
return Short.class;
} else if (anyType == char.class) {
return Character.class;
} else if (anyType == int.class) {
return Integer.class;
} else if (anyType == long.class) {
return Long.class;
} else if (anyType == float.class) {
return Float.class;
} else if (anyType == double.class) {
return Double.class;
}
/**
* The def type name as specified in the source for a script.
*/
public static final String DEF_TYPE_NAME = "def";
return anyType;
}
public static Class<?> getUnboxedAnyType(Class<?> anyType) {
if (anyType == Boolean.class) {
return boolean.class;
} else if (anyType == Byte.class) {
return byte.class;
} else if (anyType == Short.class) {
return short.class;
} else if (anyType == Character.class) {
return char.class;
} else if (anyType == Integer.class) {
return int.class;
} else if (anyType == Long.class) {
return long.class;
} else if (anyType == Float.class) {
return float.class;
} else if (anyType == Double.class) {
return double.class;
}
return anyType;
}
public static boolean isAnyTypeConstant(Class<?> anyType) {
return anyType == boolean.class ||
anyType == byte.class ||
anyType == short.class ||
anyType == char.class ||
anyType == int.class ||
anyType == long.class ||
anyType == float.class ||
anyType == double.class ||
anyType == String.class;
}
public static final String DEF_PAINLESS_CLASS_NAME = def.class.getSimpleName();
public static final String CONSTRUCTOR_ANY_NAME = "<init>";
/**
* The method name for all constructors.
*/
public static final String CONSTRUCTOR_NAME = "<init>";
private PainlessLookupUtility() {

View File

@ -70,21 +70,21 @@ public class PainlessMethod {
params = new Class<?>[1 + arguments.size()];
params[0] = augmentation;
for (int i = 0; i < arguments.size(); i++) {
params[i + 1] = PainlessLookupUtility.painlessDefTypeToJavaObjectType(arguments.get(i));
params[i + 1] = PainlessLookupUtility.typeToJavaType(arguments.get(i));
}
returnValue = PainlessLookupUtility.painlessDefTypeToJavaObjectType(rtn);
returnValue = PainlessLookupUtility.typeToJavaType(rtn);
} else if (Modifier.isStatic(modifiers)) {
// static method: straightforward copy
params = new Class<?>[arguments.size()];
for (int i = 0; i < arguments.size(); i++) {
params[i] = PainlessLookupUtility.painlessDefTypeToJavaObjectType(arguments.get(i));
params[i] = PainlessLookupUtility.typeToJavaType(arguments.get(i));
}
returnValue = PainlessLookupUtility.painlessDefTypeToJavaObjectType(rtn);
returnValue = PainlessLookupUtility.typeToJavaType(rtn);
} else if ("<init>".equals(name)) {
// constructor: returns the owner class
params = new Class<?>[arguments.size()];
for (int i = 0; i < arguments.size(); i++) {
params[i] = PainlessLookupUtility.painlessDefTypeToJavaObjectType(arguments.get(i));
params[i] = PainlessLookupUtility.typeToJavaType(arguments.get(i));
}
returnValue = target;
} else {
@ -92,9 +92,9 @@ public class PainlessMethod {
params = new Class<?>[1 + arguments.size()];
params[0] = target;
for (int i = 0; i < arguments.size(); i++) {
params[i + 1] = PainlessLookupUtility.painlessDefTypeToJavaObjectType(arguments.get(i));
params[i + 1] = PainlessLookupUtility.typeToJavaType(arguments.get(i));
}
returnValue = PainlessLookupUtility.painlessDefTypeToJavaObjectType(rtn);
returnValue = PainlessLookupUtility.typeToJavaType(rtn);
}
return MethodType.methodType(returnValue, params);
}

View File

@ -157,7 +157,7 @@ public abstract class AExpression extends ANode {
return ecast;
} else {
if (PainlessLookupUtility.isAnyTypeConstant(expected)) {
if (PainlessLookupUtility.isConstantType(expected)) {
// For the case where a cast is required, a constant is set,
// and the constant can be immediately cast to the expected type.
// An EConstant replaces this node with the constant cast appropriately

View File

@ -106,8 +106,8 @@ public final class EBinary extends AExpression {
if (promote == null) {
throw createError(new ClassCastException("Cannot apply multiply [*] to types " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "]."));
"[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "]."));
}
actual = promote;
@ -149,8 +149,8 @@ public final class EBinary extends AExpression {
if (promote == null) {
throw createError(new ClassCastException("Cannot apply divide [/] to types " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "]."));
"[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "]."));
}
actual = promote;
@ -197,8 +197,8 @@ public final class EBinary extends AExpression {
if (promote == null) {
throw createError(new ClassCastException("Cannot apply remainder [%] to types " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "]."));
"[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "]."));
}
actual = promote;
@ -245,8 +245,8 @@ public final class EBinary extends AExpression {
if (promote == null) {
throw createError(new ClassCastException("Cannot apply add [+] to types " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "]."));
"[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "]."));
}
actual = promote;
@ -304,8 +304,8 @@ public final class EBinary extends AExpression {
if (promote == null) {
throw createError(new ClassCastException("Cannot apply subtract [-] to types " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "]."));
"[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "]."));
}
actual = promote;
@ -363,8 +363,8 @@ public final class EBinary extends AExpression {
if (lhspromote == null || rhspromote == null) {
throw createError(new ClassCastException("Cannot apply left shift [<<] to types " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "]."));
"[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "]."));
}
actual = promote = lhspromote;
@ -411,8 +411,8 @@ public final class EBinary extends AExpression {
if (lhspromote == null || rhspromote == null) {
throw createError(new ClassCastException("Cannot apply right shift [>>] to types " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "]."));
"[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "]."));
}
actual = promote = lhspromote;
@ -462,8 +462,8 @@ public final class EBinary extends AExpression {
if (lhspromote == null || rhspromote == null) {
throw createError(new ClassCastException("Cannot apply unsigned shift [>>>] to types " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "]."));
"[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "]."));
}
if (lhspromote == def.class || rhspromote == def.class) {
@ -506,8 +506,8 @@ public final class EBinary extends AExpression {
if (promote == null) {
throw createError(new ClassCastException("Cannot apply and [&] to types " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "]."));
"[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "]."));
}
actual = promote;
@ -546,8 +546,8 @@ public final class EBinary extends AExpression {
if (promote == null) {
throw createError(new ClassCastException("Cannot apply xor [^] to types " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "]."));
"[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "]."));
}
actual = promote;
@ -587,8 +587,8 @@ public final class EBinary extends AExpression {
if (promote == null) {
throw createError(new ClassCastException("Cannot apply or [|] to types " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "]."));
"[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "]."));
}
actual = promote;

View File

@ -69,7 +69,7 @@ public final class ECapturingFunctionRef extends AExpression implements ILambda
defPointer = "D" + variable + "." + call + ",1";
} else {
// typed implementation
defPointer = "S" + PainlessLookupUtility.anyTypeToPainlessTypeName(captured.clazz) + "." + call + ",1";
defPointer = "S" + PainlessLookupUtility.typeToCanonicalTypeName(captured.clazz) + "." + call + ",1";
}
actual = String.class;
} else {
@ -77,8 +77,8 @@ public final class ECapturingFunctionRef extends AExpression implements ILambda
// static case
if (captured.clazz != def.class) {
try {
ref = new FunctionRef(
locals.getPainlessLookup(), expected, PainlessLookupUtility.anyTypeToPainlessTypeName(captured.clazz), call, 1);
ref = new FunctionRef(locals.getPainlessLookup(), expected,
PainlessLookupUtility.typeToCanonicalTypeName(captured.clazz), call, 1);
// check casts between the interface method and the delegate method are legal
for (int i = 0; i < ref.interfaceMethod.arguments.size(); ++i) {
@ -110,7 +110,7 @@ public final class ECapturingFunctionRef extends AExpression implements ILambda
// typed interface, dynamic implementation
writer.visitVarInsn(MethodWriter.getType(captured.clazz).getOpcode(Opcodes.ILOAD), captured.getSlot());
Type methodType = Type.getMethodType(MethodWriter.getType(expected), MethodWriter.getType(captured.clazz));
writer.invokeDefCall(call, methodType, DefBootstrap.REFERENCE, PainlessLookupUtility.anyTypeToPainlessTypeName(expected));
writer.invokeDefCall(call, methodType, DefBootstrap.REFERENCE, PainlessLookupUtility.typeToCanonicalTypeName(expected));
} else {
// typed interface, typed implementation
writer.visitVarInsn(MethodWriter.getType(captured.clazz).getOpcode(Opcodes.ILOAD), captured.getSlot());

View File

@ -63,6 +63,6 @@ final class ECast extends AExpression {
@Override
public String toString() {
return singleLineToString(PainlessLookupUtility.anyTypeToPainlessTypeName(cast.to), child);
return singleLineToString(PainlessLookupUtility.typeToCanonicalTypeName(cast.to), child);
}
}

View File

@ -93,8 +93,8 @@ public final class EComp extends AExpression {
if (promotedType == null) {
throw createError(new ClassCastException("Cannot apply equals [==] to types " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "]."));
"[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "]."));
}
if (promotedType == def.class) {
@ -143,8 +143,8 @@ public final class EComp extends AExpression {
if (promotedType == null) {
throw createError(new ClassCastException("Cannot apply reference equals [===] to types " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "]."));
"[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "]."));
}
left.expected = promotedType;
@ -184,8 +184,8 @@ public final class EComp extends AExpression {
if (promotedType == null) {
throw createError(new ClassCastException("Cannot apply not equals [!=] to types " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "]."));
"[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "]."));
}
if (promotedType == def.class) {
@ -234,8 +234,8 @@ public final class EComp extends AExpression {
if (promotedType == null) {
throw createError(new ClassCastException("Cannot apply reference not equals [!==] to types " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "]."));
"[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "]."));
}
left.expected = promotedType;
@ -275,8 +275,8 @@ public final class EComp extends AExpression {
if (promotedType == null) {
throw createError(new ClassCastException("Cannot apply greater than or equals [>=] to types " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "]."));
"[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "]."));
}
if (promotedType == def.class) {
@ -315,8 +315,8 @@ public final class EComp extends AExpression {
if (promotedType == null) {
throw createError(new ClassCastException("Cannot apply greater than [>] to types " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "]."));
"[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "]."));
}
if (promotedType == def.class) {
@ -355,8 +355,8 @@ public final class EComp extends AExpression {
if (promotedType == null) {
throw createError(new ClassCastException("Cannot apply less than or equals [<=] to types " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "]."));
"[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "]."));
}
if (promotedType == def.class) {
@ -395,8 +395,8 @@ public final class EComp extends AExpression {
if (promotedType == null) {
throw createError(new ClassCastException("Cannot apply less than [>=] to types " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(right.actual) + "]."));
"[" + PainlessLookupUtility.typeToCanonicalTypeName(left.actual) + "] and " +
"[" + PainlessLookupUtility.typeToCanonicalTypeName(right.actual) + "]."));
}
if (promotedType == def.class) {

View File

@ -68,13 +68,13 @@ public final class EFunctionRef extends AExpression implements ILambda {
PainlessMethod interfaceMethod = locals.getPainlessLookup().getPainlessStructFromJavaClass(expected).functionalMethod;
if (interfaceMethod == null) {
throw new IllegalArgumentException("Cannot convert function reference [" + type + "::" + call + "] " +
"to [" + PainlessLookupUtility.anyTypeToPainlessTypeName(expected) + "], not a functional interface");
"to [" + PainlessLookupUtility.typeToCanonicalTypeName(expected) + "], not a functional interface");
}
PainlessMethod delegateMethod =
locals.getMethod(PainlessLookupUtility.buildPainlessMethodKey(call, interfaceMethod.arguments.size()));
if (delegateMethod == null) {
throw new IllegalArgumentException("Cannot convert function reference [" + type + "::" + call + "] " +
"to [" + PainlessLookupUtility.anyTypeToPainlessTypeName(expected) + "], function not found");
"to [" + PainlessLookupUtility.typeToCanonicalTypeName(expected) + "], function not found");
}
ref = new FunctionRef(expected, interfaceMethod, delegateMethod, 0);

View File

@ -64,8 +64,8 @@ public final class EInstanceof extends AExpression {
}
// map to wrapped type for primitive types
resolvedType = clazz.isPrimitive() ? PainlessLookupUtility.getBoxedAnyType(clazz) :
PainlessLookupUtility.painlessDefTypeToJavaObjectType(clazz);
resolvedType = clazz.isPrimitive() ? PainlessLookupUtility.typeToBoxedType(clazz) :
PainlessLookupUtility.typeToJavaType(clazz);
// analyze and cast the expression
expression.analyze(locals);
@ -76,7 +76,7 @@ public final class EInstanceof extends AExpression {
primitiveExpression = expression.actual.isPrimitive();
// map to wrapped type for primitive types
expressionType = expression.actual.isPrimitive() ?
PainlessLookupUtility.getBoxedAnyType(expression.actual) : PainlessLookupUtility.painlessDefTypeToJavaObjectType(clazz);
PainlessLookupUtility.typeToBoxedType(expression.actual) : PainlessLookupUtility.typeToJavaType(clazz);
actual = boolean.class;
}

View File

@ -123,12 +123,12 @@ public final class ELambda extends AExpression implements ILambda {
interfaceMethod = locals.getPainlessLookup().getPainlessStructFromJavaClass(expected).functionalMethod;
if (interfaceMethod == null) {
throw createError(new IllegalArgumentException("Cannot pass lambda to " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(expected) + "], not a functional interface"));
"[" + PainlessLookupUtility.typeToCanonicalTypeName(expected) + "], not a functional interface"));
}
// check arity before we manipulate parameters
if (interfaceMethod.arguments.size() != paramTypeStrs.size())
throw new IllegalArgumentException("Incorrect number of parameters for [" + interfaceMethod.name +
"] in [" + PainlessLookupUtility.anyTypeToPainlessTypeName(expected) + "]");
"] in [" + PainlessLookupUtility.typeToCanonicalTypeName(expected) + "]");
// for method invocation, its allowed to ignore the return value
if (interfaceMethod.rtn == void.class) {
returnType = def.class;
@ -140,7 +140,7 @@ public final class ELambda extends AExpression implements ILambda {
for (int i = 0; i < paramTypeStrs.size(); i++) {
String paramType = paramTypeStrs.get(i);
if (paramType == null) {
actualParamTypeStrs.add(PainlessLookupUtility.anyTypeToPainlessTypeName(interfaceMethod.arguments.get(i)));
actualParamTypeStrs.add(PainlessLookupUtility.typeToCanonicalTypeName(interfaceMethod.arguments.get(i)));
} else {
actualParamTypeStrs.add(paramType);
}
@ -162,14 +162,14 @@ public final class ELambda extends AExpression implements ILambda {
List<String> paramTypes = new ArrayList<>(captures.size() + actualParamTypeStrs.size());
List<String> paramNames = new ArrayList<>(captures.size() + paramNameStrs.size());
for (Variable var : captures) {
paramTypes.add(PainlessLookupUtility.anyTypeToPainlessTypeName(var.clazz));
paramTypes.add(PainlessLookupUtility.typeToCanonicalTypeName(var.clazz));
paramNames.add(var.name);
}
paramTypes.addAll(actualParamTypeStrs);
paramNames.addAll(paramNameStrs);
// desugar lambda body into a synthetic method
desugared = new SFunction(reserved, location, PainlessLookupUtility.anyTypeToPainlessTypeName(returnType), name,
desugared = new SFunction(reserved, location, PainlessLookupUtility.typeToCanonicalTypeName(returnType), name,
paramTypes, paramNames, statements, true);
desugared.generateSignature(locals.getPainlessLookup());
desugared.analyze(Locals.newLambdaScope(locals.getProgramScope(), returnType,

View File

@ -53,7 +53,7 @@ public final class ENull extends AExpression {
if (expected != null) {
if (expected.isPrimitive()) {
throw createError(new IllegalArgumentException(
"Cannot cast null to a primitive type [" + PainlessLookupUtility.anyTypeToPainlessTypeName(expected) + "]."));
"Cannot cast null to a primitive type [" + PainlessLookupUtility.typeToCanonicalTypeName(expected) + "]."));
}
actual = expected;

View File

@ -94,7 +94,7 @@ public final class EUnary extends AExpression {
if (promote == null) {
throw createError(new ClassCastException("Cannot apply not [~] to type " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(child.actual) + "]."));
"[" + PainlessLookupUtility.typeToCanonicalTypeName(child.actual) + "]."));
}
child.expected = promote;
@ -124,7 +124,7 @@ public final class EUnary extends AExpression {
if (promote == null) {
throw createError(new ClassCastException("Cannot apply positive [+] to type " +
"[" + PainlessLookupUtility.painlessDefTypeToJavaObjectType(child.actual) + "]."));
"[" + PainlessLookupUtility.typeToJavaType(child.actual) + "]."));
}
child.expected = promote;
@ -158,7 +158,7 @@ public final class EUnary extends AExpression {
if (promote == null) {
throw createError(new ClassCastException("Cannot apply negative [-] to type " +
"[" + PainlessLookupUtility.painlessDefTypeToJavaObjectType(child.actual) + "]."));
"[" + PainlessLookupUtility.typeToJavaType(child.actual) + "]."));
}
child.expected = promote;

View File

@ -68,7 +68,7 @@ public final class PBrace extends AStoreable {
sub = new PSubListShortcut(location, locals.getPainlessLookup().getPainlessStructFromJavaClass(prefix.actual), index);
} else {
throw createError(new IllegalArgumentException("Illegal array access on type " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(prefix.actual) + "]."));
"[" + PainlessLookupUtility.typeToCanonicalTypeName(prefix.actual) + "]."));
}
sub.write = write;

View File

@ -73,7 +73,7 @@ public final class PCallInvoke extends AExpression {
PainlessClass struct = locals.getPainlessLookup().getPainlessStructFromJavaClass(prefix.actual);
if (prefix.actual.isPrimitive()) {
struct = locals.getPainlessLookup().getPainlessStructFromJavaClass(PainlessLookupUtility.getBoxedAnyType(prefix.actual));
struct = locals.getPainlessLookup().getPainlessStructFromJavaClass(PainlessLookupUtility.typeToBoxedType(prefix.actual));
}
String methodKey = PainlessLookupUtility.buildPainlessMethodKey(name, arguments.size());

View File

@ -63,7 +63,7 @@ public final class PField extends AStoreable {
prefix = prefix.cast(locals);
if (prefix.actual.isArray()) {
sub = new PSubArrayLength(location, PainlessLookupUtility.anyTypeToPainlessTypeName(prefix.actual), value);
sub = new PSubArrayLength(location, PainlessLookupUtility.typeToCanonicalTypeName(prefix.actual), value);
} else if (prefix.actual == def.class) {
sub = new PSubDefField(location, value);
} else {
@ -85,7 +85,8 @@ public final class PField extends AStoreable {
"set" + Character.toUpperCase(value.charAt(0)) + value.substring(1), 1));
if (getter != null || setter != null) {
sub = new PSubShortcut(location, value, PainlessLookupUtility.anyTypeToPainlessTypeName(prefix.actual), getter, setter);
sub = new PSubShortcut(
location, value, PainlessLookupUtility.typeToCanonicalTypeName(prefix.actual), getter, setter);
} else {
EConstant index = new EConstant(location, value);
index.analyze(locals);
@ -103,7 +104,7 @@ public final class PField extends AStoreable {
if (sub == null) {
throw createError(new IllegalArgumentException(
"Unknown field [" + value + "] for type [" + PainlessLookupUtility.anyTypeToPainlessTypeName(prefix.actual) + "]."));
"Unknown field [" + value + "] for type [" + PainlessLookupUtility.typeToCanonicalTypeName(prefix.actual) + "]."));
}
if (nullSafe) {

View File

@ -53,7 +53,7 @@ final class PSubField extends AStoreable {
void analyze(Locals locals) {
if (write && Modifier.isFinal(field.modifiers)) {
throw createError(new IllegalArgumentException("Cannot write to read-only field [" + field.name + "] for type " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(field.clazz) + "]."));
"[" + PainlessLookupUtility.typeToCanonicalTypeName(field.clazz) + "]."));
}
actual = field.clazz;

View File

@ -85,7 +85,7 @@ public class SEach extends AStatement {
sub = new SSubEachIterable(location, variable, expression, block);
} else {
throw createError(new IllegalArgumentException("Illegal for each type " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(expression.actual) + "]."));
"[" + PainlessLookupUtility.typeToCanonicalTypeName(expression.actual) + "]."));
}
sub.analyze(locals);

View File

@ -136,7 +136,7 @@ public final class SFunction extends AStatement {
try {
Class<?> paramType = painlessLookup.getJavaClassFromPainlessType(this.paramTypeStrs.get(param));
paramClasses[param] = PainlessLookupUtility.painlessDefTypeToJavaObjectType(paramType);
paramClasses[param] = PainlessLookupUtility.typeToJavaType(paramType);
paramTypes.add(paramType);
parameters.add(new Parameter(location, paramNameStrs.get(param), paramType));
} catch (IllegalArgumentException exception) {
@ -146,7 +146,7 @@ public final class SFunction extends AStatement {
}
org.objectweb.asm.commons.Method method = new org.objectweb.asm.commons.Method(name, MethodType.methodType(
PainlessLookupUtility.painlessDefTypeToJavaObjectType(rtnType), paramClasses).toMethodDescriptorString());
PainlessLookupUtility.typeToJavaType(rtnType), paramClasses).toMethodDescriptorString());
this.method = new PainlessMethod(name, null, null, rtnType, paramTypes, method, Modifier.STATIC | Modifier.PRIVATE, null);
}

View File

@ -109,6 +109,6 @@ final class SSubEachArray extends AStatement {
@Override
public String toString() {
return singleLineToString(PainlessLookupUtility.anyTypeToPainlessTypeName(variable.clazz), variable.name, expression, block);
return singleLineToString(PainlessLookupUtility.typeToCanonicalTypeName(variable.clazz), variable.name, expression, block);
}
}

View File

@ -81,7 +81,7 @@ final class SSubEachIterable extends AStatement {
if (method == null) {
throw createError(new IllegalArgumentException("Unable to create iterator for the type " +
"[" + PainlessLookupUtility.anyTypeToPainlessTypeName(expression.actual) + "]."));
"[" + PainlessLookupUtility.typeToCanonicalTypeName(expression.actual) + "]."));
}
}
@ -132,6 +132,6 @@ final class SSubEachIterable extends AStatement {
@Override
public String toString() {
return singleLineToString(PainlessLookupUtility.anyTypeToPainlessTypeName(variable.clazz), variable.name, expression, block);
return singleLineToString(PainlessLookupUtility.typeToCanonicalTypeName(variable.clazz), variable.name, expression, block);
}
}

View File

@ -210,7 +210,7 @@ public class PainlessDocGenerator {
*/
private static void emitAnchor(PrintStream stream, Class<?> clazz) {
stream.print("painless-api-reference-");
stream.print(PainlessLookupUtility.anyTypeToPainlessTypeName(clazz).replace('.', '-'));
stream.print(PainlessLookupUtility.typeToCanonicalTypeName(clazz).replace('.', '-'));
}
/**
@ -234,7 +234,7 @@ public class PainlessDocGenerator {
}
private static String methodName(PainlessMethod method) {
return method.name.equals("<init>") ? PainlessLookupUtility.anyTypeToPainlessTypeName(method.target) : method.name;
return method.name.equals("<init>") ? PainlessLookupUtility.typeToCanonicalTypeName(method.target) : method.name;
}
/**

View File

@ -156,16 +156,6 @@ if (isEclipse) {
compileJava.options.compilerArgs << "-Xlint:-cast,-deprecation,-rawtypes,-try,-unchecked"
compileTestJava.options.compilerArgs << "-Xlint:-cast,-deprecation,-rawtypes,-try,-unchecked"
// TODO: remove ScriptDocValuesMissingV6BehaviourTests in 7.0
additionalTest('testScriptDocValuesMissingV6Behaviour'){
include '**/ScriptDocValuesMissingV6BehaviourTests.class'
systemProperty 'es.scripting.exception_for_missing_value', 'false'
}
test {
// these are tested explicitly in separate test tasks
exclude '**/*ScriptDocValuesMissingV6BehaviourTests.class'
}
forbiddenPatterns {
exclude '**/*.json'
exclude '**/*.jmx'

View File

@ -29,7 +29,6 @@ import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.geo.GeoUtils;
import org.elasticsearch.common.logging.DeprecationLogger;
import org.elasticsearch.common.logging.ESLoggerFactory;
import org.elasticsearch.script.ScriptModule;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.MutableDateTime;
@ -126,11 +125,8 @@ public abstract class ScriptDocValues<T> extends AbstractList<T> {
public long getValue() {
if (count == 0) {
if (ScriptModule.EXCEPTION_FOR_MISSING_VALUE) {
throw new IllegalStateException("A document doesn't have a value for a field! " +
"Use doc[<field>].size()==0 to check if a document is missing a field!");
}
return 0L;
throw new IllegalStateException("A document doesn't have a value for a field! " +
"Use doc[<field>].size()==0 to check if a document is missing a field!");
}
return values[0];
}
@ -172,11 +168,8 @@ public abstract class ScriptDocValues<T> extends AbstractList<T> {
*/
public ReadableDateTime getValue() {
if (count == 0) {
if (ScriptModule.EXCEPTION_FOR_MISSING_VALUE) {
throw new IllegalStateException("A document doesn't have a value for a field! " +
"Use doc[<field>].size()==0 to check if a document is missing a field!");
}
return EPOCH;
throw new IllegalStateException("A document doesn't have a value for a field! " +
"Use doc[<field>].size()==0 to check if a document is missing a field!");
}
return get(0);
}
@ -277,11 +270,8 @@ public abstract class ScriptDocValues<T> extends AbstractList<T> {
public double getValue() {
if (count == 0) {
if (ScriptModule.EXCEPTION_FOR_MISSING_VALUE) {
throw new IllegalStateException("A document doesn't have a value for a field! " +
"Use doc[<field>].size()==0 to check if a document is missing a field!");
}
return 0d;
throw new IllegalStateException("A document doesn't have a value for a field! " +
"Use doc[<field>].size()==0 to check if a document is missing a field!");
}
return values[0];
}
@ -337,11 +327,8 @@ public abstract class ScriptDocValues<T> extends AbstractList<T> {
public GeoPoint getValue() {
if (count == 0) {
if (ScriptModule.EXCEPTION_FOR_MISSING_VALUE) {
throw new IllegalStateException("A document doesn't have a value for a field! " +
throw new IllegalStateException("A document doesn't have a value for a field! " +
"Use doc[<field>].size()==0 to check if a document is missing a field!");
}
return null;
}
return values[0];
}
@ -454,11 +441,8 @@ public abstract class ScriptDocValues<T> extends AbstractList<T> {
public boolean getValue() {
if (count == 0) {
if (ScriptModule.EXCEPTION_FOR_MISSING_VALUE) {
throw new IllegalStateException("A document doesn't have a value for a field! " +
"Use doc[<field>].size()==0 to check if a document is missing a field!");
}
return false;
throw new IllegalStateException("A document doesn't have a value for a field! " +
"Use doc[<field>].size()==0 to check if a document is missing a field!");
}
return values[0];
}
@ -544,11 +528,8 @@ public abstract class ScriptDocValues<T> extends AbstractList<T> {
public String getValue() {
if (count == 0) {
if (ScriptModule.EXCEPTION_FOR_MISSING_VALUE) {
throw new IllegalStateException("A document doesn't have a value for a field! " +
throw new IllegalStateException("A document doesn't have a value for a field! " +
"Use doc[<field>].size()==0 to check if a document is missing a field!");
}
return null;
}
return get(0);
}
@ -572,11 +553,8 @@ public abstract class ScriptDocValues<T> extends AbstractList<T> {
public BytesRef getValue() {
if (count == 0) {
if (ScriptModule.EXCEPTION_FOR_MISSING_VALUE) {
throw new IllegalStateException("A document doesn't have a value for a field! " +
throw new IllegalStateException("A document doesn't have a value for a field! " +
"Use doc[<field>].size()==0 to check if a document is missing a field!");
}
return new BytesRef();
}
return get(0);
}

View File

@ -31,9 +31,7 @@ import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.plugins.ScriptPlugin;
import org.elasticsearch.search.aggregations.pipeline.movfn.MovingFunctionScript;
import org.elasticsearch.common.Booleans;
import org.elasticsearch.common.logging.DeprecationLogger;
import org.elasticsearch.common.logging.Loggers;
/**
* Manages building {@link ScriptService}.
@ -64,11 +62,6 @@ public class ScriptModule {
).collect(Collectors.toMap(c -> c.name, Function.identity()));
}
public static final boolean EXCEPTION_FOR_MISSING_VALUE =
Booleans.parseBoolean(System.getProperty("es.scripting.exception_for_missing_value", "false"));
private static final DeprecationLogger DEPRECATION_LOGGER = new DeprecationLogger(Loggers.getLogger(ScriptModule.class));
private final ScriptService scriptService;
public ScriptModule(Settings settings, List<ScriptPlugin> scriptPlugins) {
@ -92,10 +85,6 @@ public class ScriptModule {
}
}
}
if (EXCEPTION_FOR_MISSING_VALUE == false)
DEPRECATION_LOGGER.deprecated("Script: returning default values for missing document values is deprecated. " +
"Set system property '-Des.scripting.exception_for_missing_value=true' " +
"to make behaviour compatible with future major versions.");
scriptService = new ScriptService(settings, Collections.unmodifiableMap(engines), Collections.unmodifiableMap(contexts));
}

View File

@ -1,195 +0,0 @@
/*
* 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.index.fielddata;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.fielddata.ScriptDocValues.Longs;
import org.elasticsearch.index.fielddata.ScriptDocValues.Dates;
import org.elasticsearch.index.fielddata.ScriptDocValues.Booleans;
import org.elasticsearch.plugins.ScriptPlugin;
import org.elasticsearch.script.MockScriptEngine;
import org.elasticsearch.script.ScriptContext;
import org.elasticsearch.script.ScriptEngine;
import org.elasticsearch.script.ScriptModule;
import org.elasticsearch.test.ESTestCase;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.ReadableDateTime;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import static java.util.Collections.singletonList;
public class ScriptDocValuesMissingV6BehaviourTests extends ESTestCase {
public void testScriptMissingValuesWarning(){
new ScriptModule(Settings.EMPTY, singletonList(new ScriptPlugin() {
@Override
public ScriptEngine getScriptEngine(Settings settings, Collection<ScriptContext<?>> contexts) {
return new MockScriptEngine(MockScriptEngine.NAME, Collections.singletonMap("1", script -> "1"));
}
}));
assertWarnings("Script: returning default values for missing document values is deprecated. " +
"Set system property '-Des.scripting.exception_for_missing_value=true' " +
"to make behaviour compatible with future major versions.");
}
public void testZeroForMissingValueLong() throws IOException {
long[][] values = new long[between(3, 10)][];
for (int d = 0; d < values.length; d++) {
values[d] = new long[0];
}
Longs longs = wrap(values);
for (int round = 0; round < 10; round++) {
int d = between(0, values.length - 1);
longs.setNextDocId(d);
assertEquals(0, longs.getValue());
}
}
public void testEpochForMissingValueDate() throws IOException {
final ReadableDateTime EPOCH = new DateTime(0, DateTimeZone.UTC);
long[][] values = new long[between(3, 10)][];
for (int d = 0; d < values.length; d++) {
values[d] = new long[0];
}
Dates dates = wrapDates(values);
for (int round = 0; round < 10; round++) {
int d = between(0, values.length - 1);
dates.setNextDocId(d);
assertEquals(EPOCH, dates.getValue());
}
}
public void testFalseForMissingValueBoolean() throws IOException {
long[][] values = new long[between(3, 10)][];
for (int d = 0; d < values.length; d++) {
values[d] = new long[0];
}
Booleans bools = wrapBooleans(values);
for (int round = 0; round < 10; round++) {
int d = between(0, values.length - 1);
bools.setNextDocId(d);
assertEquals(false, bools.getValue());
}
}
public void testNullForMissingValueGeo() throws IOException{
final MultiGeoPointValues values = wrap(new GeoPoint[0]);
final ScriptDocValues.GeoPoints script = new ScriptDocValues.GeoPoints(values);
script.setNextDocId(0);
assertEquals(null, script.getValue());
}
private Longs wrap(long[][] values) {
return new Longs(new AbstractSortedNumericDocValues() {
long[] current;
int i;
@Override
public boolean advanceExact(int doc) {
i = 0;
current = values[doc];
return current.length > 0;
}
@Override
public int docValueCount() {
return current.length;
}
@Override
public long nextValue() {
return current[i++];
}
});
}
private Booleans wrapBooleans(long[][] values) {
return new Booleans(new AbstractSortedNumericDocValues() {
long[] current;
int i;
@Override
public boolean advanceExact(int doc) {
i = 0;
current = values[doc];
return current.length > 0;
}
@Override
public int docValueCount() {
return current.length;
}
@Override
public long nextValue() {
return current[i++];
}
});
}
private Dates wrapDates(long[][] values) {
return new Dates(new AbstractSortedNumericDocValues() {
long[] current;
int i;
@Override
public boolean advanceExact(int doc) {
current = values[doc];
i = 0;
return current.length > 0;
}
@Override
public int docValueCount() {
return current.length;
}
@Override
public long nextValue() {
return current[i++];
}
});
}
private static MultiGeoPointValues wrap(final GeoPoint... points) {
return new MultiGeoPointValues() {
int docID = -1;
int i;
@Override
public GeoPoint nextValue() {
if (docID != 0) {
fail();
}
return points[i++];
}
@Override
public boolean advanceExact(int docId) {
docID = docId;
return points.length > 0;
}
@Override
public int docValueCount() {
if (docID != 0) {
return 0;
}
return points.length;
}
};
}
}

View File

@ -120,7 +120,8 @@ public class LicenseService extends AbstractLifecycleComponent implements Cluste
this.scheduler = new SchedulerEngine(clock);
this.licenseState = licenseState;
this.operationModeFileWatcher = new OperationModeFileWatcher(resourceWatcherService,
XPackPlugin.resolveConfigFile(env, "license_mode"), logger, () -> updateLicenseState(getLicense()));
XPackPlugin.resolveConfigFile(env, "license_mode"), logger,
() -> updateLicenseState(getLicensesMetaData()));
this.scheduler.register(this);
populateExpirationCallbacks();
}
@ -265,11 +266,11 @@ public class LicenseService extends AbstractLifecycleComponent implements Cluste
@Override
public void triggered(SchedulerEngine.Event event) {
final LicensesMetaData licensesMetaData = clusterService.state().metaData().custom(LicensesMetaData.TYPE);
final LicensesMetaData licensesMetaData = getLicensesMetaData();
if (licensesMetaData != null) {
final License license = licensesMetaData.getLicense();
if (event.getJobName().equals(LICENSE_JOB)) {
updateLicenseState(license);
updateLicenseState(license, licensesMetaData.getMostRecentTrialVersion());
} else if (event.getJobName().startsWith(ExpirationCallback.EXPIRATION_JOB_PREFIX)) {
expirationCallbacks.stream()
.filter(expirationCallback -> expirationCallback.getId().equals(event.getJobName()))
@ -311,6 +312,10 @@ public class LicenseService extends AbstractLifecycleComponent implements Cluste
return license == LicensesMetaData.LICENSE_TOMBSTONE ? null : license;
}
private LicensesMetaData getLicensesMetaData() {
return this.clusterService.state().metaData().custom(LicensesMetaData.TYPE);
}
void startTrialLicense(PostStartTrialRequest request, final ActionListener<PostStartTrialResponse> listener) {
if (VALID_TRIAL_TYPES.contains(request.getType()) == false) {
throw new IllegalArgumentException("Cannot start trial of type [" + request.getType() + "]. Valid trial types are "
@ -422,10 +427,16 @@ public class LicenseService extends AbstractLifecycleComponent implements Cluste
}
}
protected void updateLicenseState(final License license) {
private void updateLicenseState(LicensesMetaData licensesMetaData) {
if (licensesMetaData != null) {
updateLicenseState(getLicense(licensesMetaData), licensesMetaData.getMostRecentTrialVersion());
}
}
protected void updateLicenseState(final License license, Version mostRecentTrialVersion) {
if (license == LicensesMetaData.LICENSE_TOMBSTONE) {
// implies license has been explicitly deleted
licenseState.update(License.OperationMode.MISSING, false);
licenseState.update(License.OperationMode.MISSING, false, mostRecentTrialVersion);
return;
}
if (license != null) {
@ -438,7 +449,7 @@ public class LicenseService extends AbstractLifecycleComponent implements Cluste
// date that is near Long.MAX_VALUE
active = time >= license.issueDate() && time - GRACE_PERIOD_DURATION.getMillis() < license.expiryDate();
}
licenseState.update(license.operationMode(), active);
licenseState.update(license.operationMode(), active, mostRecentTrialVersion);
if (active) {
if (time < license.expiryDate()) {
@ -480,7 +491,7 @@ public class LicenseService extends AbstractLifecycleComponent implements Cluste
logger.info("license [{}] mode [{}] - valid", license.uid(),
license.operationMode().name().toLowerCase(Locale.ROOT));
}
updateLicenseState(license);
updateLicenseState(license, currentLicensesMetaData.getMostRecentTrialVersion());
}
}

View File

@ -5,8 +5,11 @@
*/
package org.elasticsearch.license;
import org.elasticsearch.Version;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.logging.LoggerMessageFormat;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.License.OperationMode;
import org.elasticsearch.xpack.core.XPackField;
@ -266,6 +269,7 @@ public class XPackLicenseState {
private final List<Runnable> listeners = new CopyOnWriteArrayList<>();
private final boolean isSecurityEnabled;
private final boolean isSecurityExplicitlyEnabled;
private volatile boolean isSecurityEnabledByTrialVersion;
public XPackLicenseState(Settings settings) {
this.isSecurityEnabled = XPackSettings.SECURITY_ENABLED.get(settings);
@ -274,11 +278,30 @@ public class XPackLicenseState {
// setting is not explicitly set
this.isSecurityExplicitlyEnabled = isSecurityEnabled &&
(settings.hasValue(XPackSettings.SECURITY_ENABLED.getKey()) || XPackSettings.TRANSPORT_SSL_ENABLED.get(settings));
this.isSecurityEnabledByTrialVersion = false;
}
/** Updates the current state of the license, which will change what features are available. */
void update(OperationMode mode, boolean active) {
/**
* Updates the current state of the license, which will change what features are available.
*
* @param mode The mode (type) of the current license.
* @param active True if the current license exists and is within its allowed usage period; false if it is expired or missing.
* @param mostRecentTrialVersion If this cluster has, at some point commenced a trial, the most recent version on which they did that.
* May be {@code null} if they have never generated a trial license on this cluster, or the most recent
* trial was prior to this metadata being tracked (6.1)
*/
void update(OperationMode mode, boolean active, @Nullable Version mostRecentTrialVersion) {
status = new Status(mode, active);
if (isSecurityEnabled == true && isSecurityExplicitlyEnabled == false && mode == OperationMode.TRIAL
&& isSecurityEnabledByTrialVersion == false) {
// Before 6.3, Trial licenses would default having security enabled.
// If this license was generated before that version, then treat it as if security is explicitly enabled
if (mostRecentTrialVersion == null || mostRecentTrialVersion.before(Version.V_6_3_0)) {
Loggers.getLogger(getClass()).info("Automatically enabling security for older trial license ({})",
mostRecentTrialVersion == null ? "[pre 6.1.0]" : mostRecentTrialVersion.toString());
isSecurityEnabledByTrialVersion = true;
}
}
listeners.forEach(Runnable::run);
}
@ -603,6 +626,6 @@ public class XPackLicenseState {
public boolean isSecurityEnabled() {
final OperationMode mode = status.mode;
return mode == OperationMode.TRIAL ? isSecurityExplicitlyEnabled : isSecurityEnabled;
return mode == OperationMode.TRIAL ? (isSecurityExplicitlyEnabled || isSecurityEnabledByTrialVersion) : isSecurityEnabled;
}
}

View File

@ -6,6 +6,7 @@
package org.elasticsearch.license;
import com.carrotsearch.randomizedtesting.RandomizedTest;
import org.elasticsearch.Version;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.Strings;
@ -353,20 +354,22 @@ public class TestUtils {
public static class AssertingLicenseState extends XPackLicenseState {
public final List<License.OperationMode> modeUpdates = new ArrayList<>();
public final List<Boolean> activeUpdates = new ArrayList<>();
public final List<Version> trialVersionUpdates = new ArrayList<>();
public AssertingLicenseState() {
super(Settings.EMPTY);
}
@Override
void update(License.OperationMode mode, boolean active) {
void update(License.OperationMode mode, boolean active, Version mostRecentTrialVersion) {
modeUpdates.add(mode);
activeUpdates.add(active);
trialVersionUpdates.add(mostRecentTrialVersion);
}
}
/**
* A license state that makes the {@link #update(License.OperationMode, boolean)}
* A license state that makes the {@link #update(License.OperationMode, boolean, Version)}
* method public for use in tests.
*/
public static class UpdatableLicenseState extends XPackLicenseState {
@ -379,8 +382,8 @@ public class TestUtils {
}
@Override
public void update(License.OperationMode mode, boolean active) {
super.update(mode, active);
public void update(License.OperationMode mode, boolean active, Version mostRecentTrialVersion) {
super.update(mode, active, mostRecentTrialVersion);
}
}

View File

@ -5,9 +5,11 @@
*/
package org.elasticsearch.license;
import org.elasticsearch.Version;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.License.OperationMode;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.VersionUtils;
import org.elasticsearch.xpack.core.XPackField;
import org.elasticsearch.xpack.core.XPackSettings;
@ -31,7 +33,7 @@ public class XPackLicenseStateTests extends ESTestCase {
/** Creates a license state with the given license type and active state, and checks the given method returns expected. */
void assertAllowed(OperationMode mode, boolean active, Predicate<XPackLicenseState> predicate, boolean expected) {
XPackLicenseState licenseState = new XPackLicenseState(Settings.EMPTY);
licenseState.update(mode, active);
licenseState.update(mode, active, null);
assertEquals(expected, predicate.test(licenseState));
}
@ -102,7 +104,7 @@ public class XPackLicenseStateTests extends ESTestCase {
public void testSecurityBasic() {
XPackLicenseState licenseState = new XPackLicenseState(randomFrom(Settings.EMPTY,
Settings.builder().put(XPackSettings.SECURITY_ENABLED.getKey(), true).build()));
licenseState.update(BASIC, true);
licenseState.update(BASIC, true, null);
assertThat(licenseState.isAuthAllowed(), is(false));
assertThat(licenseState.isIpFilteringAllowed(), is(false));
@ -116,7 +118,7 @@ public class XPackLicenseStateTests extends ESTestCase {
public void testSecurityBasicExpired() {
XPackLicenseState licenseState = new XPackLicenseState(randomFrom(Settings.EMPTY,
Settings.builder().put(XPackSettings.SECURITY_ENABLED.getKey(), true).build()));
licenseState.update(BASIC, false);
licenseState.update(BASIC, false, null);
assertThat(licenseState.isAuthAllowed(), is(false));
assertThat(licenseState.isIpFilteringAllowed(), is(false));
@ -130,7 +132,7 @@ public class XPackLicenseStateTests extends ESTestCase {
public void testSecurityStandard() {
XPackLicenseState licenseState = new XPackLicenseState(randomFrom(Settings.EMPTY,
Settings.builder().put(XPackSettings.SECURITY_ENABLED.getKey(), true).build()));
licenseState.update(STANDARD, true);
licenseState.update(STANDARD, true, null);
assertThat(licenseState.isAuthAllowed(), is(true));
assertThat(licenseState.isIpFilteringAllowed(), is(false));
@ -144,7 +146,7 @@ public class XPackLicenseStateTests extends ESTestCase {
public void testSecurityStandardExpired() {
XPackLicenseState licenseState = new XPackLicenseState(randomFrom(Settings.EMPTY,
Settings.builder().put(XPackSettings.SECURITY_ENABLED.getKey(), true).build()));
licenseState.update(STANDARD, false);
licenseState.update(STANDARD, false, null);
assertThat(licenseState.isAuthAllowed(), is(true));
assertThat(licenseState.isIpFilteringAllowed(), is(false));
@ -158,7 +160,7 @@ public class XPackLicenseStateTests extends ESTestCase {
public void testSecurityGold() {
XPackLicenseState licenseState = new XPackLicenseState(randomFrom(Settings.EMPTY,
Settings.builder().put(XPackSettings.SECURITY_ENABLED.getKey(), true).build()));
licenseState.update(GOLD, true);
licenseState.update(GOLD, true, null);
assertThat(licenseState.isAuthAllowed(), is(true));
assertThat(licenseState.isIpFilteringAllowed(), is(true));
@ -172,7 +174,7 @@ public class XPackLicenseStateTests extends ESTestCase {
public void testSecurityGoldExpired() {
XPackLicenseState licenseState = new XPackLicenseState(randomFrom(Settings.EMPTY,
Settings.builder().put(XPackSettings.SECURITY_ENABLED.getKey(), true).build()));
licenseState.update(GOLD, false);
licenseState.update(GOLD, false, null);
assertThat(licenseState.isAuthAllowed(), is(true));
assertThat(licenseState.isIpFilteringAllowed(), is(true));
@ -186,7 +188,7 @@ public class XPackLicenseStateTests extends ESTestCase {
public void testSecurityPlatinum() {
XPackLicenseState licenseState = new XPackLicenseState(randomFrom(Settings.EMPTY,
Settings.builder().put(XPackSettings.SECURITY_ENABLED.getKey(), true).build()));
licenseState.update(PLATINUM, true);
licenseState.update(PLATINUM, true, null);
assertThat(licenseState.isAuthAllowed(), is(true));
assertThat(licenseState.isIpFilteringAllowed(), is(true));
@ -200,7 +202,7 @@ public class XPackLicenseStateTests extends ESTestCase {
public void testSecurityPlatinumExpired() {
XPackLicenseState licenseState = new XPackLicenseState(randomFrom(Settings.EMPTY,
Settings.builder().put(XPackSettings.SECURITY_ENABLED.getKey(), true).build()));
licenseState.update(PLATINUM, false);
licenseState.update(PLATINUM, false, null);
assertThat(licenseState.isAuthAllowed(), is(true));
assertThat(licenseState.isIpFilteringAllowed(), is(true));
@ -211,6 +213,34 @@ public class XPackLicenseStateTests extends ESTestCase {
assertThat(licenseState.isCustomRoleProvidersAllowed(), is(false));
}
public void testNewTrialDefaultsSecurityOff() {
XPackLicenseState licenseState = new XPackLicenseState(Settings.EMPTY);
licenseState.update(TRIAL, true, VersionUtils.randomVersionBetween(random(), Version.V_6_3_0, Version.CURRENT));
assertThat(licenseState.isSecurityEnabled(), is(false));
assertThat(licenseState.isAuthAllowed(), is(true));
assertThat(licenseState.isIpFilteringAllowed(), is(true));
assertThat(licenseState.isAuditingAllowed(), is(true));
assertThat(licenseState.isStatsAndHealthAllowed(), is(true));
assertThat(licenseState.isDocumentAndFieldLevelSecurityAllowed(), is(true));
assertThat(licenseState.allowedRealmType(), is(XPackLicenseState.AllowedRealmType.ALL));
assertThat(licenseState.isCustomRoleProvidersAllowed(), is(true));
}
public void testOldTrialDefaultsSecurityOn() {
XPackLicenseState licenseState = new XPackLicenseState(Settings.EMPTY);
licenseState.update(TRIAL, true, rarely() ? null : VersionUtils.randomVersionBetween(random(), Version.V_5_6_0, Version.V_6_2_4));
assertThat(licenseState.isSecurityEnabled(), is(true));
assertThat(licenseState.isAuthAllowed(), is(true));
assertThat(licenseState.isIpFilteringAllowed(), is(true));
assertThat(licenseState.isAuditingAllowed(), is(true));
assertThat(licenseState.isStatsAndHealthAllowed(), is(true));
assertThat(licenseState.isDocumentAndFieldLevelSecurityAllowed(), is(true));
assertThat(licenseState.allowedRealmType(), is(XPackLicenseState.AllowedRealmType.ALL));
assertThat(licenseState.isCustomRoleProvidersAllowed(), is(true));
}
public void testSecurityAckBasicToNotGoldOrStandard() {
OperationMode toMode = randomFrom(OperationMode.values(), mode -> mode != GOLD && mode != STANDARD);
assertAckMesssages(XPackField.SECURITY, BASIC, toMode, 0);
@ -354,7 +384,7 @@ public class XPackLicenseStateTests extends ESTestCase {
public void testSqlBasic() {
XPackLicenseState licenseState = new XPackLicenseState(Settings.EMPTY);
licenseState.update(BASIC, true);
licenseState.update(BASIC, true, null);
assertThat(licenseState.isSqlAllowed(), is(true));
assertThat(licenseState.isJdbcAllowed(), is(false));
@ -362,7 +392,7 @@ public class XPackLicenseStateTests extends ESTestCase {
public void testSqlBasicExpired() {
XPackLicenseState licenseState = new XPackLicenseState(Settings.EMPTY);
licenseState.update(BASIC, false);
licenseState.update(BASIC, false, null);
assertThat(licenseState.isSqlAllowed(), is(false));
assertThat(licenseState.isJdbcAllowed(), is(false));
@ -370,7 +400,7 @@ public class XPackLicenseStateTests extends ESTestCase {
public void testSqlStandard() {
XPackLicenseState licenseState = new XPackLicenseState(Settings.EMPTY);
licenseState.update(STANDARD, true);
licenseState.update(STANDARD, true, null);
assertThat(licenseState.isSqlAllowed(), is(true));
assertThat(licenseState.isJdbcAllowed(), is(false));
@ -378,7 +408,7 @@ public class XPackLicenseStateTests extends ESTestCase {
public void testSqlStandardExpired() {
XPackLicenseState licenseState = new XPackLicenseState(Settings.EMPTY);
licenseState.update(STANDARD, false);
licenseState.update(STANDARD, false, null);
assertThat(licenseState.isSqlAllowed(), is(false));
assertThat(licenseState.isJdbcAllowed(), is(false));
@ -386,7 +416,7 @@ public class XPackLicenseStateTests extends ESTestCase {
public void testSqlGold() {
XPackLicenseState licenseState = new XPackLicenseState(Settings.EMPTY);
licenseState.update(GOLD, true);
licenseState.update(GOLD, true, null);
assertThat(licenseState.isSqlAllowed(), is(true));
assertThat(licenseState.isJdbcAllowed(), is(false));
@ -394,7 +424,7 @@ public class XPackLicenseStateTests extends ESTestCase {
public void testSqlGoldExpired() {
XPackLicenseState licenseState = new XPackLicenseState(Settings.EMPTY);
licenseState.update(GOLD, false);
licenseState.update(GOLD, false, null);
assertThat(licenseState.isSqlAllowed(), is(false));
assertThat(licenseState.isJdbcAllowed(), is(false));
@ -402,7 +432,7 @@ public class XPackLicenseStateTests extends ESTestCase {
public void testSqlPlatinum() {
XPackLicenseState licenseState = new XPackLicenseState(Settings.EMPTY);
licenseState.update(PLATINUM, true);
licenseState.update(PLATINUM, true, null);
assertThat(licenseState.isSqlAllowed(), is(true));
assertThat(licenseState.isJdbcAllowed(), is(true));
@ -410,7 +440,7 @@ public class XPackLicenseStateTests extends ESTestCase {
public void testSqlPlatinumExpired() {
XPackLicenseState licenseState = new XPackLicenseState(Settings.EMPTY);
licenseState.update(PLATINUM, false);
licenseState.update(PLATINUM, false, null);
assertThat(licenseState.isSqlAllowed(), is(false));
assertThat(licenseState.isJdbcAllowed(), is(false));

View File

@ -99,7 +99,7 @@ public class MachineLearningLicensingTests extends BaseMlIntegTestCase {
PutJobAction.Response response = putJobListener.actionGet();
assertNotNull(response);
}
// Pick a license that does not allow machine learning
License.OperationMode mode = randomInvalidLicenseType();
enableLicensing(mode);
@ -151,7 +151,7 @@ public class MachineLearningLicensingTests extends BaseMlIntegTestCase {
PutJobAction.Response putJobResponse = putJobListener.actionGet();
assertNotNull(putJobResponse);
}
// Pick a license that does not allow machine learning
License.OperationMode mode = randomInvalidLicenseType();
enableLicensing(mode);
@ -551,7 +551,7 @@ public class MachineLearningLicensingTests extends BaseMlIntegTestCase {
public static void disableLicensing(License.OperationMode operationMode) {
for (XPackLicenseState licenseState : internalCluster().getInstances(XPackLicenseState.class)) {
licenseState.update(operationMode, false);
licenseState.update(operationMode, false, null);
}
}
@ -561,7 +561,7 @@ public class MachineLearningLicensingTests extends BaseMlIntegTestCase {
public static void enableLicensing(License.OperationMode operationMode) {
for (XPackLicenseState licenseState : internalCluster().getInstances(XPackLicenseState.class)) {
licenseState.update(operationMode, true);
licenseState.update(operationMode, true, null);
}
}
}

View File

@ -307,7 +307,7 @@ public class LicensingTests extends SecurityIntegTestCase {
public static void disableLicensing(License.OperationMode operationMode) {
for (XPackLicenseState licenseState : internalCluster().getInstances(XPackLicenseState.class)) {
licenseState.update(operationMode, false);
licenseState.update(operationMode, false, null);
}
}
@ -317,7 +317,7 @@ public class LicensingTests extends SecurityIntegTestCase {
public static void enableLicensing(License.OperationMode operationMode) {
for (XPackLicenseState licenseState : internalCluster().getInstances(XPackLicenseState.class)) {
licenseState.update(operationMode, true);
licenseState.update(operationMode, true, null);
}
}
}

View File

@ -399,7 +399,8 @@ public class SecurityTests extends ESTestCase {
createComponents(Settings.EMPTY);
Function<String, Predicate<String>> fieldFilter = security.getFieldFilter();
assertNotSame(MapperPlugin.NOOP_FIELD_FILTER, fieldFilter);
licenseState.update(randomFrom(License.OperationMode.BASIC, License.OperationMode.STANDARD, License.OperationMode.GOLD), true);
licenseState.update(
randomFrom(License.OperationMode.BASIC, License.OperationMode.STANDARD, License.OperationMode.GOLD), true, null);
assertNotSame(MapperPlugin.NOOP_FIELD_FILTER, fieldFilter);
assertSame(MapperPlugin.NOOP_FIELD_PREDICATE, fieldFilter.apply(randomAlphaOfLengthBetween(3, 6)));
}

View File

@ -409,7 +409,7 @@ public class CompositeRolesStoreTests extends ESTestCase {
UpdatableLicenseState xPackLicenseState = new UpdatableLicenseState(SECURITY_ENABLED_SETTINGS);
// these licenses don't allow custom role providers
xPackLicenseState.update(randomFrom(OperationMode.BASIC, OperationMode.GOLD, OperationMode.STANDARD), true);
xPackLicenseState.update(randomFrom(OperationMode.BASIC, OperationMode.GOLD, OperationMode.STANDARD), true, null);
CompositeRolesStore compositeRolesStore = new CompositeRolesStore(
Settings.EMPTY, fileRolesStore, nativeRolesStore, reservedRolesStore,
Arrays.asList(inMemoryProvider), new ThreadContext(Settings.EMPTY), xPackLicenseState);
@ -427,7 +427,7 @@ public class CompositeRolesStoreTests extends ESTestCase {
Settings.EMPTY, fileRolesStore, nativeRolesStore, reservedRolesStore,
Arrays.asList(inMemoryProvider), new ThreadContext(Settings.EMPTY), xPackLicenseState);
// these licenses allow custom role providers
xPackLicenseState.update(randomFrom(OperationMode.PLATINUM, OperationMode.TRIAL), true);
xPackLicenseState.update(randomFrom(OperationMode.PLATINUM, OperationMode.TRIAL), true, null);
roleNames = Sets.newHashSet("roleA");
future = new PlainActionFuture<>();
fieldPermissionsCache = new FieldPermissionsCache(Settings.EMPTY);
@ -441,7 +441,7 @@ public class CompositeRolesStoreTests extends ESTestCase {
compositeRolesStore = new CompositeRolesStore(
Settings.EMPTY, fileRolesStore, nativeRolesStore, reservedRolesStore,
Arrays.asList(inMemoryProvider), new ThreadContext(Settings.EMPTY), xPackLicenseState);
xPackLicenseState.update(randomFrom(OperationMode.PLATINUM, OperationMode.TRIAL), false);
xPackLicenseState.update(randomFrom(OperationMode.PLATINUM, OperationMode.TRIAL), false, null);
roleNames = Sets.newHashSet("roleA");
future = new PlainActionFuture<>();
fieldPermissionsCache = new FieldPermissionsCache(Settings.EMPTY);

View File

@ -48,7 +48,7 @@ public class SamlBaseRestHandlerTests extends ESTestCase {
.put(XPackSettings.SECURITY_ENABLED.getKey(), true)
.build();
final TestUtils.UpdatableLicenseState licenseState = new TestUtils.UpdatableLicenseState(settings);
licenseState.update(licenseMode, true);
licenseState.update(licenseMode, true, null);
return new SamlBaseRestHandler(settings, licenseState) {
@ -64,4 +64,4 @@ public class SamlBaseRestHandlerTests extends ESTestCase {
};
}
}
}

View File

@ -85,7 +85,7 @@ public class ADLdapUserSearchSessionFactoryTests extends AbstractActiveDirectory
Settings.Builder builder = Settings.builder()
.put(globalSettings);
settings.keySet().forEach(k -> {
builder.copy("xpack.security.authc.realms.ldap." + k, k, settings);
builder.copy("xpack.security.authc.realms.ad-as-ldap-test." + k, k, settings);
});
Settings fullSettings = builder.build();

View File

@ -12,6 +12,7 @@ import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.common.util.concurrent.UncategorizedExecutionException;
import org.elasticsearch.env.Environment;
import org.elasticsearch.env.TestEnvironment;
import org.elasticsearch.threadpool.TestThreadPool;
import org.elasticsearch.threadpool.ThreadPool;
@ -59,9 +60,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryT
@SuppressWarnings("unchecked")
public void testAdAuth() throws Exception {
RealmConfig config = new RealmConfig("ad-test",
buildAdSettings(AD_LDAP_URL, AD_DOMAIN, false),
globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(Settings.EMPTY));
RealmConfig config = configureRealm("ad-test", buildAdSettings(AD_LDAP_URL, AD_DOMAIN, false));
try (ActiveDirectorySessionFactory sessionFactory = getActiveDirectorySessionFactory(config, sslService, threadPool)) {
String userName = "ironman";
@ -82,11 +81,21 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryT
}
}
private RealmConfig configureRealm(String name, Settings settings) {
final Environment env = TestEnvironment.newEnvironment(globalSettings);
final Settings mergedSettings = Settings.builder()
.put(settings)
.normalizePrefix("xpack.security.authc.realms." + name + ".")
.put(globalSettings)
.build();
this.sslService = new SSLService(mergedSettings, env);
return new RealmConfig(name, settings, globalSettings, env, new ThreadContext(globalSettings));
}
@SuppressWarnings("unchecked")
public void testNetbiosAuth() throws Exception {
final String adUrl = randomFrom(AD_LDAP_URL, AD_LDAP_GC_URL);
RealmConfig config = new RealmConfig("ad-test", buildAdSettings(adUrl, AD_DOMAIN, false), globalSettings,
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
RealmConfig config = configureRealm("ad-test", buildAdSettings(adUrl, AD_DOMAIN, false));
try (ActiveDirectorySessionFactory sessionFactory = getActiveDirectorySessionFactory(config, sslService, threadPool)) {
String userName = "ades\\ironman";
@ -108,8 +117,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryT
}
public void testAdAuthAvengers() throws Exception {
RealmConfig config = new RealmConfig("ad-test", buildAdSettings(AD_LDAP_URL, AD_DOMAIN, false), globalSettings,
TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings));
RealmConfig config = configureRealm("ad-test", buildAdSettings(AD_LDAP_URL, AD_DOMAIN, false));
try (ActiveDirectorySessionFactory sessionFactory = getActiveDirectorySessionFactory(config, sslService, threadPool)) {
String[] users = new String[]{"cap", "hawkeye", "hulk", "ironman", "thor", "blackwidow"};
@ -126,8 +134,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryT
public void testAuthenticate() throws Exception {
Settings settings = buildAdSettings(AD_LDAP_URL, AD_DOMAIN, "CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com",
LdapSearchScope.ONE_LEVEL, false);
RealmConfig config = new RealmConfig("ad-test", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings),
new ThreadContext(globalSettings));
RealmConfig config = configureRealm("ad-test", settings);
try (ActiveDirectorySessionFactory sessionFactory = getActiveDirectorySessionFactory(config, sslService, threadPool)) {
String userName = "hulk";
@ -151,8 +158,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryT
public void testAuthenticateBaseUserSearch() throws Exception {
Settings settings = buildAdSettings(AD_LDAP_URL, AD_DOMAIN, "CN=Bruce Banner, CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com",
LdapSearchScope.BASE, false);
RealmConfig config = new RealmConfig("ad-test", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings),
new ThreadContext(globalSettings));
RealmConfig config = configureRealm("ad-test", settings);
try (ActiveDirectorySessionFactory sessionFactory = getActiveDirectorySessionFactory(config, sslService, threadPool)) {
String userName = "hulk";
@ -180,8 +186,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryT
"CN=Avengers,CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com")
.put(ActiveDirectorySessionFactorySettings.AD_GROUP_SEARCH_SCOPE_SETTING, LdapSearchScope.BASE)
.build();
RealmConfig config = new RealmConfig("ad-test", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings),
new ThreadContext(globalSettings));
RealmConfig config = configureRealm("ad-test", settings);
try (ActiveDirectorySessionFactory sessionFactory = getActiveDirectorySessionFactory(config, sslService, threadPool)) {
String userName = "hulk";
@ -198,8 +203,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryT
public void testAuthenticateWithUserPrincipalName() throws Exception {
Settings settings = buildAdSettings(AD_LDAP_URL, AD_DOMAIN, "CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com",
LdapSearchScope.ONE_LEVEL, false);
RealmConfig config = new RealmConfig("ad-test", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings),
new ThreadContext(globalSettings));
RealmConfig config = configureRealm("ad-test", settings);
try (ActiveDirectorySessionFactory sessionFactory = getActiveDirectorySessionFactory(config, sslService, threadPool)) {
//Login with the UserPrincipalName
@ -220,8 +224,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryT
public void testAuthenticateWithSAMAccountName() throws Exception {
Settings settings = buildAdSettings(AD_LDAP_URL, AD_DOMAIN, "CN=Users,DC=ad,DC=test,DC=elasticsearch,DC=com",
LdapSearchScope.ONE_LEVEL, false);
RealmConfig config = new RealmConfig("ad-test", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings),
new ThreadContext(globalSettings));
RealmConfig config = configureRealm("ad-test", settings);
try (ActiveDirectorySessionFactory sessionFactory = getActiveDirectorySessionFactory(config, sslService, threadPool)) {
//login with sAMAccountName
@ -247,8 +250,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryT
.put(ActiveDirectorySessionFactorySettings.AD_USER_SEARCH_FILTER_SETTING,
"(&(objectclass=user)(userPrincipalName={0}@ad.test.elasticsearch.com))")
.build();
RealmConfig config = new RealmConfig("ad-test", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings),
new ThreadContext(globalSettings));
RealmConfig config = configureRealm("ad-test", settings);
try (ActiveDirectorySessionFactory sessionFactory = getActiveDirectorySessionFactory(config, sslService, threadPool)) {
//Login with the UserPrincipalName
@ -284,8 +286,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryT
.putList("ssl.certificate_authorities", certificatePaths)
.build();
}
RealmConfig config = new RealmConfig("ad-as-ldap-test", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings),
new ThreadContext(globalSettings));
RealmConfig config = configureRealm("ad-as-ldap-test", settings);
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService, threadPool);
String user = "Bruce Banner";
@ -348,8 +349,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryT
.putList("ssl.certificate_authorities", certificatePaths)
.build();
}
RealmConfig config = new RealmConfig("ad-as-ldap-test", settings, globalSettings, TestEnvironment.newEnvironment(globalSettings),
new ThreadContext(globalSettings));
RealmConfig config = configureRealm("ad-as-ldap-test", settings);
LdapSessionFactory sessionFactory = new LdapSessionFactory(config, sslService, threadPool);
String user = "Bruce Banner";
@ -366,9 +366,7 @@ public class ActiveDirectorySessionFactoryTests extends AbstractActiveDirectoryT
}
public void testADLookup() throws Exception {
RealmConfig config = new RealmConfig("ad-test",
buildAdSettings(AD_LDAP_URL, AD_DOMAIN, false, true),
globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(Settings.EMPTY));
RealmConfig config = configureRealm("ad-test", buildAdSettings(AD_LDAP_URL, AD_DOMAIN, false, true));
try (ActiveDirectorySessionFactory sessionFactory = getActiveDirectorySessionFactory(config, sslService, threadPool)) {
List<String> users = randomSubsetOf(Arrays.asList("cap", "hawkeye", "hulk", "ironman", "thor", "blackwidow",