Skip to content

Whitelist geo methods for Painless #40180

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,20 @@
import org.elasticsearch.plugins.ScriptPlugin;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestHandler;
import org.elasticsearch.script.AggregationScript;
import org.elasticsearch.script.BucketAggregationScript;
import org.elasticsearch.script.BucketAggregationSelectorScript;
import org.elasticsearch.script.FieldScript;
import org.elasticsearch.script.FilterScript;
import org.elasticsearch.script.IngestConditionalScript;
import org.elasticsearch.script.IngestScript;
import org.elasticsearch.script.NumberSortScript;
import org.elasticsearch.script.ScoreScript;
import org.elasticsearch.script.ScriptContext;
import org.elasticsearch.script.ScriptEngine;
import org.elasticsearch.script.ScriptedMetricAggContexts;
import org.elasticsearch.script.StringSortScript;
import org.elasticsearch.script.UpdateScript;
import org.elasticsearch.search.aggregations.pipeline.MovingFunctionScript;

import java.util.ArrayList;
Expand Down Expand Up @@ -74,13 +85,34 @@ public final class PainlessPlugin extends Plugin implements ScriptPlugin, Extens
// Moving Function Pipeline Agg
List<Whitelist> movFn = new ArrayList<>(Whitelist.BASE_WHITELISTS);
movFn.add(WhitelistLoader.loadFromResourceFiles(Whitelist.class, "org.elasticsearch.aggs.movfn.txt"));
movFn.add(WhitelistLoader.loadFromResourceFiles(Whitelist.class, "org.elasticsearch.geo.txt"));
map.put(MovingFunctionScript.CONTEXT, movFn);

// Functions used for scoring docs
List<Whitelist> scoreFn = new ArrayList<>(Whitelist.BASE_WHITELISTS);
scoreFn.add(WhitelistLoader.loadFromResourceFiles(Whitelist.class, "org.elasticsearch.score.txt"));
scoreFn.add(WhitelistLoader.loadFromResourceFiles(Whitelist.class, "org.elasticsearch.geo.txt"));
map.put(ScoreScript.CONTEXT, scoreFn);

// All other contexts that need geo classes, methods, and fields
List<Whitelist> geoWhitelists = new ArrayList<>(Whitelist.BASE_WHITELISTS);
geoWhitelists.add(WhitelistLoader.loadFromResourceFiles(Whitelist.class, "org.elasticsearch.geo.txt"));
map.put(PainlessExecuteAction.PainlessTestScript.CONTEXT, geoWhitelists);
map.put(AggregationScript.CONTEXT, geoWhitelists);
map.put(BucketAggregationSelectorScript.CONTEXT, geoWhitelists);
map.put(BucketAggregationScript.CONTEXT, geoWhitelists);
map.put(ScriptedMetricAggContexts.InitScript.CONTEXT, geoWhitelists);
map.put(ScriptedMetricAggContexts.MapScript.CONTEXT, geoWhitelists);
map.put(ScriptedMetricAggContexts.CombineScript.CONTEXT, geoWhitelists);
map.put(ScriptedMetricAggContexts.ReduceScript.CONTEXT, geoWhitelists);
map.put(FieldScript.CONTEXT, geoWhitelists);
map.put(FilterScript.CONTEXT, geoWhitelists);
map.put(IngestConditionalScript.CONTEXT, geoWhitelists);
map.put(IngestScript.CONTEXT, geoWhitelists);
map.put(NumberSortScript.CONTEXT, geoWhitelists);
map.put(StringSortScript.CONTEXT, geoWhitelists);
map.put(UpdateScript.CONTEXT, geoWhitelists);

whitelists = map;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -679,13 +679,15 @@ public void addPainlessField(Class<?> targetClass, String fieldName, Class<?> ty
"with the same name and different type parameters");
}
} else {
MethodHandle methodHandleSetter;
MethodHandle methodHandleSetter = null;

try {
methodHandleSetter = MethodHandles.publicLookup().unreflectSetter(javaField);
} catch (IllegalAccessException iae) {
throw new IllegalArgumentException(
"setter method handle not found for field [[" + targetCanonicalClassName + "], [" + fieldName + "]]");
if (Modifier.isFinal(javaField.getModifiers()) == false) {
try {
methodHandleSetter = MethodHandles.publicLookup().unreflectSetter(javaField);
} catch (IllegalAccessException iae) {
throw new IllegalArgumentException(
"setter method handle not found for field [[" + targetCanonicalClassName + "], [" + fieldName + "]]");
}
}

PainlessField existingPainlessField = painlessClassBuilder.fields.get(painlessFieldKey);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#
# 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.
#

class org.elasticsearch.common.unit.DistanceUnit {
DistanceUnit INCH
DistanceUnit YARD
DistanceUnit FEET
DistanceUnit KILOMETERS
DistanceUnit NAUTICALMILES
DistanceUnit MILLIMETERS
DistanceUnit CENTIMETERS
DistanceUnit MILES
DistanceUnit METERS
double convert(double, DistanceUnit, DistanceUnit)
double parse(String, DistanceUnit, DistanceUnit)
DistanceUnit parseUnit(String, DistanceUnit)
DistanceUnit fromString(String)
double getEarthCircumference()
double getEarthRadius()
double getDistancePerDegree()
double toMeters(double)
double fromMeters(double)
double convert(double, DistanceUnit)
double parse(String, DistanceUnit)
String toString(double)
}

class org.elasticsearch.common.unit.DistanceUnit$Distance {
double value
DistanceUnit unit
DistanceUnit.Distance parseDistance(String)
(double, DistanceUnit)
DistanceUnit.Distance convert(DistanceUnit)
}

class org.elasticsearch.common.geo.GeoPoint {
GeoPoint parseFromLatLon(String)
GeoPoint fromGeohash(String)
()
(String)
(double, double)
GeoPoint reset(double, double)
GeoPoint resetLat(double)
GeoPoint resetLon(double)
GeoPoint resetFromString(String)
GeoPoint resetFromString(String, boolean)
GeoPoint resetFromCoordinates(String, boolean)
GeoPoint resetFromIndexHash(long)
GeoPoint resetFromGeoHash(String)
double getLat()
double getLon()
String getGeohash()
}

class org.elasticsearch.common.geo.GeoUtils {
double MAX_LAT
double MIN_LAT
double MAX_LON
double MIN_LON
String LATITUDE
String LONGITUDE
String GEOHASH
double EARTH_SEMI_MAJOR_AXIS
double EARTH_SEMI_MINOR_AXIS
double EARTH_MEAN_RADIUS
double EARTH_AXIS_RATIO
double EARTH_EQUATOR
double EARTH_POLAR_DISTANCE
double TOLERANCE
boolean isValidLatitude(double)
boolean isValidLongitude(double)
double geoHashCellWidth(int)
double quadTreeCellWidth(int)
double geoHashCellHeight(int)
double quadTreeCellHeight(int)
double geoHashCellSize(int)
double quadTreeCellSize(int)
int quadTreeLevelsForPrecision(double)
int geoHashLevelsForPrecision(double)
double normalizeLon(double)
double normalizeLat(double)
void normalizePoint(GeoPoint)
void normalizePoint(GeoPoint, boolean, boolean)
double maxRadialDistanceMeters(double, double)
double arcDistance(double, double, double, double)
double planeDistance(double, double, double, double)
boolean rectangleContainsPoint(org.apache.lucene.geo.Rectangle, double, double)
}

class org.apache.lucene.geo.Rectangle no_import {
double minLat
double maxLat
double minLon
double maxLon
(double, double, double, double)
boolean crossesDateline()
boolean containsPoint(double, double, double, double, double, double)
org.apache.lucene.geo.Rectangle fromPointDistance(double, double, double)
double axisLat(double, double)
}

class org.elasticsearch.common.geo.GeoDistance {
GeoDistance PLANE
GeoDistance ARC
GeoDistance fromString(String)
double calculate(double, double, double, double, DistanceUnit)
}
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,13 @@ public void testStatic() {
assertEquals(10, exec("staticAddIntsTest(7, 3)"));
assertEquals(15.5f, exec("staticAddFloatsTest(6.5f, 9.0f)"));
}

public void testReadOnlyField() {
assertEquals(10.0, exec("DistanceUnit.Distance d = new DistanceUnit.Distance(10.0, DistanceUnit.METERS); d.value"));
expectScriptThrows(IllegalArgumentException.class,
() -> exec("DistanceUnit.Distance d = new DistanceUnit.Distance(10.0, DistanceUnit.METERS); d.value = 5.0"));
assertEquals(10.0, exec("def d = new DistanceUnit.Distance(10.0, DistanceUnit.METERS); d.value"));
expectScriptThrows(IllegalArgumentException.class,
() -> exec("def d = new DistanceUnit.Distance(10.0, DistanceUnit.METERS); d.value = 5.0"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@
import junit.framework.AssertionFailedError;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.painless.antlr.Walker;
import org.elasticsearch.painless.lookup.PainlessLookup;
import org.elasticsearch.painless.lookup.PainlessLookupBuilder;
import org.elasticsearch.painless.spi.Whitelist;
import org.elasticsearch.painless.spi.WhitelistLoader;
import org.elasticsearch.script.ScriptContext;
import org.elasticsearch.script.ScriptException;
import org.elasticsearch.test.ESTestCase;
import org.junit.Before;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
Expand All @@ -45,8 +45,6 @@
* Typically just asserts the output of {@code exec()}
*/
public abstract class ScriptTestCase extends ESTestCase {
private static final PainlessLookup PAINLESS_LOOKUP = PainlessLookupBuilder.buildFromWhitelists(Whitelist.BASE_WHITELISTS);

protected PainlessScriptEngine scriptEngine;

@Before
Expand All @@ -66,7 +64,9 @@ protected Settings scriptEngineSettings() {
*/
protected Map<ScriptContext<?>, List<Whitelist>> scriptContexts() {
Map<ScriptContext<?>, List<Whitelist>> contexts = new HashMap<>();
contexts.put(PainlessTestScript.CONTEXT, Whitelist.BASE_WHITELISTS);
List<Whitelist> whitelists = new ArrayList<>(Whitelist.BASE_WHITELISTS);
whitelists.add(WhitelistLoader.loadFromResourceFiles(Whitelist.class, "org.elasticsearch.geo.txt"));
contexts.put(PainlessTestScript.CONTEXT, whitelists);
return contexts;
}

Expand All @@ -91,12 +91,13 @@ public Object exec(String script, Map<String, Object> vars, boolean picky) {
public Object exec(String script, Map<String, Object> vars, Map<String,String> compileParams, boolean picky) {
// test for ambiguity errors before running the actual script if picky is true
if (picky) {
ScriptClassInfo scriptClassInfo = new ScriptClassInfo(PAINLESS_LOOKUP, PainlessTestScript.class);
ScriptClassInfo scriptClassInfo =
new ScriptClassInfo(scriptEngine.getContextsToLookups().get(PainlessTestScript.CONTEXT), PainlessTestScript.class);
CompilerSettings pickySettings = new CompilerSettings();
pickySettings.setPicky(true);
pickySettings.setRegexesEnabled(CompilerSettings.REGEX_ENABLED.get(scriptEngineSettings()));
Walker.buildPainlessTree(
scriptClassInfo, new MainMethodReserved(), getTestName(), script, pickySettings, PAINLESS_LOOKUP, null);
Walker.buildPainlessTree(scriptClassInfo, new MainMethodReserved(), getTestName(), script,
pickySettings, scriptEngine.getContextsToLookups().get(PainlessTestScript.CONTEXT), null);
}
// test actual script execution
PainlessTestScript.Factory factory = scriptEngine.compile(null, script, PainlessTestScript.CONTEXT, compileParams);
Expand Down