From ba5b5832039b591cfb00b8587966bd1f4ac28c40 Mon Sep 17 00:00:00 2001 From: Lee Hinman Date: Mon, 22 Jan 2018 11:55:54 -0700 Subject: [PATCH 01/14] Notify affixMap settings when any under the registered prefix matches (#28317) * Notify affixMap settings when any under the registered prefix matches Previously if an affixMap setting was registered, and then a completely different setting was applied, the affixMap update consumer would be notified with an empty map. This caused settings that were previously set to be unset in local state in a consumer that assumed it would only be called when the affixMap setting was changed. This commit changes the behavior so if a prefix `foo.` is registered, any setting under the prefix will have the update consumer notified if there are changes starting with `foo.`. Resolves #28316 * Add unit test * Address feedback --- .../common/settings/Setting.java | 4 +- .../allocation/FilteringAllocationIT.java | 58 +++++++++++++++++++ .../common/settings/ScopedSettingsTests.java | 44 ++++++++++++++ 3 files changed, 104 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/common/settings/Setting.java b/server/src/main/java/org/elasticsearch/common/settings/Setting.java index bc22dbb63eb..fd91a8a7601 100644 --- a/server/src/main/java/org/elasticsearch/common/settings/Setting.java +++ b/server/src/main/java/org/elasticsearch/common/settings/Setting.java @@ -597,7 +597,7 @@ public class Setting implements ToXContentObject { @Override public boolean hasChanged(Settings current, Settings previous) { - return Stream.concat(matchStream(current), matchStream(previous)).findAny().isPresent(); + return current.filter(k -> match(k)).equals(previous.filter(k -> match(k))) == false; } @Override @@ -612,7 +612,7 @@ public class Setting implements ToXContentObject { if (updater.hasChanged(current, previous)) { // only the ones that have changed otherwise we might get too many updates // the hasChanged above checks only if there are any changes - T value = updater.getValue(current, previous); + T value = updater.getValue(current, previous); if ((omitDefaults && value.equals(concreteSetting.getDefault(current))) == false) { result.put(namespace, value); } diff --git a/server/src/test/java/org/elasticsearch/cluster/allocation/FilteringAllocationIT.java b/server/src/test/java/org/elasticsearch/cluster/allocation/FilteringAllocationIT.java index 91a41495a46..d887387d43f 100644 --- a/server/src/test/java/org/elasticsearch/cluster/allocation/FilteringAllocationIT.java +++ b/server/src/test/java/org/elasticsearch/cluster/allocation/FilteringAllocationIT.java @@ -21,11 +21,14 @@ package org.elasticsearch.cluster.allocation; import org.apache.logging.log4j.Logger; import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.health.ClusterHealthStatus; import org.elasticsearch.cluster.routing.IndexRoutingTable; import org.elasticsearch.cluster.routing.IndexShardRoutingTable; import org.elasticsearch.cluster.routing.ShardRouting; +import org.elasticsearch.cluster.routing.ShardRoutingState; import org.elasticsearch.cluster.routing.allocation.decider.FilterAllocationDecider; import org.elasticsearch.cluster.routing.allocation.decider.ThrottlingAllocationDecider; +import org.elasticsearch.common.Strings; import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Settings; @@ -34,7 +37,9 @@ import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.ESIntegTestCase.ClusterScope; import org.elasticsearch.test.ESIntegTestCase.Scope; +import java.util.HashSet; import java.util.List; +import java.util.Set; import static org.hamcrest.Matchers.equalTo; @@ -156,5 +161,58 @@ public class FilteringAllocationIT extends ESIntegTestCase { .execute().actionGet()); assertEquals("invalid IP address [192.168.1.1.] for [" + filterSetting.getKey() + ipKey + "]", e.getMessage()); } + + public void testTransientSettingsStillApplied() throws Exception { + List nodes = internalCluster().startNodes(6); + Set excludeNodes = new HashSet<>(nodes.subList(0, 3)); + Set includeNodes = new HashSet<>(nodes.subList(3, 6)); + logger.info("--> exclude: [{}], include: [{}]", + Strings.collectionToCommaDelimitedString(excludeNodes), + Strings.collectionToCommaDelimitedString(includeNodes)); + ensureStableCluster(6); + client().admin().indices().prepareCreate("test").get(); + ensureGreen("test"); + + Settings exclude = Settings.builder().put("cluster.routing.allocation.exclude._name", + Strings.collectionToCommaDelimitedString(excludeNodes)).build(); + + logger.info("--> updating settings"); + client().admin().cluster().prepareUpdateSettings().setTransientSettings(exclude).get(); + + logger.info("--> waiting for relocation"); + waitForRelocation(ClusterHealthStatus.GREEN); + + ClusterState state = client().admin().cluster().prepareState().get().getState(); + + for (ShardRouting shard : state.getRoutingTable().shardsWithState(ShardRoutingState.STARTED)) { + String node = state.getRoutingNodes().node(shard.currentNodeId()).node().getName(); + logger.info("--> shard on {} - {}", node, shard); + assertTrue("shard on " + node + " but should only be on the include node list: " + + Strings.collectionToCommaDelimitedString(includeNodes), + includeNodes.contains(node)); + } + + Settings other = Settings.builder().put("cluster.info.update.interval", "45s").build(); + + logger.info("--> updating settings with random persistent setting"); + client().admin().cluster().prepareUpdateSettings() + .setPersistentSettings(other).setTransientSettings(exclude).get(); + + logger.info("--> waiting for relocation"); + waitForRelocation(ClusterHealthStatus.GREEN); + + state = client().admin().cluster().prepareState().get().getState(); + + // The transient settings still exist in the state + assertThat(state.metaData().transientSettings(), equalTo(exclude)); + + for (ShardRouting shard : state.getRoutingTable().shardsWithState(ShardRoutingState.STARTED)) { + String node = state.getRoutingNodes().node(shard.currentNodeId()).node().getName(); + logger.info("--> shard on {} - {}", node, shard); + assertTrue("shard on " + node + " but should only be on the include node list: " + + Strings.collectionToCommaDelimitedString(includeNodes), + includeNodes.contains(node)); + } + } } diff --git a/server/src/test/java/org/elasticsearch/common/settings/ScopedSettingsTests.java b/server/src/test/java/org/elasticsearch/common/settings/ScopedSettingsTests.java index 29c7a2b1614..0f4d0cf6634 100644 --- a/server/src/test/java/org/elasticsearch/common/settings/ScopedSettingsTests.java +++ b/server/src/test/java/org/elasticsearch/common/settings/ScopedSettingsTests.java @@ -261,6 +261,21 @@ public class ScopedSettingsTests extends ESTestCase { assertEquals(2, listResults.size()); assertEquals(2, intResults.size()); + service.applySettings(Settings.builder() + .put("foo.test.bar", 2) + .put("foo.test_1.bar", 7) + .putList("foo.test_list.list", "16", "17") + .putList("foo.test_list_1.list", "18", "19", "20") + .build()); + + assertEquals(2, intResults.get("test").intValue()); + assertEquals(7, intResults.get("test_1").intValue()); + assertEquals(Arrays.asList(16, 17), listResults.get("test_list")); + assertEquals(Arrays.asList(18, 19, 20), listResults.get("test_list_1")); + assertEquals(2, listResults.size()); + assertEquals(2, intResults.size()); + + listResults.clear(); intResults.clear(); @@ -286,6 +301,35 @@ public class ScopedSettingsTests extends ESTestCase { } + public void testAffixMapConsumerNotCalledWithNull() { + Setting.AffixSetting prefixSetting = Setting.prefixKeySetting("eggplant.", + (k) -> Setting.intSetting(k, 1, Property.Dynamic, Property.NodeScope)); + Setting.AffixSetting otherSetting = Setting.prefixKeySetting("other.", + (k) -> Setting.intSetting(k, 1, Property.Dynamic, Property.NodeScope)); + AbstractScopedSettings service = new ClusterSettings(Settings.EMPTY,new HashSet<>(Arrays.asList(prefixSetting, otherSetting))); + Map affixResults = new HashMap<>(); + + Consumer> consumer = (map) -> { + logger.info("--> consuming settings {}", map); + affixResults.clear(); + affixResults.putAll(map); + }; + service.addAffixMapUpdateConsumer(prefixSetting, consumer, (s, k) -> {}, randomBoolean()); + assertEquals(0, affixResults.size()); + service.applySettings(Settings.builder() + .put("eggplant._name", 2) + .build()); + assertThat(affixResults.size(), equalTo(1)); + assertThat(affixResults.get("_name"), equalTo(2)); + + service.applySettings(Settings.builder() + .put("eggplant._name", 2) + .put("other.thing", 3) + .build()); + + assertThat(affixResults.get("_name"), equalTo(2)); + } + public void testApply() { Setting testSetting = Setting.intSetting("foo.bar", 1, Property.Dynamic, Property.NodeScope); Setting testSetting2 = Setting.intSetting("foo.bar.baz", 1, Property.Dynamic, Property.NodeScope); From ef5c0418198215c1f932990c3f3db1c05087dc9a Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Mon, 22 Jan 2018 13:01:13 -0800 Subject: [PATCH 02/14] Painless: Replace Painless Type with Java Class during Casts (#27847) This is the first step in a series to replace Painless Type with Java Class for any casting done during compilation. There should be no behavioural change. --- .../painless/AnalyzerCaster.java | 835 +++++++++--------- .../elasticsearch/painless/Definition.java | 119 ++- .../elasticsearch/painless/MethodWriter.java | 91 +- .../elasticsearch/painless/node/ECast.java | 3 +- .../painless/AnalyzerCasterTests.java | 8 +- .../painless/node/NodeToStringTests.java | 4 +- 6 files changed, 597 insertions(+), 463 deletions(-) diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/AnalyzerCaster.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/AnalyzerCaster.java index 89f358d17e0..7bae2c7fcad 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/AnalyzerCaster.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/AnalyzerCaster.java @@ -21,6 +21,7 @@ package org.elasticsearch.painless; import org.elasticsearch.painless.Definition.Cast; import org.elasticsearch.painless.Definition.Type; +import org.elasticsearch.painless.Definition.def; import java.util.Objects; @@ -36,447 +37,459 @@ public final class AnalyzerCaster { this.definition = definition; } - public Cast getLegalCast(Location location, Type actual, Type expected, boolean explicit, boolean internal) { - Objects.requireNonNull(actual); - Objects.requireNonNull(expected); + public Cast getLegalCast(Location location, Type actualType, Type expectedType, boolean explicit, boolean internal) { + Objects.requireNonNull(actualType); + Objects.requireNonNull(expectedType); - if (actual.equals(expected)) { + Class actual = actualType.clazz; + Class expected = expectedType.clazz; + + if (actualType.dynamic) { + actual = Definition.ObjectClassTodefClass(actual); + } + + if (expectedType.dynamic) { + expected = Definition.ObjectClassTodefClass(expected); + } + + if (actual == expected) { return null; } - if (actual.dynamic) { - if (expected.clazz == boolean.class) { - return Cast.unboxTo(definition.DefType, definition.BooleanType, explicit, definition.booleanType); - } else if (expected.clazz == byte.class) { - return Cast.unboxTo(definition.DefType, definition.ByteType, explicit, definition.byteType); - } else if (expected.clazz == short.class) { - return Cast.unboxTo(definition.DefType, definition.ShortType, explicit, definition.shortType); - } else if (expected.clazz == char.class) { - return Cast.unboxTo(definition.DefType, definition.CharacterType, explicit, definition.charType); - } else if (expected.clazz == int.class) { - return Cast.unboxTo(definition.DefType, definition.IntegerType, explicit, definition.intType); - } else if (expected.clazz == long.class) { - return Cast.unboxTo(definition.DefType, definition.LongType, explicit, definition.longType); - } else if (expected.clazz == float.class) { - return Cast.unboxTo(definition.DefType, definition.FloatType, explicit, definition.floatType); - } else if (expected.clazz == double.class) { - return Cast.unboxTo(definition.DefType, definition.DoubleType, explicit, definition.doubleType); + if (actual == def.class) { + if (expected == boolean.class) { + return Cast.unboxTo(def.class, Boolean.class, explicit, boolean.class); + } else if (expected == byte.class) { + return Cast.unboxTo(def.class, Byte.class, explicit, byte.class); + } else if (expected == short.class) { + return Cast.unboxTo(def.class, Short.class, explicit, short.class); + } else if (expected == char.class) { + return Cast.unboxTo(def.class, Character.class, explicit, char.class); + } else if (expected == int.class) { + return Cast.unboxTo(def.class, Integer.class, explicit, int.class); + } else if (expected == long.class) { + return Cast.unboxTo(def.class, Long.class, explicit, long.class); + } else if (expected == float.class) { + return Cast.unboxTo(def.class, Float.class, explicit, float.class); + } else if (expected == double.class) { + return Cast.unboxTo(def.class, Double.class, explicit, double.class); } - } else if (actual.clazz == Object.class) { - if (expected.clazz == byte.class && explicit && internal) { - return Cast.unboxTo(definition.ObjectType, definition.ByteType, true, definition.byteType); - } else if (expected.clazz == short.class && explicit && internal) { - return Cast.unboxTo(definition.ObjectType, definition.ShortType, true, definition.shortType); - } else if (expected.clazz == char.class && explicit && internal) { - return Cast.unboxTo(definition.ObjectType, definition.CharacterType, true, definition.charType); - } else if (expected.clazz == int.class && explicit && internal) { - return Cast.unboxTo(definition.ObjectType, definition.IntegerType, true, definition.intType); - } else if (expected.clazz == long.class && explicit && internal) { - return Cast.unboxTo(definition.ObjectType, definition.LongType, true, definition.longType); - } else if (expected.clazz == float.class && explicit && internal) { - return Cast.unboxTo(definition.ObjectType, definition.FloatType, true, definition.floatType); - } else if (expected.clazz == double.class && explicit && internal) { - return Cast.unboxTo(definition.ObjectType, definition.DoubleType, true, definition.doubleType); + } else if (actual == Object.class) { + if (expected == byte.class && explicit && internal) { + return Cast.unboxTo(Object.class, Byte.class, true, byte.class); + } else if (expected == short.class && explicit && internal) { + return Cast.unboxTo(Object.class, Short.class, true, short.class); + } else if (expected == char.class && explicit && internal) { + return Cast.unboxTo(Object.class, Character.class, true, char.class); + } else if (expected == int.class && explicit && internal) { + return Cast.unboxTo(Object.class, Integer.class, true, int.class); + } else if (expected == long.class && explicit && internal) { + return Cast.unboxTo(Object.class, Long.class, true, long.class); + } else if (expected == float.class && explicit && internal) { + return Cast.unboxTo(Object.class, Float.class, true, float.class); + } else if (expected == double.class && explicit && internal) { + return Cast.unboxTo(Object.class, Double.class, true, double.class); } - } else if (actual.clazz == Number.class) { - if (expected.clazz == byte.class && explicit && internal) { - return Cast.unboxTo(definition.NumberType, definition.ByteType, true, definition.byteType); - } else if (expected.clazz == short.class && explicit && internal) { - return Cast.unboxTo(definition.NumberType, definition.ShortType, true, definition.shortType); - } else if (expected.clazz == char.class && explicit && internal) { - return Cast.unboxTo(definition.NumberType, definition.CharacterType, true, definition.charType); - } else if (expected.clazz == int.class && explicit && internal) { - return Cast.unboxTo(definition.NumberType, definition.IntegerType, true, definition.intType); - } else if (expected.clazz == long.class && explicit && internal) { - return Cast.unboxTo(definition.NumberType, definition.LongType, true, definition.longType); - } else if (expected.clazz == float.class && explicit && internal) { - return Cast.unboxTo(definition.NumberType, definition.FloatType, true, definition.floatType); - } else if (expected.clazz == double.class && explicit && internal) { - return Cast.unboxTo(definition.NumberType, definition.DoubleType, true, definition.doubleType); + } else if (actual == Number.class) { + if (expected == byte.class && explicit && internal) { + return Cast.unboxTo(Number.class, Byte.class, true, byte.class); + } else if (expected == short.class && explicit && internal) { + return Cast.unboxTo(Number.class, Short.class, true, short.class); + } else if (expected == char.class && explicit && internal) { + return Cast.unboxTo(Number.class, Character.class, true, char.class); + } else if (expected == int.class && explicit && internal) { + return Cast.unboxTo(Number.class, Integer.class, true, int.class); + } else if (expected == long.class && explicit && internal) { + return Cast.unboxTo(Number.class, Long.class, true, long.class); + } else if (expected == float.class && explicit && internal) { + return Cast.unboxTo(Number.class, Float.class, true, float.class); + } else if (expected == double.class && explicit && internal) { + return Cast.unboxTo(Number.class, Double.class, true, double.class); } - } else if (actual.clazz == String.class) { - if (expected.clazz == char.class && explicit) { - return Cast.standard(definition.StringType, definition.charType, true); + } else if (actual == String.class) { + if (expected == char.class && explicit) { + return Cast.standard(String.class, char.class, true); } - } else if (actual.clazz == boolean.class) { - if (expected.dynamic) { - return Cast.boxFrom(definition.BooleanType, definition.DefType, explicit, definition.booleanType); - } else if (expected.clazz == Object.class && internal) { - return Cast.boxFrom(definition.BooleanType, definition.ObjectType, explicit, definition.booleanType); - } else if (expected.clazz == Boolean.class && internal) { - return Cast.boxTo(definition.booleanType, definition.booleanType, explicit, definition.booleanType); + } else if (actual == boolean.class) { + if (expected == def.class) { + return Cast.boxFrom(Boolean.class, def.class, explicit, boolean.class); + } else if (expected == Object.class && internal) { + return Cast.boxFrom(Boolean.class, Object.class, explicit, boolean.class); + } else if (expected == Boolean.class && internal) { + return Cast.boxTo(boolean.class, boolean.class, explicit, boolean.class); } - } else if (actual.clazz == byte.class) { - if (expected.dynamic) { - return Cast.boxFrom(definition.ByteType, definition.DefType, explicit, definition.byteType); - } else if (expected.clazz == Object.class && internal) { - return Cast.boxFrom(definition.ByteType, definition.ObjectType, explicit, definition.byteType); - } else if (expected.clazz == Number.class && internal) { - return Cast.boxFrom(definition.ByteType, definition.NumberType, explicit, definition.byteType); - } else if (expected.clazz == short.class) { - return Cast.standard(definition.byteType, definition.shortType, explicit); - } else if (expected.clazz == char.class && explicit) { - return Cast.standard(definition.byteType, definition.charType, true); - } else if (expected.clazz == int.class) { - return Cast.standard(definition.byteType, definition.intType, explicit); - } else if (expected.clazz == long.class) { - return Cast.standard(definition.byteType, definition.longType, explicit); - } else if (expected.clazz == float.class) { - return Cast.standard(definition.byteType, definition.floatType, explicit); - } else if (expected.clazz == double.class) { - return Cast.standard(definition.byteType, definition.doubleType, explicit); - } else if (expected.clazz == Byte.class && internal) { - return Cast.boxTo(definition.byteType, definition.byteType, explicit, definition.byteType); - } else if (expected.clazz == Short.class && internal) { - return Cast.boxTo(definition.byteType, definition.shortType, explicit, definition.shortType); - } else if (expected.clazz == Character.class && explicit && internal) { - return Cast.boxTo(definition.byteType, definition.charType, true, definition.charType); - } else if (expected.clazz == Integer.class && internal) { - return Cast.boxTo(definition.byteType, definition.intType, explicit, definition.intType); - } else if (expected.clazz == Long.class && internal) { - return Cast.boxTo(definition.byteType, definition.longType, explicit, definition.longType); - } else if (expected.clazz == Float.class && internal) { - return Cast.boxTo(definition.byteType, definition.floatType, explicit, definition.floatType); - } else if (expected.clazz == Double.class && internal) { - return Cast.boxTo(definition.byteType, definition.doubleType, explicit, definition.doubleType); + } else if (actual == byte.class) { + if (expected == def.class) { + return Cast.boxFrom(Byte.class, def.class, explicit, byte.class); + } else if (expected == Object.class && internal) { + return Cast.boxFrom(Byte.class, Object.class, explicit, byte.class); + } else if (expected == Number.class && internal) { + return Cast.boxFrom(Byte.class, Number.class, explicit, byte.class); + } else if (expected == short.class) { + return Cast.standard(byte.class, short.class, explicit); + } else if (expected == char.class && explicit) { + return Cast.standard(byte.class, char.class, true); + } else if (expected == int.class) { + return Cast.standard(byte.class, int.class, explicit); + } else if (expected == long.class) { + return Cast.standard(byte.class, long.class, explicit); + } else if (expected == float.class) { + return Cast.standard(byte.class, float.class, explicit); + } else if (expected == double.class) { + return Cast.standard(byte.class, double.class, explicit); + } else if (expected == Byte.class && internal) { + return Cast.boxTo(byte.class, byte.class, explicit, byte.class); + } else if (expected == Short.class && internal) { + return Cast.boxTo(byte.class, short.class, explicit, short.class); + } else if (expected == Character.class && explicit && internal) { + return Cast.boxTo(byte.class, char.class, true, char.class); + } else if (expected == Integer.class && internal) { + return Cast.boxTo(byte.class, int.class, explicit, int.class); + } else if (expected == Long.class && internal) { + return Cast.boxTo(byte.class, long.class, explicit, long.class); + } else if (expected == Float.class && internal) { + return Cast.boxTo(byte.class, float.class, explicit, float.class); + } else if (expected == Double.class && internal) { + return Cast.boxTo(byte.class, double.class, explicit, double.class); } - } else if (actual.clazz == short.class) { - if (expected.dynamic) { - return Cast.boxFrom(definition.ShortType, definition.DefType, explicit, definition.shortType); - } else if (expected.clazz == Object.class && internal) { - return Cast.boxFrom(definition.ShortType, definition.ObjectType, explicit, definition.shortType); - } else if (expected.clazz == Number.class && internal) { - return Cast.boxFrom(definition.ShortType, definition.NumberType, explicit, definition.shortType); - } else if (expected.clazz == byte.class && explicit) { - return Cast.standard(definition.shortType, definition.byteType, true); - } else if (expected.clazz == char.class && explicit) { - return Cast.standard(definition.shortType, definition.charType, true); - } else if (expected.clazz == int.class) { - return Cast.standard(definition.shortType, definition.intType, explicit); - } else if (expected.clazz == long.class) { - return Cast.standard(definition.shortType, definition.longType, explicit); - } else if (expected.clazz == float.class) { - return Cast.standard(definition.shortType, definition.floatType, explicit); - } else if (expected.clazz == double.class) { - return Cast.standard(definition.shortType, definition.doubleType, explicit); - } else if (expected.clazz == Byte.class && explicit && internal) { - return Cast.boxTo(definition.shortType, definition.byteType, true, definition.byteType); - } else if (expected.clazz == Short.class && internal) { - return Cast.boxTo(definition.shortType, definition.shortType, explicit, definition.shortType); - } else if (expected.clazz == Character.class && explicit && internal) { - return Cast.boxTo(definition.shortType, definition.charType, true, definition.charType); - } else if (expected.clazz == Integer.class && internal) { - return Cast.boxTo(definition.shortType, definition.intType, explicit, definition.intType); - } else if (expected.clazz == Long.class && internal) { - return Cast.boxTo(definition.shortType, definition.longType, explicit, definition.longType); - } else if (expected.clazz == Float.class && internal) { - return Cast.boxTo(definition.shortType, definition.floatType, explicit, definition.floatType); - } else if (expected.clazz == Double.class && internal) { - return Cast.boxTo(definition.shortType, definition.doubleType, explicit, definition.doubleType); + } else if (actual == short.class) { + if (expected == def.class) { + return Cast.boxFrom(Short.class, def.class, explicit, short.class); + } else if (expected == Object.class && internal) { + return Cast.boxFrom(Short.class, Object.class, explicit, short.class); + } else if (expected == Number.class && internal) { + return Cast.boxFrom(Short.class, Number.class, explicit, short.class); + } else if (expected == byte.class && explicit) { + return Cast.standard(short.class, byte.class, true); + } else if (expected == char.class && explicit) { + return Cast.standard(short.class, char.class, true); + } else if (expected == int.class) { + return Cast.standard(short.class, int.class, explicit); + } else if (expected == long.class) { + return Cast.standard(short.class, long.class, explicit); + } else if (expected == float.class) { + return Cast.standard(short.class, float.class, explicit); + } else if (expected == double.class) { + return Cast.standard(short.class, double.class, explicit); + } else if (expected == Byte.class && explicit && internal) { + return Cast.boxTo(short.class, byte.class, true, byte.class); + } else if (expected == Short.class && internal) { + return Cast.boxTo(short.class, short.class, explicit, short.class); + } else if (expected == Character.class && explicit && internal) { + return Cast.boxTo(short.class, char.class, true, char.class); + } else if (expected == Integer.class && internal) { + return Cast.boxTo(short.class, int.class, explicit, int.class); + } else if (expected == Long.class && internal) { + return Cast.boxTo(short.class, long.class, explicit, long.class); + } else if (expected == Float.class && internal) { + return Cast.boxTo(short.class, float.class, explicit, float.class); + } else if (expected == Double.class && internal) { + return Cast.boxTo(short.class, double.class, explicit, double.class); } - } else if (actual.clazz == char.class) { - if (expected.dynamic) { - return Cast.boxFrom(definition.CharacterType, definition.DefType, explicit, definition.charType); - } else if (expected.clazz == Object.class && internal) { - return Cast.boxFrom(definition.CharacterType, definition.ObjectType, explicit, definition.charType); - } else if (expected.clazz == Number.class && internal) { - return Cast.boxFrom(definition.CharacterType, definition.NumberType, explicit, definition.charType); - } else if (expected.clazz == String.class) { - return Cast.standard(definition.charType, definition.StringType, explicit); - } else if (expected.clazz == byte.class && explicit) { - return Cast.standard(definition.charType, definition.byteType, true); - } else if (expected.clazz == short.class && explicit) { - return Cast.standard(definition.charType, definition.shortType, true); - } else if (expected.clazz == int.class) { - return Cast.standard(definition.charType, definition.intType, explicit); - } else if (expected.clazz == long.class) { - return Cast.standard(definition.charType, definition.longType, explicit); - } else if (expected.clazz == float.class) { - return Cast.standard(definition.charType, definition.floatType, explicit); - } else if (expected.clazz == double.class) { - return Cast.standard(definition.charType, definition.doubleType, explicit); - } else if (expected.clazz == Byte.class && explicit && internal) { - return Cast.boxTo(definition.charType, definition.byteType, true, definition.byteType); - } else if (expected.clazz == Short.class && internal) { - return Cast.boxTo(definition.charType, definition.shortType, explicit, definition.shortType); - } else if (expected.clazz == Character.class && internal) { - return Cast.boxTo(definition.charType, definition.charType, true, definition.charType); - } else if (expected.clazz == Integer.class && internal) { - return Cast.boxTo(definition.charType, definition.intType, explicit, definition.intType); - } else if (expected.clazz == Long.class && internal) { - return Cast.boxTo(definition.charType, definition.longType, explicit, definition.longType); - } else if (expected.clazz == Float.class && internal) { - return Cast.boxTo(definition.charType, definition.floatType, explicit, definition.floatType); - } else if (expected.clazz == Double.class && internal) { - return Cast.boxTo(definition.charType, definition.doubleType, explicit, definition.doubleType); + } else if (actual == char.class) { + if (expected == def.class) { + return Cast.boxFrom(Character.class, def.class, explicit, char.class); + } else if (expected == Object.class && internal) { + return Cast.boxFrom(Character.class, Object.class, explicit, char.class); + } else if (expected == Number.class && internal) { + return Cast.boxFrom(Character.class, Number.class, explicit, char.class); + } else if (expected == String.class) { + return Cast.standard(char.class, String.class, explicit); + } else if (expected == byte.class && explicit) { + return Cast.standard(char.class, byte.class, true); + } else if (expected == short.class && explicit) { + return Cast.standard(char.class, short.class, true); + } else if (expected == int.class) { + return Cast.standard(char.class, int.class, explicit); + } else if (expected == long.class) { + return Cast.standard(char.class, long.class, explicit); + } else if (expected == float.class) { + return Cast.standard(char.class, float.class, explicit); + } else if (expected == double.class) { + return Cast.standard(char.class, double.class, explicit); + } else if (expected == Byte.class && explicit && internal) { + return Cast.boxTo(char.class, byte.class, true, byte.class); + } else if (expected == Short.class && internal) { + return Cast.boxTo(char.class, short.class, explicit, short.class); + } else if (expected == Character.class && internal) { + return Cast.boxTo(char.class, char.class, true, char.class); + } else if (expected == Integer.class && internal) { + return Cast.boxTo(char.class, int.class, explicit, int.class); + } else if (expected == Long.class && internal) { + return Cast.boxTo(char.class, long.class, explicit, long.class); + } else if (expected == Float.class && internal) { + return Cast.boxTo(char.class, float.class, explicit, float.class); + } else if (expected == Double.class && internal) { + return Cast.boxTo(char.class, double.class, explicit, double.class); } - } else if (actual.clazz == int.class) { - if (expected.dynamic) { - return Cast.boxFrom(definition.IntegerType, definition.DefType, explicit, definition.intType); - } else if (expected.clazz == Object.class && internal) { - return Cast.boxFrom(definition.IntegerType, definition.ObjectType, explicit, definition.intType); - } else if (expected.clazz == Number.class && internal) { - return Cast.boxFrom(definition.IntegerType, definition.NumberType, explicit, definition.intType); - } else if (expected.clazz == byte.class && explicit) { - return Cast.standard(definition.intType, definition.byteType, true); - } else if (expected.clazz == char.class && explicit) { - return Cast.standard(definition.intType, definition.charType, true); - } else if (expected.clazz == short.class && explicit) { - return Cast.standard(definition.intType, definition.shortType, true); - } else if (expected.clazz == long.class) { - return Cast.standard(definition.intType, definition.longType, explicit); - } else if (expected.clazz == float.class) { - return Cast.standard(definition.intType, definition.floatType, explicit); - } else if (expected.clazz == double.class) { - return Cast.standard(definition.intType, definition.doubleType, explicit); - } else if (expected.clazz == Byte.class && explicit && internal) { - return Cast.boxTo(definition.intType, definition.byteType, true, definition.byteType); - } else if (expected.clazz == Short.class && explicit && internal) { - return Cast.boxTo(definition.intType, definition.shortType, true, definition.shortType); - } else if (expected.clazz == Character.class && explicit && internal) { - return Cast.boxTo(definition.intType, definition.charType, true, definition.charType); - } else if (expected.clazz == Integer.class && internal) { - return Cast.boxTo(definition.intType, definition.intType, explicit, definition.intType); - } else if (expected.clazz == Long.class && internal) { - return Cast.boxTo(definition.intType, definition.longType, explicit, definition.longType); - } else if (expected.clazz == Float.class && internal) { - return Cast.boxTo(definition.intType, definition.floatType, explicit, definition.floatType); - } else if (expected.clazz == Double.class && internal) { - return Cast.boxTo(definition.intType, definition.doubleType, explicit, definition.doubleType); + } else if (actual == int.class) { + if (expected == def.class) { + return Cast.boxFrom(Integer.class, def.class, explicit, int.class); + } else if (expected == Object.class && internal) { + return Cast.boxFrom(Integer.class, Object.class, explicit, int.class); + } else if (expected == Number.class && internal) { + return Cast.boxFrom(Integer.class, Number.class, explicit, int.class); + } else if (expected == byte.class && explicit) { + return Cast.standard(int.class, byte.class, true); + } else if (expected == char.class && explicit) { + return Cast.standard(int.class, char.class, true); + } else if (expected == short.class && explicit) { + return Cast.standard(int.class, short.class, true); + } else if (expected == long.class) { + return Cast.standard(int.class, long.class, explicit); + } else if (expected == float.class) { + return Cast.standard(int.class, float.class, explicit); + } else if (expected == double.class) { + return Cast.standard(int.class, double.class, explicit); + } else if (expected == Byte.class && explicit && internal) { + return Cast.boxTo(int.class, byte.class, true, byte.class); + } else if (expected == Short.class && explicit && internal) { + return Cast.boxTo(int.class, short.class, true, short.class); + } else if (expected == Character.class && explicit && internal) { + return Cast.boxTo(int.class, char.class, true, char.class); + } else if (expected == Integer.class && internal) { + return Cast.boxTo(int.class, int.class, explicit, int.class); + } else if (expected == Long.class && internal) { + return Cast.boxTo(int.class, long.class, explicit, long.class); + } else if (expected == Float.class && internal) { + return Cast.boxTo(int.class, float.class, explicit, float.class); + } else if (expected == Double.class && internal) { + return Cast.boxTo(int.class, double.class, explicit, double.class); } - } else if (actual.clazz == long.class) { - if (expected.dynamic) { - return Cast.boxFrom(definition.LongType, definition.DefType, explicit, definition.longType); - } else if (expected.clazz == Object.class && internal) { - return Cast.boxFrom(definition.LongType, definition.ObjectType, explicit, definition.longType); - } else if (expected.clazz == Number.class && internal) { - return Cast.boxFrom(definition.LongType, definition.NumberType, explicit, definition.longType); - } else if (expected.clazz == byte.class && explicit) { - return Cast.standard(definition.longType, definition.byteType, true); - } else if (expected.clazz == char.class && explicit) { - return Cast.standard(definition.longType, definition.charType, true); - } else if (expected.clazz == short.class && explicit) { - return Cast.standard(definition.longType, definition.shortType, true); - } else if (expected.clazz == int.class && explicit) { - return Cast.standard(definition.longType, definition.intType, true); - } else if (expected.clazz == float.class) { - return Cast.standard(definition.longType, definition.floatType, explicit); - } else if (expected.clazz == double.class) { - return Cast.standard(definition.longType, definition.doubleType, explicit); - } else if (expected.clazz == Byte.class && explicit && internal) { - return Cast.boxTo(definition.longType, definition.byteType, true, definition.byteType); - } else if (expected.clazz == Short.class && explicit && internal) { - return Cast.boxTo(definition.longType, definition.shortType, true, definition.shortType); - } else if (expected.clazz == Character.class && explicit && internal) { - return Cast.boxTo(definition.longType, definition.charType, true, definition.charType); - } else if (expected.clazz == Integer.class && explicit && internal) { - return Cast.boxTo(definition.longType, definition.intType, true, definition.intType); - } else if (expected.clazz == Long.class && internal) { - return Cast.boxTo(definition.longType, definition.longType, explicit, definition.longType); - } else if (expected.clazz == Float.class && internal) { - return Cast.boxTo(definition.longType, definition.floatType, explicit, definition.floatType); - } else if (expected.clazz == Double.class && internal) { - return Cast.boxTo(definition.longType, definition.doubleType, explicit, definition.doubleType); + } else if (actual == long.class) { + if (expected == def.class) { + return Cast.boxFrom(Long.class, def.class, explicit, long.class); + } else if (expected == Object.class && internal) { + return Cast.boxFrom(Long.class, Object.class, explicit, long.class); + } else if (expected == Number.class && internal) { + return Cast.boxFrom(Long.class, Number.class, explicit, long.class); + } else if (expected == byte.class && explicit) { + return Cast.standard(long.class, byte.class, true); + } else if (expected == char.class && explicit) { + return Cast.standard(long.class, char.class, true); + } else if (expected == short.class && explicit) { + return Cast.standard(long.class, short.class, true); + } else if (expected == int.class && explicit) { + return Cast.standard(long.class, int.class, true); + } else if (expected == float.class) { + return Cast.standard(long.class, float.class, explicit); + } else if (expected == double.class) { + return Cast.standard(long.class, double.class, explicit); + } else if (expected == Byte.class && explicit && internal) { + return Cast.boxTo(long.class, byte.class, true, byte.class); + } else if (expected == Short.class && explicit && internal) { + return Cast.boxTo(long.class, short.class, true, short.class); + } else if (expected == Character.class && explicit && internal) { + return Cast.boxTo(long.class, char.class, true, char.class); + } else if (expected == Integer.class && explicit && internal) { + return Cast.boxTo(long.class, int.class, true, int.class); + } else if (expected == Long.class && internal) { + return Cast.boxTo(long.class, long.class, explicit, long.class); + } else if (expected == Float.class && internal) { + return Cast.boxTo(long.class, float.class, explicit, float.class); + } else if (expected == Double.class && internal) { + return Cast.boxTo(long.class, double.class, explicit, double.class); } - } else if (actual.clazz == float.class) { - if (expected.dynamic) { - return Cast.boxFrom(definition.FloatType, definition.DefType, explicit, definition.floatType); - } else if (expected.clazz == Object.class && internal) { - return Cast.boxFrom(definition.FloatType, definition.ObjectType, explicit, definition.floatType); - } else if (expected.clazz == Number.class && internal) { - return Cast.boxFrom(definition.FloatType, definition.NumberType, explicit, definition.floatType); - } else if (expected.clazz == byte.class && explicit) { - return Cast.standard(definition.floatType, definition.byteType, true); - } else if (expected.clazz == char.class && explicit) { - return Cast.standard(definition.floatType, definition.charType, true); - } else if (expected.clazz == short.class && explicit) { - return Cast.standard(definition.floatType, definition.shortType, true); - } else if (expected.clazz == int.class && explicit) { - return Cast.standard(definition.floatType, definition.intType, true); - } else if (expected.clazz == long.class && explicit) { - return Cast.standard(definition.floatType, definition.longType, true); - } else if (expected.clazz == double.class) { - return Cast.standard(definition.floatType, definition.doubleType, explicit); - } else if (expected.clazz == Byte.class && explicit && internal) { - return Cast.boxTo(definition.floatType, definition.byteType, true, definition.byteType); - } else if (expected.clazz == Short.class && explicit && internal) { - return Cast.boxTo(definition.floatType, definition.shortType, true, definition.shortType); - } else if (expected.clazz == Character.class && explicit && internal) { - return Cast.boxTo(definition.floatType, definition.charType, true, definition.charType); - } else if (expected.clazz == Integer.class && explicit && internal) { - return Cast.boxTo(definition.floatType, definition.intType, true, definition.intType); - } else if (expected.clazz == Long.class && explicit && internal) { - return Cast.boxTo(definition.floatType, definition.longType, true, definition.longType); - } else if (expected.clazz == Float.class && internal) { - return Cast.boxTo(definition.floatType, definition.floatType, explicit, definition.floatType); - } else if (expected.clazz == Double.class && internal) { - return Cast.boxTo(definition.floatType, definition.doubleType, explicit, definition.doubleType); + } else if (actual == float.class) { + if (expected == def.class) { + return Cast.boxFrom(Float.class, def.class, explicit, float.class); + } else if (expected == Object.class && internal) { + return Cast.boxFrom(Float.class, Object.class, explicit, float.class); + } else if (expected == Number.class && internal) { + return Cast.boxFrom(Float.class, Number.class, explicit, float.class); + } else if (expected == byte.class && explicit) { + return Cast.standard(float.class, byte.class, true); + } else if (expected == char.class && explicit) { + return Cast.standard(float.class, char.class, true); + } else if (expected == short.class && explicit) { + return Cast.standard(float.class, short.class, true); + } else if (expected == int.class && explicit) { + return Cast.standard(float.class, int.class, true); + } else if (expected == long.class && explicit) { + return Cast.standard(float.class, long.class, true); + } else if (expected == double.class) { + return Cast.standard(float.class, double.class, explicit); + } else if (expected == Byte.class && explicit && internal) { + return Cast.boxTo(float.class, byte.class, true, byte.class); + } else if (expected == Short.class && explicit && internal) { + return Cast.boxTo(float.class, short.class, true, short.class); + } else if (expected == Character.class && explicit && internal) { + return Cast.boxTo(float.class, char.class, true, char.class); + } else if (expected == Integer.class && explicit && internal) { + return Cast.boxTo(float.class, int.class, true, int.class); + } else if (expected == Long.class && explicit && internal) { + return Cast.boxTo(float.class, long.class, true, long.class); + } else if (expected == Float.class && internal) { + return Cast.boxTo(float.class, float.class, explicit, float.class); + } else if (expected == Double.class && internal) { + return Cast.boxTo(float.class, double.class, explicit, double.class); } - } else if (actual.clazz == double.class) { - if (expected.dynamic) { - return Cast.boxFrom(definition.DoubleType, definition.DefType, explicit, definition.doubleType); - } else if (expected.clazz == Object.class && internal) { - return Cast.boxFrom(definition.DoubleType, definition.ObjectType, explicit, definition.doubleType); - } else if (expected.clazz == Number.class && internal) { - return Cast.boxFrom(definition.DoubleType, definition.NumberType, explicit, definition.doubleType); - } else if (expected.clazz == byte.class && explicit) { - return Cast.standard(definition.doubleType, definition.byteType, true); - } else if (expected.clazz == char.class && explicit) { - return Cast.standard(definition.doubleType, definition.charType, true); - } else if (expected.clazz == short.class && explicit) { - return Cast.standard(definition.doubleType, definition.shortType, true); - } else if (expected.clazz == int.class && explicit) { - return Cast.standard(definition.doubleType, definition.intType, true); - } else if (expected.clazz == long.class && explicit) { - return Cast.standard(definition.doubleType, definition.longType, true); - } else if (expected.clazz == float.class && explicit) { - return Cast.standard(definition.doubleType, definition.floatType, true); - } else if (expected.clazz == Byte.class && explicit && internal) { - return Cast.boxTo(definition.doubleType, definition.byteType, true, definition.byteType); - } else if (expected.clazz == Short.class && explicit && internal) { - return Cast.boxTo(definition.doubleType, definition.shortType, true, definition.shortType); - } else if (expected.clazz == Character.class && explicit && internal) { - return Cast.boxTo(definition.doubleType, definition.charType, true, definition.charType); - } else if (expected.clazz == Integer.class && explicit && internal) { - return Cast.boxTo(definition.doubleType, definition.intType, true, definition.intType); - } else if (expected.clazz == Long.class && explicit && internal) { - return Cast.boxTo(definition.doubleType, definition.longType, true, definition.longType); - } else if (expected.clazz == Float.class && explicit && internal) { - return Cast.boxTo(definition.doubleType, definition.floatType, true, definition.floatType); - } else if (expected.clazz == Double.class && internal) { - return Cast.boxTo(definition.doubleType, definition.doubleType, explicit, definition.doubleType); + } else if (actual == double.class) { + if (expected == def.class) { + return Cast.boxFrom(Double.class, def.class, explicit, double.class); + } else if (expected == Object.class && internal) { + return Cast.boxFrom(Double.class, Object.class, explicit, double.class); + } else if (expected == Number.class && internal) { + return Cast.boxFrom(Double.class, Number.class, explicit, double.class); + } else if (expected == byte.class && explicit) { + return Cast.standard(double.class, byte.class, true); + } else if (expected == char.class && explicit) { + return Cast.standard(double.class, char.class, true); + } else if (expected == short.class && explicit) { + return Cast.standard(double.class, short.class, true); + } else if (expected == int.class && explicit) { + return Cast.standard(double.class, int.class, true); + } else if (expected == long.class && explicit) { + return Cast.standard(double.class, long.class, true); + } else if (expected == float.class && explicit) { + return Cast.standard(double.class, float.class, true); + } else if (expected == Byte.class && explicit && internal) { + return Cast.boxTo(double.class, byte.class, true, byte.class); + } else if (expected == Short.class && explicit && internal) { + return Cast.boxTo(double.class, short.class, true, short.class); + } else if (expected == Character.class && explicit && internal) { + return Cast.boxTo(double.class, char.class, true, char.class); + } else if (expected == Integer.class && explicit && internal) { + return Cast.boxTo(double.class, int.class, true, int.class); + } else if (expected == Long.class && explicit && internal) { + return Cast.boxTo(double.class, long.class, true, long.class); + } else if (expected == Float.class && explicit && internal) { + return Cast.boxTo(double.class, float.class, true, float.class); + } else if (expected == Double.class && internal) { + return Cast.boxTo(double.class, double.class, explicit, double.class); } - } else if (actual.clazz == Boolean.class) { - if (expected.clazz == boolean.class && internal) { - return Cast.unboxFrom(definition.booleanType, definition.booleanType, explicit, definition.booleanType); + } else if (actual == Boolean.class) { + if (expected == boolean.class && internal) { + return Cast.unboxFrom(boolean.class, boolean.class, explicit, boolean.class); } - } else if (actual.clazz == Byte.class) { - if (expected.clazz == byte.class && internal) { - return Cast.unboxFrom(definition.byteType, definition.byteType, explicit, definition.byteType); - } else if (expected.clazz == short.class && internal) { - return Cast.unboxFrom(definition.byteType, definition.shortType, explicit, definition.byteType); - } else if (expected.clazz == char.class && explicit && internal) { - return Cast.unboxFrom(definition.byteType, definition.charType, true, definition.byteType); - } else if (expected.clazz == int.class && internal) { - return Cast.unboxFrom(definition.byteType, definition.intType, explicit, definition.byteType); - } else if (expected.clazz == long.class && internal) { - return Cast.unboxFrom(definition.byteType, definition.longType, explicit, definition.byteType); - } else if (expected.clazz == float.class && internal) { - return Cast.unboxFrom(definition.byteType, definition.floatType, explicit, definition.byteType); - } else if (expected.clazz == double.class && internal) { - return Cast.unboxFrom(definition.byteType, definition.doubleType, explicit, definition.byteType); + } else if (actual == Byte.class) { + if (expected == byte.class && internal) { + return Cast.unboxFrom(byte.class, byte.class, explicit, byte.class); + } else if (expected == short.class && internal) { + return Cast.unboxFrom(byte.class, short.class, explicit, byte.class); + } else if (expected == char.class && explicit && internal) { + return Cast.unboxFrom(byte.class, char.class, true, byte.class); + } else if (expected == int.class && internal) { + return Cast.unboxFrom(byte.class, int.class, explicit, byte.class); + } else if (expected == long.class && internal) { + return Cast.unboxFrom(byte.class, long.class, explicit, byte.class); + } else if (expected == float.class && internal) { + return Cast.unboxFrom(byte.class, float.class, explicit, byte.class); + } else if (expected == double.class && internal) { + return Cast.unboxFrom(byte.class, double.class, explicit, byte.class); } - } else if (actual.clazz == Short.class) { - if (expected.clazz == byte.class && explicit && internal) { - return Cast.unboxFrom(definition.shortType, definition.byteType, true, definition.shortType); - } else if (expected.clazz == short.class && internal) { - return Cast.unboxFrom(definition.shortType, definition.shortType, explicit, definition.shortType); - } else if (expected.clazz == char.class && explicit && internal) { - return Cast.unboxFrom(definition.shortType, definition.charType, true, definition.shortType); - } else if (expected.clazz == int.class && internal) { - return Cast.unboxFrom(definition.shortType, definition.intType, explicit, definition.shortType); - } else if (expected.clazz == long.class && internal) { - return Cast.unboxFrom(definition.shortType, definition.longType, explicit, definition.shortType); - } else if (expected.clazz == float.class && internal) { - return Cast.unboxFrom(definition.shortType, definition.floatType, explicit, definition.shortType); - } else if (expected.clazz == double.class && internal) { - return Cast.unboxFrom(definition.shortType, definition.doubleType, explicit, definition.shortType); + } else if (actual == Short.class) { + if (expected == byte.class && explicit && internal) { + return Cast.unboxFrom(short.class, byte.class, true, short.class); + } else if (expected == short.class && internal) { + return Cast.unboxFrom(short.class, short.class, explicit, short.class); + } else if (expected == char.class && explicit && internal) { + return Cast.unboxFrom(short.class, char.class, true, short.class); + } else if (expected == int.class && internal) { + return Cast.unboxFrom(short.class, int.class, explicit, short.class); + } else if (expected == long.class && internal) { + return Cast.unboxFrom(short.class, long.class, explicit, short.class); + } else if (expected == float.class && internal) { + return Cast.unboxFrom(short.class, float.class, explicit, short.class); + } else if (expected == double.class && internal) { + return Cast.unboxFrom(short.class, double.class, explicit, short.class); } - } else if (actual.clazz == Character.class) { - if (expected.clazz == byte.class && explicit && internal) { - return Cast.unboxFrom(definition.charType, definition.byteType, true, definition.charType); - } else if (expected.clazz == short.class && explicit && internal) { - return Cast.unboxFrom(definition.charType, definition.shortType, true, definition.charType); - } else if (expected.clazz == char.class && internal) { - return Cast.unboxFrom(definition.charType, definition.charType, explicit, definition.charType); - } else if (expected.clazz == int.class && internal) { - return Cast.unboxFrom(definition.charType, definition.intType, explicit, definition.charType); - } else if (expected.clazz == long.class && internal) { - return Cast.unboxFrom(definition.charType, definition.longType, explicit, definition.charType); - } else if (expected.clazz == float.class && internal) { - return Cast.unboxFrom(definition.charType, definition.floatType, explicit, definition.charType); - } else if (expected.clazz == double.class && internal) { - return Cast.unboxFrom(definition.charType, definition.doubleType, explicit, definition.charType); + } else if (actual == Character.class) { + if (expected == byte.class && explicit && internal) { + return Cast.unboxFrom(char.class, byte.class, true, char.class); + } else if (expected == short.class && explicit && internal) { + return Cast.unboxFrom(char.class, short.class, true, char.class); + } else if (expected == char.class && internal) { + return Cast.unboxFrom(char.class, char.class, explicit, char.class); + } else if (expected == int.class && internal) { + return Cast.unboxFrom(char.class, int.class, explicit, char.class); + } else if (expected == long.class && internal) { + return Cast.unboxFrom(char.class, long.class, explicit, char.class); + } else if (expected == float.class && internal) { + return Cast.unboxFrom(char.class, float.class, explicit, char.class); + } else if (expected == double.class && internal) { + return Cast.unboxFrom(char.class, double.class, explicit, char.class); } - } else if (actual.clazz == Integer.class) { - if (expected.clazz == byte.class && explicit && internal) { - return Cast.unboxFrom(definition.intType, definition.byteType, true, definition.intType); - } else if (expected.clazz == short.class && explicit && internal) { - return Cast.unboxFrom(definition.intType, definition.shortType, true, definition.intType); - } else if (expected.clazz == char.class && explicit && internal) { - return Cast.unboxFrom(definition.intType, definition.charType, true, definition.intType); - } else if (expected.clazz == int.class && internal) { - return Cast.unboxFrom(definition.intType, definition.intType, explicit, definition.intType); - } else if (expected.clazz == long.class && internal) { - return Cast.unboxFrom(definition.intType, definition.longType, explicit, definition.intType); - } else if (expected.clazz == float.class && internal) { - return Cast.unboxFrom(definition.intType, definition.floatType, explicit, definition.intType); - } else if (expected.clazz == double.class && internal) { - return Cast.unboxFrom(definition.intType, definition.doubleType, explicit, definition.intType); + } else if (actual == Integer.class) { + if (expected == byte.class && explicit && internal) { + return Cast.unboxFrom(int.class, byte.class, true, int.class); + } else if (expected == short.class && explicit && internal) { + return Cast.unboxFrom(int.class, short.class, true, int.class); + } else if (expected == char.class && explicit && internal) { + return Cast.unboxFrom(int.class, char.class, true, int.class); + } else if (expected == int.class && internal) { + return Cast.unboxFrom(int.class, int.class, explicit, int.class); + } else if (expected == long.class && internal) { + return Cast.unboxFrom(int.class, long.class, explicit, int.class); + } else if (expected == float.class && internal) { + return Cast.unboxFrom(int.class, float.class, explicit, int.class); + } else if (expected == double.class && internal) { + return Cast.unboxFrom(int.class, double.class, explicit, int.class); } - } else if (actual.clazz == Long.class) { - if (expected.clazz == byte.class && explicit && internal) { - return Cast.unboxFrom(definition.longType, definition.byteType, true, definition.longType); - } else if (expected.clazz == short.class && explicit && internal) { - return Cast.unboxFrom(definition.longType, definition.shortType, true, definition.longType); - } else if (expected.clazz == char.class && explicit && internal) { - return Cast.unboxFrom(definition.longType, definition.charType, true, definition.longType); - } else if (expected.clazz == int.class && explicit && internal) { - return Cast.unboxFrom(definition.longType, definition.intType, true, definition.longType); - } else if (expected.clazz == long.class && internal) { - return Cast.unboxFrom(definition.longType, definition.longType, explicit, definition.longType); - } else if (expected.clazz == float.class && internal) { - return Cast.unboxFrom(definition.longType, definition.floatType, explicit, definition.longType); - } else if (expected.clazz == double.class && internal) { - return Cast.unboxFrom(definition.longType, definition.doubleType, explicit, definition.longType); + } else if (actual == Long.class) { + if (expected == byte.class && explicit && internal) { + return Cast.unboxFrom(long.class, byte.class, true, long.class); + } else if (expected == short.class && explicit && internal) { + return Cast.unboxFrom(long.class, short.class, true, long.class); + } else if (expected == char.class && explicit && internal) { + return Cast.unboxFrom(long.class, char.class, true, long.class); + } else if (expected == int.class && explicit && internal) { + return Cast.unboxFrom(long.class, int.class, true, long.class); + } else if (expected == long.class && internal) { + return Cast.unboxFrom(long.class, long.class, explicit, long.class); + } else if (expected == float.class && internal) { + return Cast.unboxFrom(long.class, float.class, explicit, long.class); + } else if (expected == double.class && internal) { + return Cast.unboxFrom(long.class, double.class, explicit, long.class); } - } else if (actual.clazz == Float.class) { - if (expected.clazz == byte.class && explicit && internal) { - return Cast.unboxFrom(definition.floatType, definition.byteType, true, definition.floatType); - } else if (expected.clazz == short.class && explicit && internal) { - return Cast.unboxFrom(definition.floatType, definition.shortType, true, definition.floatType); - } else if (expected.clazz == char.class && explicit && internal) { - return Cast.unboxFrom(definition.floatType, definition.charType, true, definition.floatType); - } else if (expected.clazz == int.class && explicit && internal) { - return Cast.unboxFrom(definition.floatType, definition.intType, true, definition.floatType); - } else if (expected.clazz == long.class && explicit && internal) { - return Cast.unboxFrom(definition.floatType, definition.longType, true, definition.floatType); - } else if (expected.clazz == float.class && internal) { - return Cast.unboxFrom(definition.floatType, definition.floatType, explicit, definition.floatType); - } else if (expected.clazz == double.class && internal) { - return Cast.unboxFrom(definition.floatType, definition.doubleType, explicit, definition.floatType); + } else if (actual == Float.class) { + if (expected == byte.class && explicit && internal) { + return Cast.unboxFrom(float.class, byte.class, true, float.class); + } else if (expected == short.class && explicit && internal) { + return Cast.unboxFrom(float.class, short.class, true, float.class); + } else if (expected == char.class && explicit && internal) { + return Cast.unboxFrom(float.class, char.class, true, float.class); + } else if (expected == int.class && explicit && internal) { + return Cast.unboxFrom(float.class, int.class, true, float.class); + } else if (expected == long.class && explicit && internal) { + return Cast.unboxFrom(float.class, long.class, true, float.class); + } else if (expected == float.class && internal) { + return Cast.unboxFrom(float.class, float.class, explicit, float.class); + } else if (expected == double.class && internal) { + return Cast.unboxFrom(float.class, double.class, explicit, float.class); } - } else if (actual.clazz == Double.class) { - if (expected.clazz == byte.class && explicit && internal) { - return Cast.unboxFrom(definition.doubleType, definition.byteType, true, definition.doubleType); - } else if (expected.clazz == short.class && explicit && internal) { - return Cast.unboxFrom(definition.doubleType, definition.shortType, true, definition.doubleType); - } else if (expected.clazz == char.class && explicit && internal) { - return Cast.unboxFrom(definition.doubleType, definition.charType, true, definition.doubleType); - } else if (expected.clazz == int.class && explicit && internal) { - return Cast.unboxFrom(definition.doubleType, definition.intType, true, definition.doubleType); - } else if (expected.clazz == long.class && explicit && internal) { - return Cast.unboxFrom(definition.doubleType, definition.longType, true, definition.doubleType); - } else if (expected.clazz == float.class && explicit && internal) { - return Cast.unboxFrom(definition.doubleType, definition.floatType, true, definition.doubleType); - } else if (expected.clazz == double.class && internal) { - return Cast.unboxFrom(definition.doubleType, definition.doubleType, explicit, definition.doubleType); + } else if (actual == Double.class) { + if (expected == byte.class && explicit && internal) { + return Cast.unboxFrom(double.class, byte.class, true, double.class); + } else if (expected == short.class && explicit && internal) { + return Cast.unboxFrom(double.class, short.class, true, double.class); + } else if (expected == char.class && explicit && internal) { + return Cast.unboxFrom(double.class, char.class, true, double.class); + } else if (expected == int.class && explicit && internal) { + return Cast.unboxFrom(double.class, int.class, true, double.class); + } else if (expected == long.class && explicit && internal) { + return Cast.unboxFrom(double.class, long.class, true, double.class); + } else if (expected == float.class && explicit && internal) { + return Cast.unboxFrom(double.class, float.class, true, double.class); + } else if (expected == double.class && internal) { + return Cast.unboxFrom(double.class, double.class, explicit, double.class); } } - if ( actual.dynamic || - (actual.clazz != void.class && expected.dynamic) || - expected.clazz.isAssignableFrom(actual.clazz) || - (actual.clazz.isAssignableFrom(expected.clazz) && explicit)) { + if ( actual == def.class || + (actual != void.class && expected == def.class) || + expected.isAssignableFrom(actual) || + (actual.isAssignableFrom(expected) && explicit)) { return Cast.standard(actual, expected, explicit); } else { - throw location.createError(new ClassCastException("Cannot cast from [" + actual.name + "] to [" + expected.name + "].")); + throw location.createError(new ClassCastException( + "Cannot cast from [" + Definition.ClassToName(actual) + "] to [" + Definition.ClassToName(expected) + "].")); } } public Object constCast(Location location, final Object constant, final Cast cast) { - Class fsort = cast.from.clazz; - Class tsort = cast.to.clazz; + Class fsort = cast.from; + Class tsort = cast.to; if (fsort == tsort) { return constant; @@ -502,11 +515,11 @@ public final class AnalyzerCaster { else if (tsort == double.class) return number.doubleValue(); else { throw location.createError(new IllegalStateException("Cannot cast from " + - "[" + cast.from.clazz.getCanonicalName() + "] to [" + cast.to.clazz.getCanonicalName() + "].")); + "[" + cast.from.getCanonicalName() + "] to [" + cast.to.getCanonicalName() + "].")); } } else { throw location.createError(new IllegalStateException("Cannot cast from " + - "[" + cast.from.clazz.getCanonicalName() + "] to [" + cast.to.clazz.getCanonicalName() + "].")); + "[" + cast.from.getCanonicalName() + "] to [" + cast.to.getCanonicalName() + "].")); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Definition.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Definition.java index 7729c5319ea..52f0c2c6330 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Definition.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Definition.java @@ -27,6 +27,7 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.reflect.Modifier; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -76,6 +77,13 @@ public final class Definition { public final Type ArrayListType; public final Type HashMapType; + /** Marker class for def type to be used during type analysis. */ + public static final class def { + private def() { + + } + } + public static final class Type { public final String name; public final int dimensions; @@ -365,40 +373,41 @@ public final class Definition { } public static class Cast { + /** Create a standard cast with no boxing/unboxing. */ - public static Cast standard(Type from, Type to, boolean explicit) { + public static Cast standard(Class from, Class to, boolean explicit) { return new Cast(from, to, explicit, null, null, null, null); } /** Create a cast where the from type will be unboxed, and then the cast will be performed. */ - public static Cast unboxFrom(Type from, Type to, boolean explicit, Type unboxFrom) { + public static Cast unboxFrom(Class from, Class to, boolean explicit, Class unboxFrom) { return new Cast(from, to, explicit, unboxFrom, null, null, null); } /** Create a cast where the to type will be unboxed, and then the cast will be performed. */ - public static Cast unboxTo(Type from, Type to, boolean explicit, Type unboxTo) { + public static Cast unboxTo(Class from, Class to, boolean explicit, Class unboxTo) { return new Cast(from, to, explicit, null, unboxTo, null, null); } /** Create a cast where the from type will be boxed, and then the cast will be performed. */ - public static Cast boxFrom(Type from, Type to, boolean explicit, Type boxFrom) { + public static Cast boxFrom(Class from, Class to, boolean explicit, Class boxFrom) { return new Cast(from, to, explicit, null, null, boxFrom, null); } /** Create a cast where the to type will be boxed, and then the cast will be performed. */ - public static Cast boxTo(Type from, Type to, boolean explicit, Type boxTo) { + public static Cast boxTo(Class from, Class to, boolean explicit, Class boxTo) { return new Cast(from, to, explicit, null, null, null, boxTo); } - public final Type from; - public final Type to; + public final Class from; + public final Class to; public final boolean explicit; - public final Type unboxFrom; - public final Type unboxTo; - public final Type boxFrom; - public final Type boxTo; + public final Class unboxFrom; + public final Class unboxTo; + public final Class boxFrom; + public final Class boxTo; - private Cast(Type from, Type to, boolean explicit, Type unboxFrom, Type unboxTo, Type boxFrom, Type boxTo) { + private Cast(Class from, Class to, boolean explicit, Class unboxFrom, Class unboxTo, Class boxFrom, Class boxTo) { this.from = from; this.to = to; this.explicit = explicit; @@ -499,6 +508,92 @@ public final class Definition { constant.clazz == String.class; } + public static Class ObjectClassTodefClass(Class clazz) { + if (clazz.isArray()) { + Class component = clazz.getComponentType(); + int dimensions = 1; + + while (component.isArray()) { + component = component.getComponentType(); + ++dimensions; + } + + if (component == Object.class) { + char[] braces = new char[dimensions]; + Arrays.fill(braces, '['); + + String descriptor = new String(braces) + org.objectweb.asm.Type.getType(def.class).getDescriptor(); + org.objectweb.asm.Type type = org.objectweb.asm.Type.getType(descriptor); + + try { + return Class.forName(type.getInternalName().replace('/', '.')); + } catch (ClassNotFoundException exception) { + throw new IllegalStateException("internal error", exception); + } + } + } else if (clazz == Object.class) { + return def.class; + } + + return clazz; + } + + public static Class defClassToObjectClass(Class clazz) { + if (clazz.isArray()) { + Class component = clazz.getComponentType(); + int dimensions = 1; + + while (component.isArray()) { + component = component.getComponentType(); + ++dimensions; + } + + if (component == def.class) { + char[] braces = new char[dimensions]; + Arrays.fill(braces, '['); + + String descriptor = new String(braces) + org.objectweb.asm.Type.getType(Object.class).getDescriptor(); + org.objectweb.asm.Type type = org.objectweb.asm.Type.getType(descriptor); + + try { + return Class.forName(type.getInternalName().replace('/', '.')); + } catch (ClassNotFoundException exception) { + throw new IllegalStateException("internal error", exception); + } + } + } else if (clazz == def.class) { + return Object.class; + } + + return clazz; + } + + public static String ClassToName(Class clazz) { + if (clazz.isArray()) { + Class component = clazz.getComponentType(); + int dimensions = 1; + + while (component.isArray()) { + component = component.getComponentType(); + ++dimensions; + } + + if (component == def.class) { + StringBuilder builder = new StringBuilder("def"); + + for (int dimension = 0; dimension < dimensions; dimensions++) { + builder.append("[]"); + } + + return builder.toString(); + } + } else if (clazz == def.class) { + return "def"; + } + + return clazz.getCanonicalName(); + } + public RuntimeClass getRuntimeClass(Class clazz) { return runtimeMap.get(clazz); } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/MethodWriter.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/MethodWriter.java index b0c15abbfb0..7925856656e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/MethodWriter.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/MethodWriter.java @@ -20,15 +20,17 @@ package org.elasticsearch.painless; import org.elasticsearch.painless.Definition.Cast; -import org.elasticsearch.painless.Definition.Type; +import org.elasticsearch.painless.Definition.def; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; import org.objectweb.asm.commons.GeneratorAdapter; import org.objectweb.asm.commons.Method; import java.util.ArrayDeque; import java.util.ArrayList; +import java.util.Arrays; import java.util.BitSet; import java.util.Deque; import java.util.List; @@ -128,68 +130,68 @@ public final class MethodWriter extends GeneratorAdapter { mark(end); } - public void writeCast(final Cast cast) { + public void writeCast(Cast cast) { if (cast != null) { - if (cast.from.clazz == char.class && cast.to.clazz == String.class) { + if (cast.from == char.class && cast.to == String.class) { invokeStatic(UTILITY_TYPE, CHAR_TO_STRING); - } else if (cast.from.clazz == String.class && cast.to.clazz == char.class) { + } else if (cast.from == String.class && cast.to == char.class) { invokeStatic(UTILITY_TYPE, STRING_TO_CHAR); } else if (cast.unboxFrom != null) { - unbox(cast.unboxFrom.type); + unbox(getType(cast.unboxFrom)); writeCast(cast.from, cast.to); } else if (cast.unboxTo != null) { - if (cast.from.dynamic) { + if (cast.from == def.class) { if (cast.explicit) { - if (cast.to.clazz == Boolean.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_BOOLEAN); - else if (cast.to.clazz == Byte.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_BYTE_EXPLICIT); - else if (cast.to.clazz == Short.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_SHORT_EXPLICIT); - else if (cast.to.clazz == Character.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_CHAR_EXPLICIT); - else if (cast.to.clazz == Integer.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_INT_EXPLICIT); - else if (cast.to.clazz == Long.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_LONG_EXPLICIT); - else if (cast.to.clazz == Float.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_FLOAT_EXPLICIT); - else if (cast.to.clazz == Double.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_DOUBLE_EXPLICIT); + if (cast.to == Boolean.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_BOOLEAN); + else if (cast.to == Byte.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_BYTE_EXPLICIT); + else if (cast.to == Short.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_SHORT_EXPLICIT); + else if (cast.to == Character.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_CHAR_EXPLICIT); + else if (cast.to == Integer.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_INT_EXPLICIT); + else if (cast.to == Long.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_LONG_EXPLICIT); + else if (cast.to == Float.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_FLOAT_EXPLICIT); + else if (cast.to == Double.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_DOUBLE_EXPLICIT); else { throw new IllegalStateException("Illegal tree structure."); } } else { - if (cast.to.clazz == Boolean.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_BOOLEAN); - else if (cast.to.clazz == Byte.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_BYTE_IMPLICIT); - else if (cast.to.clazz == Short.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_SHORT_IMPLICIT); - else if (cast.to.clazz == Character.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_CHAR_IMPLICIT); - else if (cast.to.clazz == Integer.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_INT_IMPLICIT); - else if (cast.to.clazz == Long.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_LONG_IMPLICIT); - else if (cast.to.clazz == Float.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_FLOAT_IMPLICIT); - else if (cast.to.clazz == Double.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_DOUBLE_IMPLICIT); + if (cast.to == Boolean.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_BOOLEAN); + else if (cast.to == Byte.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_BYTE_IMPLICIT); + else if (cast.to == Short.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_SHORT_IMPLICIT); + else if (cast.to == Character.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_CHAR_IMPLICIT); + else if (cast.to == Integer.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_INT_IMPLICIT); + else if (cast.to == Long.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_LONG_IMPLICIT); + else if (cast.to == Float.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_FLOAT_IMPLICIT); + else if (cast.to == Double.class) invokeStatic(DEF_UTIL_TYPE, DEF_TO_DOUBLE_IMPLICIT); else { throw new IllegalStateException("Illegal tree structure."); } } } else { writeCast(cast.from, cast.to); - unbox(cast.unboxTo.type); + unbox(getType(cast.unboxTo)); } } else if (cast.boxFrom != null) { - box(cast.boxFrom.type); + box(getType(cast.boxFrom)); writeCast(cast.from, cast.to); } else if (cast.boxTo != null) { writeCast(cast.from, cast.to); - box(cast.boxTo.type); + box(getType(cast.boxTo)); } else { writeCast(cast.from, cast.to); } } } - private void writeCast(final Type from, final Type to) { + private void writeCast(Class from, Class to) { if (from.equals(to)) { return; } - if (from.clazz != boolean.class && from.clazz.isPrimitive() && to.clazz != boolean.class && to.clazz.isPrimitive()) { - cast(from.type, to.type); + if (from != boolean.class && from.isPrimitive() && to != boolean.class && to.isPrimitive()) { + cast(getType(from), getType(to)); } else { - if (!to.clazz.isAssignableFrom(from.clazz)) { - checkCast(to.type); + if (!to.isAssignableFrom(from)) { + checkCast(getType(to)); } } } @@ -202,6 +204,29 @@ public final class MethodWriter extends GeneratorAdapter { valueOf(type); } + public static Type getType(Class clazz) { + if (clazz.isArray()) { + Class component = clazz.getComponentType(); + int dimensions = 1; + + while (component.isArray()) { + component = component.getComponentType(); + ++dimensions; + } + + if (component == def.class) { + char[] braces = new char[dimensions]; + Arrays.fill(braces, '['); + + return Type.getType(new String(braces) + Type.getType(Object.class).getDescriptor()); + } + } else if (clazz == def.class) { + return Type.getType(Object.class); + } + + return Type.getType(clazz); + } + public void writeBranch(final Label tru, final Label fals) { if (tru != null) { visitJumpInsn(Opcodes.IFNE, tru); @@ -227,7 +252,7 @@ public final class MethodWriter extends GeneratorAdapter { } } - public void writeAppendStrings(final Type type) { + public void writeAppendStrings(final Definition.Type type) { if (INDY_STRING_CONCAT_BOOTSTRAP_HANDLE != null) { // Java 9+: record type information stringConcatArgs.peek().add(type.type); @@ -267,7 +292,7 @@ public final class MethodWriter extends GeneratorAdapter { } /** Writes a dynamic binary instruction: returnType, lhs, and rhs can be different */ - public void writeDynamicBinaryInstruction(Location location, Type returnType, Type lhs, Type rhs, + public void writeDynamicBinaryInstruction(Location location, Definition.Type returnType, Definition.Type lhs, Definition.Type rhs, Operation operation, int flags) { org.objectweb.asm.Type methodType = org.objectweb.asm.Type.getMethodType(returnType.type, lhs.type, rhs.type); @@ -318,7 +343,7 @@ public final class MethodWriter extends GeneratorAdapter { } /** Writes a static binary instruction */ - public void writeBinaryInstruction(Location location, Type type, Operation operation) { + public void writeBinaryInstruction(Location location, Definition.Type type, Operation operation) { if ((type.clazz == float.class || type.clazz == double.class) && (operation == Operation.LSH || operation == Operation.USH || operation == Operation.RSH || operation == Operation.BWAND || diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECast.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECast.java index 5c2a1498761..42ec197c7f5 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECast.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECast.java @@ -19,6 +19,7 @@ package org.elasticsearch.painless.node; +import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition.Cast; import java.util.Objects; @@ -63,6 +64,6 @@ final class ECast extends AExpression { @Override public String toString() { - return singleLineToString(cast.to, child); + return singleLineToString(Definition.ClassToName(cast.to), child); } } diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/AnalyzerCasterTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/AnalyzerCasterTests.java index 919b0881c07..b8fe2486017 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/AnalyzerCasterTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/AnalyzerCasterTests.java @@ -39,8 +39,8 @@ public class AnalyzerCasterTests extends ESTestCase { } Cast cast = definition.caster.getLegalCast(location, actual, expected, true, false); - assertEquals(actual, cast.from); - assertEquals(expected, cast.to); + assertEquals(actual.clazz, cast.from); + assertEquals(expected.clazz, cast.to); if (mustBeExplicit) { ClassCastException error = expectThrows(ClassCastException.class, @@ -48,8 +48,8 @@ public class AnalyzerCasterTests extends ESTestCase { assertTrue(error.getMessage().startsWith("Cannot cast")); } else { cast = definition.caster.getLegalCast(location, actual, expected, false, false); - assertEquals(actual, cast.from); - assertEquals(expected, cast.to); + assertEquals(actual.clazz, cast.from); + assertEquals(expected.clazz, cast.to); } } diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/node/NodeToStringTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/node/NodeToStringTests.java index 424b0c286ec..fb1a004e3cd 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/node/NodeToStringTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/node/NodeToStringTests.java @@ -162,12 +162,12 @@ public class NodeToStringTests extends ESTestCase { public void testECast() { Location l = new Location(getTestName(), 0); AExpression child = new EConstant(l, "test"); - Cast cast = Cast.standard(definition.StringType, definition.IntegerType, true); + Cast cast = Cast.standard(String.class, Integer.class, true); assertEquals("(ECast java.lang.Integer (EConstant String 'test'))", new ECast(l, child, cast).toString()); l = new Location(getTestName(), 1); child = new EBinary(l, Operation.ADD, new EConstant(l, "test"), new EConstant(l, 12)); - cast = Cast.standard(definition.IntegerType, definition.BooleanType, true); + cast = Cast.standard(Integer.class, Boolean.class, true); assertEquals("(ECast java.lang.Boolean (EBinary (EConstant String 'test') + (EConstant Integer 12)))", new ECast(l, child, cast).toString()); } From 4ef341a0c3925d28ad4ab007b42a3b79cb34af2c Mon Sep 17 00:00:00 2001 From: Martijn van Groningen Date: Tue, 23 Jan 2018 09:06:02 +0100 Subject: [PATCH 03/14] Revert change that does not return all indices if a specific alias is requested via get alias api. (#28294) Reopens #27763 --- .../cluster/metadata/MetaData.java | 5 +---- .../elasticsearch/aliases/IndexAliasesIT.java | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/cluster/metadata/MetaData.java b/server/src/main/java/org/elasticsearch/cluster/metadata/MetaData.java index 98afe41c596..23ed28569d2 100644 --- a/server/src/main/java/org/elasticsearch/cluster/metadata/MetaData.java +++ b/server/src/main/java/org/elasticsearch/cluster/metadata/MetaData.java @@ -276,11 +276,8 @@ public class MetaData implements Iterable, Diffable, To if (!filteredValues.isEmpty()) { // Make the list order deterministic CollectionUtil.timSort(filteredValues, Comparator.comparing(AliasMetaData::alias)); - mapBuilder.put(index, Collections.unmodifiableList(filteredValues)); - } else if (matchAllAliases) { - // in case all aliases are requested then it is desired to return the concrete index with no aliases (#25114): - mapBuilder.put(index, Collections.emptyList()); } + mapBuilder.put(index, Collections.unmodifiableList(filteredValues)); } return mapBuilder.build(); } diff --git a/server/src/test/java/org/elasticsearch/aliases/IndexAliasesIT.java b/server/src/test/java/org/elasticsearch/aliases/IndexAliasesIT.java index dae421db97f..8bf074be551 100644 --- a/server/src/test/java/org/elasticsearch/aliases/IndexAliasesIT.java +++ b/server/src/test/java/org/elasticsearch/aliases/IndexAliasesIT.java @@ -570,20 +570,24 @@ public class IndexAliasesIT extends ESIntegTestCase { logger.info("--> getting alias1"); GetAliasesResponse getResponse = admin().indices().prepareGetAliases("alias1").get(); assertThat(getResponse, notNullValue()); - assertThat(getResponse.getAliases().size(), equalTo(1)); + assertThat(getResponse.getAliases().size(), equalTo(5)); assertThat(getResponse.getAliases().get("foobar").size(), equalTo(1)); assertThat(getResponse.getAliases().get("foobar").get(0), notNullValue()); assertThat(getResponse.getAliases().get("foobar").get(0).alias(), equalTo("alias1")); assertThat(getResponse.getAliases().get("foobar").get(0).getFilter(), nullValue()); assertThat(getResponse.getAliases().get("foobar").get(0).getIndexRouting(), nullValue()); assertThat(getResponse.getAliases().get("foobar").get(0).getSearchRouting(), nullValue()); + assertTrue(getResponse.getAliases().get("test").isEmpty()); + assertTrue(getResponse.getAliases().get("test123").isEmpty()); + assertTrue(getResponse.getAliases().get("foobarbaz").isEmpty()); + assertTrue(getResponse.getAliases().get("bazbar").isEmpty()); AliasesExistResponse existsResponse = admin().indices().prepareAliasesExist("alias1").get(); assertThat(existsResponse.exists(), equalTo(true)); logger.info("--> getting all aliases that start with alias*"); getResponse = admin().indices().prepareGetAliases("alias*").get(); assertThat(getResponse, notNullValue()); - assertThat(getResponse.getAliases().size(), equalTo(1)); + assertThat(getResponse.getAliases().size(), equalTo(5)); assertThat(getResponse.getAliases().get("foobar").size(), equalTo(2)); assertThat(getResponse.getAliases().get("foobar").get(0), notNullValue()); assertThat(getResponse.getAliases().get("foobar").get(0).alias(), equalTo("alias1")); @@ -595,6 +599,10 @@ public class IndexAliasesIT extends ESIntegTestCase { assertThat(getResponse.getAliases().get("foobar").get(1).getFilter(), nullValue()); assertThat(getResponse.getAliases().get("foobar").get(1).getIndexRouting(), nullValue()); assertThat(getResponse.getAliases().get("foobar").get(1).getSearchRouting(), nullValue()); + assertTrue(getResponse.getAliases().get("test").isEmpty()); + assertTrue(getResponse.getAliases().get("test123").isEmpty()); + assertTrue(getResponse.getAliases().get("foobarbaz").isEmpty()); + assertTrue(getResponse.getAliases().get("bazbar").isEmpty()); existsResponse = admin().indices().prepareAliasesExist("alias*").get(); assertThat(existsResponse.exists(), equalTo(true)); @@ -679,12 +687,13 @@ public class IndexAliasesIT extends ESIntegTestCase { logger.info("--> getting f* for index *bar"); getResponse = admin().indices().prepareGetAliases("f*").addIndices("*bar").get(); assertThat(getResponse, notNullValue()); - assertThat(getResponse.getAliases().size(), equalTo(1)); + assertThat(getResponse.getAliases().size(), equalTo(2)); assertThat(getResponse.getAliases().get("foobar").get(0), notNullValue()); assertThat(getResponse.getAliases().get("foobar").get(0).alias(), equalTo("foo")); assertThat(getResponse.getAliases().get("foobar").get(0).getFilter(), nullValue()); assertThat(getResponse.getAliases().get("foobar").get(0).getIndexRouting(), nullValue()); assertThat(getResponse.getAliases().get("foobar").get(0).getSearchRouting(), nullValue()); + assertTrue(getResponse.getAliases().get("bazbar").isEmpty()); existsResponse = admin().indices().prepareAliasesExist("f*") .addIndices("*bar").get(); assertThat(existsResponse.exists(), equalTo(true)); @@ -693,13 +702,14 @@ public class IndexAliasesIT extends ESIntegTestCase { logger.info("--> getting f* for index *bac"); getResponse = admin().indices().prepareGetAliases("foo").addIndices("*bac").get(); assertThat(getResponse, notNullValue()); - assertThat(getResponse.getAliases().size(), equalTo(1)); + assertThat(getResponse.getAliases().size(), equalTo(2)); assertThat(getResponse.getAliases().get("foobar").size(), equalTo(1)); assertThat(getResponse.getAliases().get("foobar").get(0), notNullValue()); assertThat(getResponse.getAliases().get("foobar").get(0).alias(), equalTo("foo")); assertThat(getResponse.getAliases().get("foobar").get(0).getFilter(), nullValue()); assertThat(getResponse.getAliases().get("foobar").get(0).getIndexRouting(), nullValue()); assertThat(getResponse.getAliases().get("foobar").get(0).getSearchRouting(), nullValue()); + assertTrue(getResponse.getAliases().get("bazbar").isEmpty()); existsResponse = admin().indices().prepareAliasesExist("foo") .addIndices("*bac").get(); assertThat(existsResponse.exists(), equalTo(true)); From cf61d792b2ed27d69272cd3b5fd6e93200c90379 Mon Sep 17 00:00:00 2001 From: Catalin Ursachi Date: Tue, 23 Jan 2018 10:03:32 +0000 Subject: [PATCH 04/14] Added Put Mapping API to high-level Rest client (#27869) Relates to #27205 --- .../elasticsearch/client/IndicesClient.java | 25 +++++ .../org/elasticsearch/client/Request.java | 21 ++++ .../elasticsearch/client/IndicesClientIT.java | 31 ++++++ .../elasticsearch/client/RequestTests.java | 34 +++++++ .../IndicesClientDocumentationIT.java | 96 +++++++++++++++++-- docs/java-rest/high-level/apis/index.asciidoc | 2 + .../high-level/apis/putmapping.asciidoc | 71 ++++++++++++++ .../high-level/supported-apis.asciidoc | 1 + .../mapping/put/PutMappingRequest.java | 13 ++- .../mapping/put/PutMappingResponse.java | 25 ++++- .../create/CreateIndexRequestTests.java | 4 +- .../mapping/put/PutMappingRequestTests.java | 84 ++++++++++++++++ .../mapping/put/PutMappingResponseTests.java | 85 ++++++++++++++++ 13 files changed, 481 insertions(+), 11 deletions(-) create mode 100644 docs/java-rest/high-level/apis/putmapping.asciidoc create mode 100644 server/src/test/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingResponseTests.java diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java index 2dd130fc634..d17f0bf94e3 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java @@ -27,6 +27,8 @@ import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse; +import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; +import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse; import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; import org.elasticsearch.action.admin.indices.open.OpenIndexResponse; @@ -89,6 +91,29 @@ public final class IndicesClient { listener, Collections.emptySet(), headers); } + /** + * Updates the mappings on an index using the Put Mapping API + *

+ * See + * Put Mapping API on elastic.co + */ + public PutMappingResponse putMapping(PutMappingRequest putMappingRequest, Header... headers) throws IOException { + return restHighLevelClient.performRequestAndParseEntity(putMappingRequest, Request::putMapping, PutMappingResponse::fromXContent, + Collections.emptySet(), headers); + } + + /** + * Asynchronously updates the mappings on an index using the Put Mapping API + *

+ * See + * Put Mapping API on elastic.co + */ + public void putMappingAsync(PutMappingRequest putMappingRequest, ActionListener listener, + Header... headers) { + restHighLevelClient.performRequestAsyncAndParseEntity(putMappingRequest, Request::putMapping, PutMappingResponse::fromXContent, + listener, Collections.emptySet(), headers); + } + /** * Opens an index using the Open Index API *

diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/Request.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/Request.java index cc3b0deff52..229e45498aa 100755 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/Request.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/Request.java @@ -32,6 +32,7 @@ import org.elasticsearch.action.DocWriteRequest; import org.elasticsearch.action.admin.indices.close.CloseIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; +import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.delete.DeleteRequest; @@ -178,6 +179,22 @@ public final class Request { return new Request(HttpPut.METHOD_NAME, endpoint, parameters.getParams(), entity); } + static Request putMapping(PutMappingRequest putMappingRequest) throws IOException { + // The concreteIndex is an internal concept, not applicable to requests made over the REST API. + if (putMappingRequest.getConcreteIndex() != null) { + throw new IllegalArgumentException("concreteIndex cannot be set on PutMapping requests made over the REST API"); + } + + String endpoint = endpoint(putMappingRequest.indices(), "_mapping", putMappingRequest.type()); + + Params parameters = Params.builder(); + parameters.withTimeout(putMappingRequest.timeout()); + parameters.withMasterTimeout(putMappingRequest.masterNodeTimeout()); + + HttpEntity entity = createEntity(putMappingRequest, REQUEST_BODY_CONTENT_TYPE); + return new Request(HttpPut.METHOD_NAME, endpoint, parameters.getParams(), entity); + } + static Request info() { return new Request(HttpGet.METHOD_NAME, "/", Collections.emptyMap(), null); } @@ -454,6 +471,10 @@ public final class Request { return endpoint(String.join(",", indices), String.join(",", types), endpoint); } + static String endpoint(String[] indices, String endpoint, String type) { + return endpoint(String.join(",", indices), endpoint, type); + } + /** * Utility method to build request's endpoint. */ diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java index 5f8702807fb..2f81479f93a 100755 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java @@ -27,6 +27,8 @@ import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse; +import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; +import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse; import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; import org.elasticsearch.action.admin.indices.open.OpenIndexResponse; import org.elasticsearch.action.support.IndicesOptions; @@ -108,6 +110,35 @@ public class IndicesClientIT extends ESRestHighLevelClientTestCase { } } + @SuppressWarnings("unchecked") + public void testPutMapping() throws IOException { + { + // Add mappings to index + String indexName = "mapping_index"; + createIndex(indexName); + + PutMappingRequest putMappingRequest = new PutMappingRequest(indexName); + putMappingRequest.type("type_name"); + XContentBuilder mappingBuilder = JsonXContent.contentBuilder(); + mappingBuilder.startObject().startObject("properties").startObject("field"); + mappingBuilder.field("type", "text"); + mappingBuilder.endObject().endObject().endObject(); + putMappingRequest.source(mappingBuilder); + + PutMappingResponse putMappingResponse = + execute(putMappingRequest, highLevelClient().indices()::putMapping, highLevelClient().indices()::putMappingAsync); + assertTrue(putMappingResponse.isAcknowledged()); + + Map indexMetaData = getIndexMetadata(indexName); + Map mappingsData = (Map) indexMetaData.get("mappings"); + Map typeData = (Map) mappingsData.get("type_name"); + Map properties = (Map) typeData.get("properties"); + Map field = (Map) properties.get("field"); + + assertEquals("text", field.get("type")); + } + } + public void testDeleteIndex() throws IOException { { // Delete index if exists diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestTests.java index 49667a3dee2..0ddaf1de1ca 100755 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestTests.java @@ -28,6 +28,7 @@ import org.elasticsearch.action.DocWriteRequest; import org.elasticsearch.action.admin.indices.close.CloseIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; +import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkShardRequest; @@ -317,6 +318,39 @@ public class RequestTests extends ESTestCase { assertToXContentBody(createIndexRequest, request.getEntity()); } + public void testPutMapping() throws IOException { + PutMappingRequest putMappingRequest = new PutMappingRequest(); + + int numIndices = randomIntBetween(0, 5); + String[] indices = new String[numIndices]; + for (int i = 0; i < numIndices; i++) { + indices[i] = "index-" + randomAlphaOfLengthBetween(2, 5); + } + putMappingRequest.indices(indices); + + String type = randomAlphaOfLengthBetween(3, 10); + putMappingRequest.type(type); + + Map expectedParams = new HashMap<>(); + + setRandomTimeout(putMappingRequest::timeout, AcknowledgedRequest.DEFAULT_ACK_TIMEOUT, expectedParams); + setRandomMasterTimeout(putMappingRequest, expectedParams); + + Request request = Request.putMapping(putMappingRequest); + StringJoiner endpoint = new StringJoiner("/", "/", ""); + String index = String.join(",", indices); + if (Strings.hasLength(index)) { + endpoint.add(index); + } + endpoint.add("_mapping"); + endpoint.add(type); + assertEquals(endpoint.toString(), request.getEndpoint()); + + assertEquals(expectedParams, request.getParameters()); + assertEquals("PUT", request.getMethod()); + assertToXContentBody(putMappingRequest, request.getEntity()); + } + public void testDeleteIndex() { String[] indices = randomIndicesNames(0, 5); DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(indices); diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java index bc3b1698f96..23029c7c6b0 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java @@ -28,6 +28,8 @@ import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse; +import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; +import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse; import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; import org.elasticsearch.action.admin.indices.open.OpenIndexResponse; import org.elasticsearch.action.support.ActiveShardCount; @@ -157,15 +159,15 @@ public class IndicesClientDocumentationIT extends ESRestHighLevelClientTestCase // tag::create-index-request-mappings request.mapping("tweet", // <1> - " {\n" + - " \"tweet\": {\n" + - " \"properties\": {\n" + - " \"message\": {\n" + - " \"type\": \"text\"\n" + - " }\n" + + "{\n" + + " \"tweet\": {\n" + + " \"properties\": {\n" + + " \"message\": {\n" + + " \"type\": \"text\"\n" + " }\n" + " }\n" + - " }", // <2> + " }\n" + + "}", // <2> XContentType.JSON); // end::create-index-request-mappings @@ -228,6 +230,86 @@ public class IndicesClientDocumentationIT extends ESRestHighLevelClientTestCase } } + public void testPutMapping() throws IOException { + RestHighLevelClient client = highLevelClient(); + + { + CreateIndexResponse createIndexResponse = client.indices().create(new CreateIndexRequest("twitter")); + assertTrue(createIndexResponse.isAcknowledged()); + } + + { + // tag::put-mapping-request + PutMappingRequest request = new PutMappingRequest("twitter"); // <1> + request.type("tweet"); // <2> + // end::put-mapping-request + + // tag::put-mapping-request-source + request.source( + "{\n" + + " \"tweet\": {\n" + + " \"properties\": {\n" + + " \"message\": {\n" + + " \"type\": \"text\"\n" + + " }\n" + + " }\n" + + " }\n" + + "}", // <1> + XContentType.JSON); + // end::put-mapping-request-source + + // tag::put-mapping-request-timeout + request.timeout(TimeValue.timeValueMinutes(2)); // <1> + request.timeout("2m"); // <2> + // end::put-mapping-request-timeout + // tag::put-mapping-request-masterTimeout + request.masterNodeTimeout(TimeValue.timeValueMinutes(1)); // <1> + request.masterNodeTimeout("1m"); // <2> + // end::put-mapping-request-masterTimeout + + // tag::put-mapping-execute + PutMappingResponse putMappingResponse = client.indices().putMapping(request); + // end::put-mapping-execute + + // tag::put-mapping-response + boolean acknowledged = putMappingResponse.isAcknowledged(); // <1> + // end::put-mapping-response + assertTrue(acknowledged); + } + } + + public void testPutMappingAsync() throws Exception { + final RestHighLevelClient client = highLevelClient(); + + { + CreateIndexResponse createIndexResponse = client.indices().create(new CreateIndexRequest("twitter")); + assertTrue(createIndexResponse.isAcknowledged()); + } + + { + PutMappingRequest request = new PutMappingRequest("twitter").type("tweet"); + // tag::put-mapping-execute-async + client.indices().putMappingAsync(request, new ActionListener() { + @Override + public void onResponse(PutMappingResponse putMappingResponse) { + // <1> + } + + @Override + public void onFailure(Exception e) { + // <2> + } + }); + // end::put-mapping-execute-async + + assertBusy(() -> { + // TODO Use Indices Exist API instead once it exists + Response response = client.getLowLevelClient().performRequest("HEAD", "twitter"); + assertTrue(RestStatus.OK.getStatus() == response.getStatusLine().getStatusCode()); + }); + } + } + public void testOpenIndex() throws IOException { RestHighLevelClient client = highLevelClient(); diff --git a/docs/java-rest/high-level/apis/index.asciidoc b/docs/java-rest/high-level/apis/index.asciidoc index f6da998a847..f7367b6e8c2 100644 --- a/docs/java-rest/high-level/apis/index.asciidoc +++ b/docs/java-rest/high-level/apis/index.asciidoc @@ -6,6 +6,8 @@ include::open_index.asciidoc[] include::close_index.asciidoc[] +include::putmapping.asciidoc[] + include::_index.asciidoc[] include::get.asciidoc[] diff --git a/docs/java-rest/high-level/apis/putmapping.asciidoc b/docs/java-rest/high-level/apis/putmapping.asciidoc new file mode 100644 index 00000000000..57b8ec8964a --- /dev/null +++ b/docs/java-rest/high-level/apis/putmapping.asciidoc @@ -0,0 +1,71 @@ +[[java-rest-high-put-mapping]] +=== Put Mapping API + +[[java-rest-high-put-mapping-request]] +==== Put Mapping Request + +A `PutMappingRequest` requires an `index` argument, and a type: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[put-mapping-request] +-------------------------------------------------- +<1> The index to add the mapping to +<2> The type to create (or update) + +==== Mapping source +A description of the fields to create on the mapping; if not defined, the mapping will default to empty. + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[put-mapping-request-source] +-------------------------------------------------- +<1> The mapping source + +==== Optional arguments +The following arguments can optionally be provided: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[put-mapping-request-timeout] +-------------------------------------------------- +<1> Timeout to wait for the all the nodes to acknowledge the index creation as a `TimeValue` +<2> Timeout to wait for the all the nodes to acknowledge the index creation as a `String` + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[put-mapping-request-masterTimeout] +-------------------------------------------------- +<1> Timeout to connect to the master node as a `TimeValue` +<2> Timeout to connect to the master node as a `String` + +[[java-rest-high-put-mapping-sync]] +==== Synchronous Execution + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[put-mapping-execute] +-------------------------------------------------- + +[[java-rest-high-put-mapping-async]] +==== Asynchronous Execution + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[put-mapping-execute-async] +-------------------------------------------------- +<1> Called when the execution is successfully completed. The response is +provided as an argument +<2> Called in case of failure. The raised exception is provided as an argument + +[[java-rest-high-put-mapping-response]] +==== Put Mapping Response + +The returned `PutMappingResponse` allows to retrieve information about the executed + operation as follows: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[put-mapping-response] +-------------------------------------------------- +<1> Indicates whether all of the nodes have acknowledged the request diff --git a/docs/java-rest/high-level/supported-apis.asciidoc b/docs/java-rest/high-level/supported-apis.asciidoc index fa71b62d64e..aede4789f4d 100644 --- a/docs/java-rest/high-level/supported-apis.asciidoc +++ b/docs/java-rest/high-level/supported-apis.asciidoc @@ -8,6 +8,7 @@ Indices APIs:: * <> * <> * <> +* <> Single document APIs:: * <> diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequest.java b/server/src/main/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequest.java index 7b6c8f6eb6f..03c1308e1d9 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequest.java +++ b/server/src/main/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequest.java @@ -32,6 +32,7 @@ import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.xcontent.ToXContentObject; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentHelper; @@ -57,7 +58,7 @@ import static org.elasticsearch.action.ValidateActions.addValidationError; * @see org.elasticsearch.client.IndicesAdminClient#putMapping(PutMappingRequest) * @see PutMappingResponse */ -public class PutMappingRequest extends AcknowledgedRequest implements IndicesRequest.Replaceable { +public class PutMappingRequest extends AcknowledgedRequest implements IndicesRequest.Replaceable, ToXContentObject { private static ObjectHashSet RESERVED_FIELDS = ObjectHashSet.from( "_uid", "_id", "_type", "_source", "_all", "_analyzer", "_parent", "_routing", "_index", @@ -318,4 +319,14 @@ public class PutMappingRequest extends AcknowledgedRequest im } out.writeOptionalWriteable(concreteIndex); } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + if (source != null) { + builder.rawValue(new BytesArray(source), XContentType.JSON); + } else { + builder.startObject().endObject(); + } + return builder; + } } diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingResponse.java b/server/src/main/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingResponse.java index 64b3c77f050..f427a316c2e 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingResponse.java +++ b/server/src/main/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingResponse.java @@ -22,13 +22,24 @@ package org.elasticsearch.action.admin.indices.mapping.put; import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.xcontent.ConstructingObjectParser; +import org.elasticsearch.common.xcontent.ToXContentObject; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentParser; import java.io.IOException; /** * The response of put mapping operation. */ -public class PutMappingResponse extends AcknowledgedResponse { +public class PutMappingResponse extends AcknowledgedResponse implements ToXContentObject { + + private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>("put_mapping", + true, args -> new PutMappingResponse((boolean) args[0])); + + static { + declareAcknowledgedField(PARSER); + } protected PutMappingResponse() { @@ -49,4 +60,16 @@ public class PutMappingResponse extends AcknowledgedResponse { super.writeTo(out); writeAcknowledged(out); } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + addAcknowledgedField(builder); + builder.endObject(); + return builder; + } + + public static PutMappingResponse fromXContent(XContentParser parser) throws IOException { + return PARSER.apply(parser, null); + } } diff --git a/server/src/test/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequestTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequestTests.java index 41691f70c06..d7553ebf07c 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequestTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequestTests.java @@ -115,7 +115,7 @@ public class CreateIndexRequestTests extends ESTestCase { final XContentType xContentType = randomFrom(XContentType.values()); BytesReference originalBytes = toShuffledXContent(createIndexRequest, xContentType, EMPTY_PARAMS, humanReadable); - CreateIndexRequest parsedCreateIndexRequest = new CreateIndexRequest(createIndexRequest.index()); + CreateIndexRequest parsedCreateIndexRequest = new CreateIndexRequest(); parsedCreateIndexRequest.source(originalBytes, xContentType); assertMappingsEqual(createIndexRequest.mappings(), parsedCreateIndexRequest.mappings()); @@ -201,7 +201,7 @@ public class CreateIndexRequestTests extends ESTestCase { return builder; } - private static void randomMappingFields(XContentBuilder builder, boolean allowObjectField) throws IOException { + public static void randomMappingFields(XContentBuilder builder, boolean allowObjectField) throws IOException { builder.startObject("properties"); int fieldsNo = randomIntBetween(0, 5); diff --git a/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequestTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequestTests.java index 96dcef700a9..902dc187093 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequestTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequestTests.java @@ -21,17 +21,26 @@ package org.elasticsearch.action.admin.indices.mapping.put; import org.elasticsearch.Version; import org.elasticsearch.action.ActionRequestValidationException; +import org.elasticsearch.action.admin.indices.create.CreateIndexRequestTests; +import org.elasticsearch.common.Strings; import org.elasticsearch.common.bytes.BytesArray; +import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentHelper; +import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.common.xcontent.yaml.YamlXContent; import org.elasticsearch.index.Index; import org.elasticsearch.test.ESTestCase; import java.io.IOException; +import static org.elasticsearch.common.xcontent.ToXContent.EMPTY_PARAMS; + public class PutMappingRequestTests extends ESTestCase { public void testValidation() { @@ -94,4 +103,79 @@ public class PutMappingRequestTests extends ESTestCase { } } } + + public void testToXContent() throws IOException { + PutMappingRequest request = new PutMappingRequest("foo"); + request.type("my_type"); + + XContentBuilder mapping = JsonXContent.contentBuilder().startObject(); + mapping.startObject("properties"); + mapping.startObject("email"); + mapping.field("type", "text"); + mapping.endObject(); + mapping.endObject(); + mapping.endObject(); + request.source(mapping); + + String actualRequestBody = Strings.toString(request); + String expectedRequestBody = "{\"properties\":{\"email\":{\"type\":\"text\"}}}"; + assertEquals(expectedRequestBody, actualRequestBody); + } + + public void testToXContentWithEmptySource() throws IOException { + PutMappingRequest request = new PutMappingRequest("foo"); + request.type("my_type"); + + String actualRequestBody = Strings.toString(request); + String expectedRequestBody = "{}"; + assertEquals(expectedRequestBody, actualRequestBody); + } + + public void testToAndFromXContent() throws IOException { + + final PutMappingRequest putMappingRequest = createTestItem(); + + boolean humanReadable = randomBoolean(); + final XContentType xContentType = randomFrom(XContentType.values()); + BytesReference originalBytes = toShuffledXContent(putMappingRequest, xContentType, EMPTY_PARAMS, humanReadable); + + PutMappingRequest parsedPutMappingRequest = new PutMappingRequest(); + parsedPutMappingRequest.source(originalBytes, xContentType); + + assertMappingsEqual(putMappingRequest.source(), parsedPutMappingRequest.source()); + } + + private void assertMappingsEqual(String expected, String actual) throws IOException { + + XContentParser expectedJson = createParser(XContentType.JSON.xContent(), expected); + XContentParser actualJson = createParser(XContentType.JSON.xContent(), actual); + assertEquals(expectedJson.mapOrdered(), actualJson.mapOrdered()); + } + + /** + * Returns a random {@link PutMappingRequest}. + */ + private static PutMappingRequest createTestItem() throws IOException { + String index = randomAlphaOfLength(5); + + PutMappingRequest request = new PutMappingRequest(index); + + String type = randomAlphaOfLength(5); + request.type(type); + request.source(randomMapping()); + + return request; + } + + private static XContentBuilder randomMapping() throws IOException { + XContentBuilder builder = XContentFactory.jsonBuilder(); + builder.startObject(); + + if (randomBoolean()) { + CreateIndexRequestTests.randomMappingFields(builder, true); + } + + builder.endObject(); + return builder; + } } diff --git a/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingResponseTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingResponseTests.java new file mode 100644 index 00000000000..a52969c6281 --- /dev/null +++ b/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingResponseTests.java @@ -0,0 +1,85 @@ +/* + * 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.action.admin.indices.mapping.put; + +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.bytes.BytesReference; +import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.test.ESTestCase; + +import java.io.IOException; + +import static org.elasticsearch.test.XContentTestUtils.insertRandomFields; + +public class PutMappingResponseTests extends ESTestCase { + + public void testToXContent() { + PutMappingResponse response = new PutMappingResponse(true); + String output = Strings.toString(response); + assertEquals("{\"acknowledged\":true}", output); + } + + public void testToAndFromXContent() throws IOException { + doFromXContentTestWithRandomFields(false); + } + + /** + * This test adds random fields and objects to the xContent rendered out to + * ensure we can parse it back to be forward compatible with additions to + * the xContent + */ + public void testFromXContentWithRandomFields() throws IOException { + doFromXContentTestWithRandomFields(true); + } + + private void doFromXContentTestWithRandomFields(boolean addRandomFields) throws IOException { + + final PutMappingResponse putMappingResponse = createTestItem(); + + boolean humanReadable = randomBoolean(); + final XContentType xContentType = randomFrom(XContentType.values()); + BytesReference originalBytes = toShuffledXContent(putMappingResponse, xContentType, ToXContent.EMPTY_PARAMS, humanReadable); + + BytesReference mutated; + if (addRandomFields) { + mutated = insertRandomFields(xContentType, originalBytes, null, random()); + } else { + mutated = originalBytes; + } + PutMappingResponse parsedPutMappingResponse; + try (XContentParser parser = createParser(xContentType.xContent(), mutated)) { + parsedPutMappingResponse = PutMappingResponse.fromXContent(parser); + assertNull(parser.nextToken()); + } + + assertEquals(putMappingResponse.isAcknowledged(), parsedPutMappingResponse.isAcknowledged()); + } + + /** + * Returns a random {@link PutMappingResponse}. + */ + private static PutMappingResponse createTestItem() throws IOException { + boolean acknowledged = randomBoolean(); + + return new PutMappingResponse(acknowledged); + } +} From ba9e2e44cb32f1181dc47b3a6cc5cacac75600a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BCscher?= Date: Tue, 23 Jan 2018 13:08:54 +0100 Subject: [PATCH 05/14] [Test] Re-Add integer_range and date_range field types for query builder tests (#28171) The tests for those field types were removed in #26549 because the range mapper was moved to a module, but later this mapper was moved back to core in #27854. This change adds back those two field types like before to the general setup in AbstractQueryTestCase and adds some specifics to the RangeQueryBuilder and TermsQueryBuilder tests. Also adding back an integration test in SearchQueryIT that has been removed before but that can be kept with the mapper back in core now. Relates to #28147 --- .../index/query/RangeQueryBuilderTests.java | 14 +++++++++++--- .../index/query/TermsQueryBuilderTests.java | 7 +++---- .../elasticsearch/search/query/SearchQueryIT.java | 14 ++++++++++++++ .../elasticsearch/test/AbstractQueryTestCase.java | 12 ++++++++---- 4 files changed, 36 insertions(+), 11 deletions(-) diff --git a/server/src/test/java/org/elasticsearch/index/query/RangeQueryBuilderTests.java b/server/src/test/java/org/elasticsearch/index/query/RangeQueryBuilderTests.java index 2230436b18e..3668c7dec17 100644 --- a/server/src/test/java/org/elasticsearch/index/query/RangeQueryBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/index/query/RangeQueryBuilderTests.java @@ -65,13 +65,13 @@ public class RangeQueryBuilderTests extends AbstractQueryTestCase choice.equals(GEO_POINT_FIELD_NAME) || choice.equals(GEO_SHAPE_FIELD_NAME) + || choice.equals(INT_RANGE_FIELD_NAME) || choice.equals(DATE_RANGE_FIELD_NAME), () -> getRandomFieldName()); Object[] values = new Object[randomInt(5)]; for (int i = 0; i < values.length; i++) { values[i] = getRandomValueForFieldName(fieldName); diff --git a/server/src/test/java/org/elasticsearch/search/query/SearchQueryIT.java b/server/src/test/java/org/elasticsearch/search/query/SearchQueryIT.java index 4b56d2bc9e1..c3f1da82c79 100644 --- a/server/src/test/java/org/elasticsearch/search/query/SearchQueryIT.java +++ b/server/src/test/java/org/elasticsearch/search/query/SearchQueryIT.java @@ -36,6 +36,7 @@ import org.elasticsearch.index.query.MatchQueryBuilder; import org.elasticsearch.index.query.MultiMatchQueryBuilder; import org.elasticsearch.index.query.Operator; import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.index.query.RangeQueryBuilder; import org.elasticsearch.index.query.TermQueryBuilder; import org.elasticsearch.index.query.WrapperQueryBuilder; import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders; @@ -1893,4 +1894,17 @@ public class SearchQueryIT extends ESIntegTestCase { } } + public void testRangeQueryRangeFields_24744() throws Exception { + assertAcked(prepareCreate("test").addMapping("type1", "int_range", "type=integer_range")); + + client().prepareIndex("test", "type1", "1") + .setSource(jsonBuilder().startObject().startObject("int_range").field("gte", 10).field("lte", 20).endObject().endObject()) + .get(); + refresh(); + + RangeQueryBuilder range = new RangeQueryBuilder("int_range").relation("intersects").from(Integer.MIN_VALUE).to(Integer.MAX_VALUE); + SearchResponse searchResponse = client().prepareSearch("test").setQuery(range).get(); + assertHitCount(searchResponse, 1); + } + } diff --git a/test/framework/src/main/java/org/elasticsearch/test/AbstractQueryTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/AbstractQueryTestCase.java index 4d30bddb3a4..f8b1572fa09 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/AbstractQueryTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/AbstractQueryTestCase.java @@ -138,17 +138,19 @@ public abstract class AbstractQueryTestCase> public static final String STRING_FIELD_NAME = "mapped_string"; protected static final String STRING_FIELD_NAME_2 = "mapped_string_2"; protected static final String INT_FIELD_NAME = "mapped_int"; + protected static final String INT_RANGE_FIELD_NAME = "mapped_int_range"; protected static final String DOUBLE_FIELD_NAME = "mapped_double"; protected static final String BOOLEAN_FIELD_NAME = "mapped_boolean"; protected static final String DATE_FIELD_NAME = "mapped_date"; + protected static final String DATE_RANGE_FIELD_NAME = "mapped_date_range"; protected static final String OBJECT_FIELD_NAME = "mapped_object"; protected static final String GEO_POINT_FIELD_NAME = "mapped_geo_point"; protected static final String GEO_SHAPE_FIELD_NAME = "mapped_geo_shape"; - protected static final String[] MAPPED_FIELD_NAMES = new String[]{STRING_FIELD_NAME, INT_FIELD_NAME, - DOUBLE_FIELD_NAME, BOOLEAN_FIELD_NAME, DATE_FIELD_NAME, OBJECT_FIELD_NAME, GEO_POINT_FIELD_NAME, + protected static final String[] MAPPED_FIELD_NAMES = new String[]{STRING_FIELD_NAME, INT_FIELD_NAME, INT_RANGE_FIELD_NAME, + DOUBLE_FIELD_NAME, BOOLEAN_FIELD_NAME, DATE_FIELD_NAME, DATE_RANGE_FIELD_NAME, OBJECT_FIELD_NAME, GEO_POINT_FIELD_NAME, GEO_SHAPE_FIELD_NAME}; - private static final String[] MAPPED_LEAF_FIELD_NAMES = new String[]{STRING_FIELD_NAME, INT_FIELD_NAME, - DOUBLE_FIELD_NAME, BOOLEAN_FIELD_NAME, DATE_FIELD_NAME, GEO_POINT_FIELD_NAME, }; + private static final String[] MAPPED_LEAF_FIELD_NAMES = new String[]{STRING_FIELD_NAME, INT_FIELD_NAME, INT_RANGE_FIELD_NAME, + DOUBLE_FIELD_NAME, BOOLEAN_FIELD_NAME, DATE_FIELD_NAME, DATE_RANGE_FIELD_NAME, GEO_POINT_FIELD_NAME, }; private static final int NUMBER_OF_TESTQUERIES = 20; protected static Version indexVersionCreated; @@ -1077,9 +1079,11 @@ public abstract class AbstractQueryTestCase> STRING_FIELD_NAME, "type=text", STRING_FIELD_NAME_2, "type=keyword", INT_FIELD_NAME, "type=integer", + INT_RANGE_FIELD_NAME, "type=integer_range", DOUBLE_FIELD_NAME, "type=double", BOOLEAN_FIELD_NAME, "type=boolean", DATE_FIELD_NAME, "type=date", + DATE_RANGE_FIELD_NAME, "type=date_range", OBJECT_FIELD_NAME, "type=object", GEO_POINT_FIELD_NAME, "type=geo_point", GEO_SHAPE_FIELD_NAME, "type=geo_shape" From d31e964a869432dc506578d744f2a4d3465f0ea3 Mon Sep 17 00:00:00 2001 From: Simon Willnauer Date: Tue, 23 Jan 2018 14:50:02 +0100 Subject: [PATCH 06/14] Provide a better error message for the case when all shards failed (#28333) Today we don't specify a cause which can make debugging very very tricky. This change is best effort to supply at least one cause for the failure. --- .../action/search/AbstractSearchAsyncAction.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/action/search/AbstractSearchAsyncAction.java b/server/src/main/java/org/elasticsearch/action/search/AbstractSearchAsyncAction.java index 4632ef63174..b9e9f1ec483 100644 --- a/server/src/main/java/org/elasticsearch/action/search/AbstractSearchAsyncAction.java +++ b/server/src/main/java/org/elasticsearch/action/search/AbstractSearchAsyncAction.java @@ -122,14 +122,14 @@ abstract class AbstractSearchAsyncAction exten * at least one successful operation left and if so we move to the next phase. If not we immediately fail the * search phase as "all shards failed"*/ if (successfulOps.get() == 0) { // we have 0 successful results that means we shortcut stuff and return a failure + final ShardOperationFailedException[] shardSearchFailures = ExceptionsHelper.groupBy(buildShardFailures()); + Throwable cause = shardSearchFailures.length == 0 ? null : + ElasticsearchException.guessRootCauses(shardSearchFailures[0].getCause())[0]; if (logger.isDebugEnabled()) { - final ShardOperationFailedException[] shardSearchFailures = ExceptionsHelper.groupBy(buildShardFailures()); - Throwable cause = shardSearchFailures.length == 0 ? null : - ElasticsearchException.guessRootCauses(shardSearchFailures[0].getCause())[0]; logger.debug((Supplier) () -> new ParameterizedMessage("All shards failed for phase: [{}]", getName()), cause); } - onPhaseFailure(currentPhase, "all shards failed", null); + onPhaseFailure(currentPhase, "all shards failed", cause); } else { if (logger.isTraceEnabled()) { final String resultsFrom = results.getSuccessfulResults() From 19cfc258734e633889c130e7b13961c827af6249 Mon Sep 17 00:00:00 2001 From: Jim Ferenczi Date: Tue, 23 Jan 2018 15:14:49 +0100 Subject: [PATCH 07/14] Adds the ability to specify a format on composite date_histogram source (#28310) This commit adds the ability to specify a date format on the `date_histogram` composite source. If the format is defined, the key for the source is returned as a formatted date. Closes #27923 --- .../bucket/composite-aggregation.asciidoc | 36 +++++++- .../test/search.aggregation/230_composite.yml | 83 ++++++++++++++++- .../CompositeAggregationBuilder.java | 6 +- .../CompositeAggregationFactory.java | 7 +- .../bucket/composite/CompositeAggregator.java | 17 ++-- .../composite/CompositeValuesComparator.java | 2 +- .../composite/CompositeValuesSource.java | 18 +++- .../CompositeValuesSourceBuilder.java | 36 +++++++- .../CompositeValuesSourceConfig.java | 22 ++++- .../DateHistogramValuesSourceBuilder.java | 13 ++- .../HistogramValuesSourceBuilder.java | 4 +- .../bucket/composite/InternalComposite.java | 88 +++++++++++++++---- .../composite/TermsValuesSourceBuilder.java | 2 +- .../composite/CompositeAggregatorTests.java | 87 ++++++++++++++++++ .../composite/InternalCompositeTests.java | 56 +++++++----- 15 files changed, 401 insertions(+), 76 deletions(-) diff --git a/docs/reference/aggregations/bucket/composite-aggregation.asciidoc b/docs/reference/aggregations/bucket/composite-aggregation.asciidoc index 2e4b9a11011..438eb5afc01 100644 --- a/docs/reference/aggregations/bucket/composite-aggregation.asciidoc +++ b/docs/reference/aggregations/bucket/composite-aggregation.asciidoc @@ -225,7 +225,41 @@ Note that fractional time values are not supported, but you can address this by time unit (e.g., `1.5h` could instead be specified as `90m`). [float] -===== Time Zone +====== Format + +Internally, a date is represented as a 64 bit number representing a timestamp in milliseconds-since-the-epoch. +These timestamps are returned as the bucket keys. It is possible to return a formatted date string instead using +the format specified with the format parameter: + +[source,js] +-------------------------------------------------- +GET /_search +{ + "aggs" : { + "my_buckets": { + "composite" : { + "sources" : [ + { + "date": { + "date_histogram" : { + "field": "timestamp", + "interval": "1d", + "format": "yyyy-MM-dd" <1> + } + } + } + ] + } + } + } +} +-------------------------------------------------- +// CONSOLE + +<1> Supports expressive date <> + +[float] +====== Time Zone Date-times are stored in Elasticsearch in UTC. By default, all bucketing and rounding is also done in UTC. The `time_zone` parameter can be used to indicate diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/search.aggregation/230_composite.yml b/rest-api-spec/src/main/resources/rest-api-spec/test/search.aggregation/230_composite.yml index aaf277d171b..e094c47ff42 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/search.aggregation/230_composite.yml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/search.aggregation/230_composite.yml @@ -7,6 +7,8 @@ setup: mappings: doc: properties: + date: + type: date keyword: type: keyword long: @@ -40,6 +42,20 @@ setup: id: 4 body: { "keyword": "bar", "long": [1000, 0] } + - do: + index: + index: test + type: doc + id: 5 + body: { "date": "2017-10-20T03:08:45" } + + - do: + index: + index: test + type: doc + id: 6 + body: { "date": "2017-10-21T07:00:00" } + - do: indices.refresh: index: [test] @@ -66,7 +82,7 @@ setup: } ] - - match: {hits.total: 4} + - match: {hits.total: 6} - length: { aggregations.test.buckets: 2 } - match: { aggregations.test.buckets.0.key.kw: "bar" } - match: { aggregations.test.buckets.0.doc_count: 3 } @@ -104,7 +120,7 @@ setup: } ] - - match: {hits.total: 4} + - match: {hits.total: 6} - length: { aggregations.test.buckets: 5 } - match: { aggregations.test.buckets.0.key.long: 0} - match: { aggregations.test.buckets.0.key.kw: "bar" } @@ -154,7 +170,7 @@ setup: ] after: { "long": 20, "kw": "foo" } - - match: {hits.total: 4} + - match: {hits.total: 6} - length: { aggregations.test.buckets: 2 } - match: { aggregations.test.buckets.0.key.long: 100 } - match: { aggregations.test.buckets.0.key.kw: "bar" } @@ -188,7 +204,7 @@ setup: ] after: { "kw": "delta" } - - match: {hits.total: 4} + - match: {hits.total: 6} - length: { aggregations.test.buckets: 1 } - match: { aggregations.test.buckets.0.key.kw: "foo" } - match: { aggregations.test.buckets.0.doc_count: 2 } @@ -220,3 +236,62 @@ setup: } } ] + +--- +"Composite aggregation with format": + - skip: + version: " - 6.99.99" + reason: this uses a new option (format) added in 7.0.0 + + - do: + search: + index: test + body: + aggregations: + test: + composite: + sources: [ + { + "date": { + "date_histogram": { + "field": "date", + "interval": "1d", + "format": "yyyy-MM-dd" + } + } + } + ] + + - match: {hits.total: 6} + - length: { aggregations.test.buckets: 2 } + - match: { aggregations.test.buckets.0.key.date: "2017-10-20" } + - match: { aggregations.test.buckets.0.doc_count: 1 } + - match: { aggregations.test.buckets.1.key.date: "2017-10-21" } + - match: { aggregations.test.buckets.1.doc_count: 1 } + + - do: + search: + index: test + body: + aggregations: + test: + composite: + after: { + date: "2017-10-20" + } + sources: [ + { + "date": { + "date_histogram": { + "field": "date", + "interval": "1d", + "format": "yyyy-MM-dd" + } + } + } + ] + + - match: {hits.total: 6} + - length: { aggregations.test.buckets: 1 } + - match: { aggregations.test.buckets.0.key.date: "2017-10-21" } + - match: { aggregations.test.buckets.0.doc_count: 1 } diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeAggregationBuilder.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeAggregationBuilder.java index 5b36063e17a..58a15bbb366 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeAggregationBuilder.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeAggregationBuilder.java @@ -147,17 +147,15 @@ public class CompositeAggregationBuilder extends AbstractAggregationBuilder sourceNames = new ArrayList<>(); for (int i = 0; i < configs.length; i++) { configs[i] = sources.get(i).build(context, i, configs.length, sortFields[i]); - sourceNames.add(sources.get(i).name()); if (configs[i].valuesSource().needsScores()) { throw new IllegalArgumentException("[sources] cannot access _score"); } } final CompositeKey afterKey; if (after != null) { - if (after.size() != sources.size()) { + if (after.size() != configs.length) { throw new IllegalArgumentException("[after] has " + after.size() + " value(s) but [sources] has " + sources.size()); } @@ -179,7 +177,7 @@ public class CompositeAggregationBuilder extends AbstractAggregationBuilder { private final int size; private final CompositeValuesSourceConfig[] sources; - private final List sourceNames; private final CompositeKey afterKey; CompositeAggregationFactory(String name, SearchContext context, AggregatorFactory parent, AggregatorFactories.Builder subFactoriesBuilder, Map metaData, - int size, CompositeValuesSourceConfig[] sources, - List sourceNames, CompositeKey afterKey) throws IOException { + int size, CompositeValuesSourceConfig[] sources, CompositeKey afterKey) throws IOException { super(name, context, parent, subFactoriesBuilder, metaData); this.size = size; this.sources = sources; - this.sourceNames = sourceNames; this.afterKey = afterKey; } @@ -50,6 +47,6 @@ class CompositeAggregationFactory extends AggregatorFactory pipelineAggregators, Map metaData) throws IOException { return new CompositeAggregator(name, factories, context, parent, pipelineAggregators, metaData, - size, sources, sourceNames, afterKey); + size, sources, afterKey); } } diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeAggregator.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeAggregator.java index 3467aaf318b..e822480f915 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeAggregator.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeAggregator.java @@ -27,6 +27,7 @@ import org.apache.lucene.search.Query; import org.apache.lucene.search.Scorer; import org.apache.lucene.search.Weight; import org.apache.lucene.util.RoaringDocIdSet; +import org.elasticsearch.search.DocValueFormat; import org.elasticsearch.search.aggregations.Aggregator; import org.elasticsearch.search.aggregations.AggregatorFactories; import org.elasticsearch.search.aggregations.InternalAggregation; @@ -43,11 +44,13 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.TreeMap; +import java.util.stream.Collectors; final class CompositeAggregator extends BucketsAggregator { private final int size; private final CompositeValuesSourceConfig[] sources; private final List sourceNames; + private final List formats; private final boolean canEarlyTerminate; private final TreeMap keys; @@ -59,12 +62,12 @@ final class CompositeAggregator extends BucketsAggregator { CompositeAggregator(String name, AggregatorFactories factories, SearchContext context, Aggregator parent, List pipelineAggregators, Map metaData, - int size, CompositeValuesSourceConfig[] sources, List sourceNames, - CompositeKey rawAfterKey) throws IOException { + int size, CompositeValuesSourceConfig[] sources, CompositeKey rawAfterKey) throws IOException { super(name, factories, context, parent, pipelineAggregators, metaData); this.size = size; this.sources = sources; - this.sourceNames = sourceNames; + this.sourceNames = Arrays.stream(sources).map(CompositeValuesSourceConfig::name).collect(Collectors.toList()); + this.formats = Arrays.stream(sources).map(CompositeValuesSourceConfig::format).collect(Collectors.toList()); // we use slot 0 to fill the current document (size+1). this.array = new CompositeValuesComparator(context.searcher().getIndexReader(), sources, size+1); if (rawAfterKey != null) { @@ -131,15 +134,17 @@ final class CompositeAggregator extends BucketsAggregator { CompositeKey key = array.toCompositeKey(slot); InternalAggregations aggs = bucketAggregations(slot); int docCount = bucketDocCount(slot); - buckets[pos++] = new InternalComposite.InternalBucket(sourceNames, key, reverseMuls, docCount, aggs); + buckets[pos++] = new InternalComposite.InternalBucket(sourceNames, formats, key, reverseMuls, docCount, aggs); } - return new InternalComposite(name, size, sourceNames, Arrays.asList(buckets), reverseMuls, pipelineAggregators(), metaData()); + return new InternalComposite(name, size, sourceNames, formats, Arrays.asList(buckets), reverseMuls, + pipelineAggregators(), metaData()); } @Override public InternalAggregation buildEmptyAggregation() { final int[] reverseMuls = getReverseMuls(); - return new InternalComposite(name, size, sourceNames, Collections.emptyList(), reverseMuls, pipelineAggregators(), metaData()); + return new InternalComposite(name, size, sourceNames, formats, Collections.emptyList(), reverseMuls, + pipelineAggregators(), metaData()); } @Override diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesComparator.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesComparator.java index 849fe2c513e..0ce87460a54 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesComparator.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesComparator.java @@ -56,7 +56,7 @@ final class CompositeValuesComparator { if (vs.isFloatingPoint()) { arrays[i] = CompositeValuesSource.wrapDouble(vs, size, reverseMul); } else { - arrays[i] = CompositeValuesSource.wrapLong(vs, size, reverseMul); + arrays[i] = CompositeValuesSource.wrapLong(vs, sources[i].format(), size, reverseMul); } } } diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesSource.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesSource.java index 88d54744777..2d0368dfd4d 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesSource.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesSource.java @@ -23,8 +23,10 @@ import org.apache.lucene.index.SortedNumericDocValues; import org.apache.lucene.index.SortedSetDocValues; import org.apache.lucene.search.LeafCollector; import org.apache.lucene.util.BytesRef; +import org.elasticsearch.common.joda.FormatDateTimeFormatter; import org.elasticsearch.index.fielddata.SortedBinaryDocValues; import org.elasticsearch.index.fielddata.SortedNumericDoubleValues; +import org.elasticsearch.search.DocValueFormat; import org.elasticsearch.search.aggregations.support.ValuesSource; import org.elasticsearch.search.sort.SortOrder; @@ -96,8 +98,9 @@ abstract class CompositeValuesSource wrapLong(ValuesSource.Numeric vs, int size, int reverseMul) { - return new LongValuesSource(vs, size, reverseMul); + static CompositeValuesSource wrapLong(ValuesSource.Numeric vs, DocValueFormat format, + int size, int reverseMul) { + return new LongValuesSource(vs, format, size, reverseMul); } /** @@ -273,9 +276,12 @@ abstract class CompositeValuesSource { private final long[] values; + // handles "format" for date histogram source + private final DocValueFormat format; - LongValuesSource(ValuesSource.Numeric vs, int size, int reverseMul) { + LongValuesSource(ValuesSource.Numeric vs, DocValueFormat format, int size, int reverseMul) { super(vs, size, reverseMul); + this.format = format; this.values = new long[size]; } @@ -304,7 +310,11 @@ abstract class CompositeValuesSource { + throw new IllegalArgumentException("now() is not supported in [after] key"); + }); } } diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesSourceBuilder.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesSourceBuilder.java index 2652d90f8c3..85d172907e0 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesSourceBuilder.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesSourceBuilder.java @@ -25,6 +25,7 @@ import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.SortedNumericDocValues; import org.apache.lucene.index.SortedSetDocValues; import org.apache.lucene.search.SortField; +import org.elasticsearch.Version; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.Writeable; @@ -51,6 +52,7 @@ public abstract class CompositeValuesSourceBuilder config = ValuesSourceConfig.resolve(context.getQueryShardContext(), - valueType, field, script, missing, null, null); + valueType, field, script, missing, null, format); return innerBuild(context, config, pos, numPos, sortField); } diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesSourceConfig.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesSourceConfig.java index 4d5c1c8c846..ee70d3f39a5 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesSourceConfig.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/CompositeValuesSourceConfig.java @@ -19,30 +19,47 @@ package org.elasticsearch.search.aggregations.bucket.composite; +import org.elasticsearch.search.DocValueFormat; import org.elasticsearch.search.aggregations.support.ValuesSource; import org.elasticsearch.search.sort.SortOrder; class CompositeValuesSourceConfig { private final String name; private final ValuesSource vs; + private final DocValueFormat format; private final int reverseMul; private final boolean canEarlyTerminate; - CompositeValuesSourceConfig(String name, ValuesSource vs, SortOrder order, boolean canEarlyTerminate) { + CompositeValuesSourceConfig(String name, ValuesSource vs, DocValueFormat format, SortOrder order, boolean canEarlyTerminate) { this.name = name; this.vs = vs; + this.format = format; this.canEarlyTerminate = canEarlyTerminate; this.reverseMul = order == SortOrder.ASC ? 1 : -1; } + /** + * Returns the name associated with this configuration. + */ String name() { return name; } + /** + * Returns the {@link ValuesSource} for this configuration. + */ ValuesSource valuesSource() { return vs; } + /** + * The {@link DocValueFormat} to use for formatting the keys. + * {@link DocValueFormat#RAW} means no formatting. + */ + DocValueFormat format() { + return format; + } + /** * The sort order for the values source (e.g. -1 for descending and 1 for ascending). */ @@ -51,6 +68,9 @@ class CompositeValuesSourceConfig { return reverseMul; } + /** + * Returns whether this {@link ValuesSource} is used to sort the index. + */ boolean canEarlyTerminate() { return canEarlyTerminate; } diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/DateHistogramValuesSourceBuilder.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/DateHistogramValuesSourceBuilder.java index 0094da5069f..b7abf82a58e 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/DateHistogramValuesSourceBuilder.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/DateHistogramValuesSourceBuilder.java @@ -30,6 +30,8 @@ import org.elasticsearch.common.xcontent.ObjectParser; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.script.Script; +import org.elasticsearch.search.DocValueFormat; +import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramAggregationBuilder; import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval; import org.elasticsearch.search.aggregations.bucket.histogram.Histogram; import org.elasticsearch.search.aggregations.support.FieldContext; @@ -46,8 +48,8 @@ import java.util.Objects; import static org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramAggregationBuilder.DATE_FIELD_UNITS; /** - * A {@link CompositeValuesSourceBuilder} that that builds a {@link RoundingValuesSource} from a {@link Script} or - * a field name. + * A {@link CompositeValuesSourceBuilder} that builds a {@link RoundingValuesSource} from a {@link Script} or + * a field name using the provided interval. */ public class DateHistogramValuesSourceBuilder extends CompositeValuesSourceBuilder { static final String TYPE = "date_histogram"; @@ -55,6 +57,7 @@ public class DateHistogramValuesSourceBuilder extends CompositeValuesSourceBuild private static final ObjectParser PARSER; static { PARSER = new ObjectParser<>(DateHistogramValuesSourceBuilder.TYPE); + PARSER.declareString(DateHistogramValuesSourceBuilder::format, new ParseField("format")); PARSER.declareField((histogram, interval) -> { if (interval instanceof Long) { histogram.interval((long) interval); @@ -235,7 +238,11 @@ public class DateHistogramValuesSourceBuilder extends CompositeValuesSourceBuild canEarlyTerminate = checkCanEarlyTerminate(context.searcher().getIndexReader(), fieldContext.field(), order() == SortOrder.ASC ? false : true, sortField); } - return new CompositeValuesSourceConfig(name, vs, order(), canEarlyTerminate); + // dates are returned as timestamp in milliseconds-since-the-epoch unless a specific date format + // is specified in the builder. + final DocValueFormat docValueFormat = format() == null ? DocValueFormat.RAW : config.format(); + return new CompositeValuesSourceConfig(name, vs, docValueFormat, + order(), canEarlyTerminate); } else { throw new IllegalArgumentException("invalid source, expected numeric, got " + orig.getClass().getSimpleName()); } diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/HistogramValuesSourceBuilder.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/HistogramValuesSourceBuilder.java index dd5eb1b52d0..83ada5dbbc3 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/HistogramValuesSourceBuilder.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/HistogramValuesSourceBuilder.java @@ -37,7 +37,7 @@ import java.io.IOException; import java.util.Objects; /** - * A {@link CompositeValuesSourceBuilder} that that builds a {@link HistogramValuesSource} from another numeric values source + * A {@link CompositeValuesSourceBuilder} that builds a {@link HistogramValuesSource} from another numeric values source * using the provided interval. */ public class HistogramValuesSourceBuilder extends CompositeValuesSourceBuilder { @@ -128,7 +128,7 @@ public class HistogramValuesSourceBuilder extends CompositeValuesSourceBuilder buckets; private final int[] reverseMuls; private final List sourceNames; + private final List formats; - InternalComposite(String name, int size, List sourceNames, List buckets, int[] reverseMuls, + InternalComposite(String name, int size, List sourceNames, List formats, + List buckets, int[] reverseMuls, List pipelineAggregators, Map metaData) { super(name, pipelineAggregators, metaData); this.sourceNames = sourceNames; + this.formats = formats; this.buckets = buckets; this.size = size; this.reverseMuls = reverseMuls; @@ -63,14 +69,27 @@ public class InternalComposite super(in); this.size = in.readVInt(); this.sourceNames = in.readList(StreamInput::readString); + this.formats = new ArrayList<>(sourceNames.size()); + for (int i = 0; i < sourceNames.size(); i++) { + if (in.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) { + formats.add(in.readNamedWriteable(DocValueFormat.class)); + } else { + formats.add(DocValueFormat.RAW); + } + } this.reverseMuls = in.readIntArray(); - this.buckets = in.readList((input) -> new InternalBucket(input, sourceNames, reverseMuls)); + this.buckets = in.readList((input) -> new InternalBucket(input, sourceNames, formats, reverseMuls)); } @Override protected void doWriteTo(StreamOutput out) throws IOException { out.writeVInt(size); out.writeStringList(sourceNames); + if (out.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) { + for (DocValueFormat format : formats) { + out.writeNamedWriteable(format); + } + } out.writeIntArray(reverseMuls); out.writeList(buckets); } @@ -87,12 +106,13 @@ public class InternalComposite @Override public InternalComposite create(List buckets) { - return new InternalComposite(name, size, sourceNames, buckets, reverseMuls, pipelineAggregators(), getMetaData()); + return new InternalComposite(name, size, sourceNames, formats, buckets, reverseMuls, pipelineAggregators(), getMetaData()); } @Override public InternalBucket createBucket(InternalAggregations aggregations, InternalBucket prototype) { - return new InternalBucket(prototype.sourceNames, prototype.key, prototype.reverseMuls, prototype.docCount, aggregations); + return new InternalBucket(prototype.sourceNames, prototype.formats, prototype.key, prototype.reverseMuls, + prototype.docCount, aggregations); } public int getSize() { @@ -149,7 +169,7 @@ public class InternalComposite reduceContext.consumeBucketsAndMaybeBreak(1); result.add(reduceBucket); } - return new InternalComposite(name, size, sourceNames, result, reverseMuls, pipelineAggregators(), metaData); + return new InternalComposite(name, size, sourceNames, formats, result, reverseMuls, pipelineAggregators(), metaData); } @Override @@ -191,18 +211,21 @@ public class InternalComposite private final InternalAggregations aggregations; private final transient int[] reverseMuls; private final transient List sourceNames; + private final transient List formats; - InternalBucket(List sourceNames, CompositeKey key, int[] reverseMuls, long docCount, InternalAggregations aggregations) { + InternalBucket(List sourceNames, List formats, CompositeKey key, int[] reverseMuls, long docCount, + InternalAggregations aggregations) { this.key = key; this.docCount = docCount; this.aggregations = aggregations; this.reverseMuls = reverseMuls; this.sourceNames = sourceNames; + this.formats = formats; } @SuppressWarnings("unchecked") - InternalBucket(StreamInput in, List sourceNames, int[] reverseMuls) throws IOException { + InternalBucket(StreamInput in, List sourceNames, List formats, int[] reverseMuls) throws IOException { final Comparable[] values = new Comparable[in.readVInt()]; for (int i = 0; i < values.length; i++) { values[i] = (Comparable) in.readGenericValue(); @@ -212,6 +235,7 @@ public class InternalComposite this.aggregations = InternalAggregations.readAggregations(in); this.reverseMuls = reverseMuls; this.sourceNames = sourceNames; + this.formats = formats; } @Override @@ -242,9 +266,11 @@ public class InternalComposite @Override public Map getKey() { - return new ArrayMap(sourceNames, key.values()); + // returns the formatted key in a map + return new ArrayMap(sourceNames, formats, key.values()); } + // get the raw key (without formatting to preserve the natural order). // visible for testing CompositeKey getRawKey() { return key; @@ -260,7 +286,7 @@ public class InternalComposite } builder.append(sourceNames.get(i)); builder.append('='); - builder.append(formatObject(key.get(i))); + builder.append(formatObject(key.get(i), formats.get(i))); } builder.append('}'); return builder.toString(); @@ -284,7 +310,7 @@ public class InternalComposite aggregations.add(bucket.aggregations); } InternalAggregations aggs = InternalAggregations.reduce(aggregations, reduceContext); - return new InternalBucket(sourceNames, key, reverseMuls, docCount, aggs); + return new InternalBucket(sourceNames, formats, key, reverseMuls, docCount, aggs); } @Override @@ -303,26 +329,52 @@ public class InternalComposite @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { /** - * See {@link CompositeAggregation#bucketToXContentFragment} + * See {@link CompositeAggregation#bucketToXContent} */ throw new UnsupportedOperationException("not implemented"); } } - static Object formatObject(Object obj) { - if (obj instanceof BytesRef) { - return ((BytesRef) obj).utf8ToString(); + /** + * Format obj using the provided {@link DocValueFormat}. + * If the format is equals to {@link DocValueFormat#RAW}, the object is returned as is + * for numbers and a string for {@link BytesRef}s. + */ + static Object formatObject(Object obj, DocValueFormat format) { + if (obj.getClass() == BytesRef.class) { + BytesRef value = (BytesRef) obj; + if (format == DocValueFormat.RAW) { + return value.utf8ToString(); + } else { + return format.format((BytesRef) obj); + } + } else if (obj.getClass() == Long.class) { + Long value = (Long) obj; + if (format == DocValueFormat.RAW) { + return value; + } else { + return format.format(value); + } + } else if (obj.getClass() == Double.class) { + Double value = (Double) obj; + if (format == DocValueFormat.RAW) { + return value; + } else { + return format.format((Double) obj); + } } return obj; } private static class ArrayMap extends AbstractMap { final List keys; + final List formats; final Object[] values; - ArrayMap(List keys, Object[] values) { - assert keys.size() == values.length; + ArrayMap(List keys, List formats, Object[] values) { + assert keys.size() == values.length && keys.size() == formats.size(); this.keys = keys; + this.formats = formats; this.values = values; } @@ -335,7 +387,7 @@ public class InternalComposite public Object get(Object key) { for (int i = 0; i < keys.size(); i++) { if (key.equals(keys.get(i))) { - return formatObject(values[i]); + return formatObject(values[i], formats.get(i)); } } return null; @@ -356,7 +408,7 @@ public class InternalComposite @Override public Entry next() { SimpleEntry entry = - new SimpleEntry<>(keys.get(pos), formatObject(values[pos])); + new SimpleEntry<>(keys.get(pos), formatObject(values[pos], formats.get(pos))); ++ pos; return entry; } diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/TermsValuesSourceBuilder.java b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/TermsValuesSourceBuilder.java index 481c14a37f5..6ca5cdbcb62 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/TermsValuesSourceBuilder.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/bucket/composite/TermsValuesSourceBuilder.java @@ -95,6 +95,6 @@ public class TermsValuesSourceBuilder extends CompositeValuesSourceBuilder>> dataset = new ArrayList<>(); + dataset.addAll( + Arrays.asList( + createDocument("date", asLong("2017-10-20T03:08:45")), + createDocument("date", asLong("2016-09-20T09:00:34")), + createDocument("date", asLong("2016-09-20T11:34:00")), + createDocument("date", asLong("2017-10-20T06:09:24")), + createDocument("date", asLong("2017-10-19T06:09:24")), + createDocument("long", 4L) + ) + ); + final Sort sort = new Sort(new SortedNumericSortField("date", SortField.Type.LONG)); + testSearchCase(new MatchAllDocsQuery(), sort, dataset, + () -> { + DateHistogramValuesSourceBuilder histo = new DateHistogramValuesSourceBuilder("date") + .field("date") + .dateHistogramInterval(DateHistogramInterval.days(1)) + .format("yyyy-MM-dd"); + return new CompositeAggregationBuilder("name", Collections.singletonList(histo)); + }, + (result) -> { + assertEquals(3, result.getBuckets().size()); + assertEquals("{date=2016-09-20}", result.getBuckets().get(0).getKeyAsString()); + assertEquals(2L, result.getBuckets().get(0).getDocCount()); + assertEquals("{date=2017-10-19}", result.getBuckets().get(1).getKeyAsString()); + assertEquals(1L, result.getBuckets().get(1).getDocCount()); + assertEquals("{date=2017-10-20}", result.getBuckets().get(2).getKeyAsString()); + assertEquals(2L, result.getBuckets().get(2).getDocCount()); + } + ); + + testSearchCase(new MatchAllDocsQuery(), sort, dataset, + () -> { + DateHistogramValuesSourceBuilder histo = new DateHistogramValuesSourceBuilder("date") + .field("date") + .dateHistogramInterval(DateHistogramInterval.days(1)) + .format("yyyy-MM-dd"); + return new CompositeAggregationBuilder("name", Collections.singletonList(histo)) + .aggregateAfter(createAfterKey("date", "2016-09-20")); + + }, (result) -> { + assertEquals(2, result.getBuckets().size()); + assertEquals("{date=2017-10-19}", result.getBuckets().get(0).getKeyAsString()); + assertEquals(1L, result.getBuckets().get(0).getDocCount()); + assertEquals("{date=2017-10-20}", result.getBuckets().get(1).getKeyAsString()); + assertEquals(2L, result.getBuckets().get(1).getDocCount()); + } + ); + } + + public void testThatDateHistogramFailsFormatAfter() throws IOException { + ElasticsearchParseException exc = expectThrows(ElasticsearchParseException.class, + () -> testSearchCase(new MatchAllDocsQuery(), null, Collections.emptyList(), + () -> { + DateHistogramValuesSourceBuilder histo = new DateHistogramValuesSourceBuilder("date") + .field("date") + .dateHistogramInterval(DateHistogramInterval.days(1)) + .format("yyyy-MM-dd"); + return new CompositeAggregationBuilder("name", Collections.singletonList(histo)) + .aggregateAfter(createAfterKey("date", "now")); + }, + (result) -> {} + )); + assertThat(exc.getCause(), instanceOf(IllegalArgumentException.class)); + assertThat(exc.getCause().getMessage(), containsString("now() is not supported in [after] key")); + + exc = expectThrows(ElasticsearchParseException.class, + () -> testSearchCase(new MatchAllDocsQuery(), null, Collections.emptyList(), + () -> { + DateHistogramValuesSourceBuilder histo = new DateHistogramValuesSourceBuilder("date") + .field("date") + .dateHistogramInterval(DateHistogramInterval.days(1)) + .format("yyyy-MM-dd"); + return new CompositeAggregationBuilder("name", Collections.singletonList(histo)) + .aggregateAfter(createAfterKey("date", "1474329600000")); + }, + (result) -> {} + )); + assertThat(exc.getCause(), instanceOf(IllegalArgumentException.class)); + assertThat(exc.getCause().getMessage(), containsString("Parse failure")); + } + public void testWithDateHistogramAndTimeZone() throws IOException { final List>> dataset = new ArrayList<>(); dataset.addAll( diff --git a/server/src/test/java/org/elasticsearch/search/aggregations/bucket/composite/InternalCompositeTests.java b/server/src/test/java/org/elasticsearch/search/aggregations/bucket/composite/InternalCompositeTests.java index 10cc5b8016d..322b70cb2d9 100644 --- a/server/src/test/java/org/elasticsearch/search/aggregations/bucket/composite/InternalCompositeTests.java +++ b/server/src/test/java/org/elasticsearch/search/aggregations/bucket/composite/InternalCompositeTests.java @@ -21,12 +21,15 @@ package org.elasticsearch.search.aggregations.bucket.composite; import org.apache.lucene.util.BytesRef; import org.elasticsearch.common.io.stream.Writeable; +import org.elasticsearch.common.joda.Joda; import org.elasticsearch.common.util.BigArrays; +import org.elasticsearch.search.DocValueFormat; import org.elasticsearch.search.aggregations.InternalAggregation; import org.elasticsearch.search.aggregations.InternalAggregations; import org.elasticsearch.search.aggregations.ParsedAggregation; import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator; import org.elasticsearch.test.InternalMultiBucketAggregationTestCase; +import org.joda.time.DateTimeZone; import org.junit.After; import java.io.IOException; @@ -41,28 +44,45 @@ import java.util.TreeSet; import java.util.stream.Collectors; import static com.carrotsearch.randomizedtesting.RandomizedTest.randomAsciiLettersOfLengthBetween; -import static com.carrotsearch.randomizedtesting.RandomizedTest.randomLongBetween; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.lessThanOrEqualTo; public class InternalCompositeTests extends InternalMultiBucketAggregationTestCase { private List sourceNames; + private List formats; private int[] reverseMuls; - private int[] formats; + private int[] types; private int size; + private static DocValueFormat randomDocValueFormat(boolean isLong) { + if (isLong) { + // we use specific format only for date histogram on a long/date field + if (randomBoolean()) { + return new DocValueFormat.DateTime(Joda.forPattern("epoch_second"), DateTimeZone.forOffsetHours(1)); + } else { + return DocValueFormat.RAW; + } + } else { + // and the raw format for the other types + return DocValueFormat.RAW; + } + } + @Override public void setUp() throws Exception { super.setUp(); int numFields = randomIntBetween(1, 10); size = randomNumberOfBuckets(); sourceNames = new ArrayList<>(); + formats = new ArrayList<>(); reverseMuls = new int[numFields]; - formats = new int[numFields]; + types = new int[numFields]; for (int i = 0; i < numFields; i++) { sourceNames.add("field_" + i); reverseMuls[i] = randomBoolean() ? 1 : -1; - formats[i] = randomIntBetween(0, 2); + int type = randomIntBetween(0, 2); + types[i] = type; + formats.add(randomDocValueFormat(type == 0)); } } @@ -70,9 +90,10 @@ public class InternalCompositeTests extends InternalMultiBucketAggregationTestCa @After public void tearDown() throws Exception { super.tearDown(); - sourceNames= null; - reverseMuls = null; + sourceNames = null; formats = null; + reverseMuls = null; + types = null; } @Override @@ -93,7 +114,7 @@ public class InternalCompositeTests extends InternalMultiBucketAggregationTestCa private CompositeKey createCompositeKey() { Comparable[] keys = new Comparable[sourceNames.size()]; for (int j = 0; j < keys.length; j++) { - switch (formats[j]) { + switch (types[j]) { case 0: keys[j] = randomLong(); break; @@ -123,19 +144,6 @@ public class InternalCompositeTests extends InternalMultiBucketAggregationTestCa }; } - @SuppressWarnings("unchecked") - private Comparator getBucketComparator() { - return (o1, o2) -> { - for (int i = 0; i < o1.getRawKey().size(); i++) { - int cmp = ((Comparable) o1.getRawKey().get(i)).compareTo(o2.getRawKey().get(i)) * reverseMuls[i]; - if (cmp != 0) { - return cmp; - } - } - return 0; - }; - } - @Override protected InternalComposite createTestInstance(String name, List pipelineAggregators, Map metaData, InternalAggregations aggregations) { @@ -149,11 +157,11 @@ public class InternalCompositeTests extends InternalMultiBucketAggregationTestCa } keys.add(key); InternalComposite.InternalBucket bucket = - new InternalComposite.InternalBucket(sourceNames, key, reverseMuls, 1L, aggregations); + new InternalComposite.InternalBucket(sourceNames, formats, key, reverseMuls, 1L, aggregations); buckets.add(bucket); } Collections.sort(buckets, (o1, o2) -> o1.compareKey(o2)); - return new InternalComposite(name, size, sourceNames, buckets, reverseMuls, Collections.emptyList(), metaData); + return new InternalComposite(name, size, sourceNames, formats, buckets, reverseMuls, Collections.emptyList(), metaData); } @Override @@ -172,7 +180,7 @@ public class InternalCompositeTests extends InternalMultiBucketAggregationTestCa break; case 1: buckets = new ArrayList<>(buckets); - buckets.add(new InternalComposite.InternalBucket(sourceNames, createCompositeKey(), reverseMuls, + buckets.add(new InternalComposite.InternalBucket(sourceNames, formats, createCompositeKey(), reverseMuls, randomLongBetween(1, 100), InternalAggregations.EMPTY) ); break; @@ -187,7 +195,7 @@ public class InternalCompositeTests extends InternalMultiBucketAggregationTestCa default: throw new AssertionError("illegal branch"); } - return new InternalComposite(instance.getName(), instance.getSize(), sourceNames, buckets, reverseMuls, + return new InternalComposite(instance.getName(), instance.getSize(), sourceNames, formats, buckets, reverseMuls, instance.pipelineAggregators(), metaData); } From b2ce994be7b99b9239938c411630e690debd216d Mon Sep 17 00:00:00 2001 From: Jim Ferenczi Date: Tue, 23 Jan 2018 16:41:32 +0100 Subject: [PATCH 08/14] [Docs] Fix asciidoc style in composite agg docs --- .../aggregations/bucket/composite-aggregation.asciidoc | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/reference/aggregations/bucket/composite-aggregation.asciidoc b/docs/reference/aggregations/bucket/composite-aggregation.asciidoc index 438eb5afc01..be18689bfdd 100644 --- a/docs/reference/aggregations/bucket/composite-aggregation.asciidoc +++ b/docs/reference/aggregations/bucket/composite-aggregation.asciidoc @@ -224,7 +224,6 @@ Time values can also be specified via abbreviations supported by < Supports expressive date <> -[float] ====== Time Zone Date-times are stored in Elasticsearch in UTC. By default, all bucketing and From 4d3f7a7695d252dcfc97242f179e934d7d043c51 Mon Sep 17 00:00:00 2001 From: Simon Willnauer Date: Tue, 23 Jan 2018 16:57:26 +0100 Subject: [PATCH 09/14] Ensure we protect Collections obtained from scripts from self-referencing (#28335) Self referencing maps can cause SOE if they are iterated ie. in their toString methods. This chance adds some protected to the usage of those collections. --- .../CustomReflectionObjectHandler.java | 6 +++ .../rest-api-spec/test/painless/15_update.yml | 2 +- .../rest-api-spec/test/painless/30_search.yml | 36 ++++++++++++++++++ .../common/util/CollectionUtils.java | 38 +++++++++++++++++++ .../common/xcontent/XContentBuilder.java | 36 ++---------------- .../scripted/ScriptedMetricAggregator.java | 2 + .../BucketScriptPipelineAggregator.java | 3 +- .../aggregations/support/ValuesSource.java | 5 ++- .../support/values/ScriptBytesValues.java | 2 + .../subphase/ScriptFieldsFetchSubPhase.java | 2 + .../search/sort/ScriptSortBuilder.java | 5 ++- .../common/util/CollectionUtilsTests.java | 16 ++++++++ .../common/xcontent/BaseXContentTestCase.java | 23 +++++------ 13 files changed, 128 insertions(+), 48 deletions(-) diff --git a/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/CustomReflectionObjectHandler.java b/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/CustomReflectionObjectHandler.java index eef9d7af8dd..79319369489 100644 --- a/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/CustomReflectionObjectHandler.java +++ b/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/CustomReflectionObjectHandler.java @@ -20,6 +20,7 @@ package org.elasticsearch.script.mustache; import com.github.mustachejava.reflect.ReflectionObjectHandler; +import org.elasticsearch.common.util.CollectionUtils; import org.elasticsearch.common.util.iterable.Iterables; import java.lang.reflect.Array; @@ -154,4 +155,9 @@ final class CustomReflectionObjectHandler extends ReflectionObjectHandler { } } + @Override + public String stringify(Object object) { + CollectionUtils.ensureNoSelfReferences(object); + return super.stringify(object); + } } diff --git a/modules/lang-painless/src/test/resources/rest-api-spec/test/painless/15_update.yml b/modules/lang-painless/src/test/resources/rest-api-spec/test/painless/15_update.yml index 0e319be97bf..20047e7d482 100644 --- a/modules/lang-painless/src/test/resources/rest-api-spec/test/painless/15_update.yml +++ b/modules/lang-painless/src/test/resources/rest-api-spec/test/painless/15_update.yml @@ -137,4 +137,4 @@ - match: { error.root_cause.0.type: "remote_transport_exception" } - match: { error.type: "illegal_argument_exception" } - - match: { error.reason: "Object has already been built and is self-referencing itself" } + - match: { error.reason: "Iterable object is self-referencing itself" } diff --git a/modules/lang-painless/src/test/resources/rest-api-spec/test/painless/30_search.yml b/modules/lang-painless/src/test/resources/rest-api-spec/test/painless/30_search.yml index 28679cb223f..b7be116b386 100644 --- a/modules/lang-painless/src/test/resources/rest-api-spec/test/painless/30_search.yml +++ b/modules/lang-painless/src/test/resources/rest-api-spec/test/painless/30_search.yml @@ -406,3 +406,39 @@ - match: { hits.hits.0._score: 1.0 } - match: { aggregations.value_agg.buckets.0.key: 2 } - match: { aggregations.value_agg.buckets.0.doc_count: 1 } + +--- +"Return self-referencing map": + - do: + indices.create: + index: test + body: + settings: + number_of_shards: "1" + + - do: + index: + index: test + type: test + id: 1 + body: { "genre": 1 } + + - do: + indices.refresh: {} + + - do: + catch: bad_request + index: test + search: + body: + aggs: + genre: + terms: + script: + lang: painless + source: "def x = [:] ; def y = [:] ; x.a = y ; y.a = x ; return x" + + - match: { error.root_cause.0.type: "illegal_argument_exception" } + - match: { error.root_cause.0.reason: "Iterable object is self-referencing itself" } + - match: { error.type: "search_phase_execution_exception" } + - match: { error.reason: "all shards failed" } diff --git a/server/src/main/java/org/elasticsearch/common/util/CollectionUtils.java b/server/src/main/java/org/elasticsearch/common/util/CollectionUtils.java index 54a49f7e4f2..08d02cdea31 100644 --- a/server/src/main/java/org/elasticsearch/common/util/CollectionUtils.java +++ b/server/src/main/java/org/elasticsearch/common/util/CollectionUtils.java @@ -19,16 +19,20 @@ package org.elasticsearch.common.util; +import java.nio.file.Path; import java.util.AbstractList; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import java.util.IdentityHashMap; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.RandomAccess; +import java.util.Set; import com.carrotsearch.hppc.ObjectArrayList; import org.apache.lucene.util.BytesRef; @@ -221,6 +225,40 @@ public class CollectionUtils { return ints.stream().mapToInt(s -> s).toArray(); } + public static void ensureNoSelfReferences(Object value) { + Iterable it = convert(value); + if (it != null) { + ensureNoSelfReferences(it, value, Collections.newSetFromMap(new IdentityHashMap<>())); + } + } + + private static Iterable convert(Object value) { + if (value == null) { + return null; + } + if (value instanceof Map) { + return ((Map) value).values(); + } else if ((value instanceof Iterable) && (value instanceof Path == false)) { + return (Iterable) value; + } else if (value instanceof Object[]) { + return Arrays.asList((Object[]) value); + } else { + return null; + } + } + + private static void ensureNoSelfReferences(final Iterable value, Object originalReference, final Set ancestors) { + if (value != null) { + if (ancestors.add(originalReference) == false) { + throw new IllegalArgumentException("Iterable object is self-referencing itself"); + } + for (Object o : value) { + ensureNoSelfReferences(convert(o), o, ancestors); + } + ancestors.remove(originalReference); + } + } + private static class RotatedList extends AbstractList implements RandomAccess { private final List in; diff --git a/server/src/main/java/org/elasticsearch/common/xcontent/XContentBuilder.java b/server/src/main/java/org/elasticsearch/common/xcontent/XContentBuilder.java index 070510e13ff..9f7603c997e 100644 --- a/server/src/main/java/org/elasticsearch/common/xcontent/XContentBuilder.java +++ b/server/src/main/java/org/elasticsearch/common/xcontent/XContentBuilder.java @@ -28,6 +28,7 @@ import org.elasticsearch.common.lease.Releasable; import org.elasticsearch.common.text.Text; import org.elasticsearch.common.unit.ByteSizeValue; import org.elasticsearch.common.unit.TimeValue; +import org.elasticsearch.common.util.CollectionUtils; import org.joda.time.DateTimeZone; import org.joda.time.ReadableInstant; import org.joda.time.format.DateTimeFormatter; @@ -43,7 +44,6 @@ import java.util.Calendar; import java.util.Collections; import java.util.Date; import java.util.HashMap; -import java.util.IdentityHashMap; import java.util.Locale; import java.util.Map; import java.util.Objects; @@ -780,7 +780,6 @@ public final class XContentBuilder implements Releasable, Flushable { if (values == null) { return nullValue(); } - return value(Arrays.asList(values), ensureNoSelfReferences); } @@ -865,7 +864,7 @@ public final class XContentBuilder implements Releasable, Flushable { // checks that the map does not contain references to itself because // iterating over map entries will cause a stackoverflow error if (ensureNoSelfReferences) { - ensureNoSelfReferences(values); + CollectionUtils.ensureNoSelfReferences(values); } startObject(); @@ -894,9 +893,8 @@ public final class XContentBuilder implements Releasable, Flushable { // checks that the iterable does not contain references to itself because // iterating over entries will cause a stackoverflow error if (ensureNoSelfReferences) { - ensureNoSelfReferences(values); + CollectionUtils.ensureNoSelfReferences(values); } - startArray(); for (Object value : values) { // pass ensureNoSelfReferences=false as we already performed the check at a higher level @@ -1067,32 +1065,4 @@ public final class XContentBuilder implements Releasable, Flushable { throw new IllegalArgumentException(message); } } - - static void ensureNoSelfReferences(Object value) { - ensureNoSelfReferences(value, Collections.newSetFromMap(new IdentityHashMap<>())); - } - - private static void ensureNoSelfReferences(final Object value, final Set ancestors) { - if (value != null) { - - Iterable it; - if (value instanceof Map) { - it = ((Map) value).values(); - } else if ((value instanceof Iterable) && (value instanceof Path == false)) { - it = (Iterable) value; - } else if (value instanceof Object[]) { - it = Arrays.asList((Object[]) value); - } else { - return; - } - - if (ancestors.add(value) == false) { - throw new IllegalArgumentException("Object has already been built and is self-referencing itself"); - } - for (Object o : it) { - ensureNoSelfReferences(o, ancestors); - } - ancestors.remove(value); - } - } } diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/ScriptedMetricAggregator.java b/server/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/ScriptedMetricAggregator.java index bebe9f892b6..04ef595690a 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/ScriptedMetricAggregator.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/metrics/scripted/ScriptedMetricAggregator.java @@ -20,6 +20,7 @@ package org.elasticsearch.search.aggregations.metrics.scripted; import org.apache.lucene.index.LeafReaderContext; +import org.elasticsearch.common.util.CollectionUtils; import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.Script; import org.elasticsearch.script.SearchScript; @@ -77,6 +78,7 @@ public class ScriptedMetricAggregator extends MetricsAggregator { Object aggregation; if (combineScript != null) { aggregation = combineScript.run(); + CollectionUtils.ensureNoSelfReferences(aggregation); } else { aggregation = params.get("_agg"); } diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/pipeline/bucketscript/BucketScriptPipelineAggregator.java b/server/src/main/java/org/elasticsearch/search/aggregations/pipeline/bucketscript/BucketScriptPipelineAggregator.java index 0a56ae2c1cb..42337fbce0f 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/pipeline/bucketscript/BucketScriptPipelineAggregator.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/pipeline/bucketscript/BucketScriptPipelineAggregator.java @@ -112,10 +112,11 @@ public class BucketScriptPipelineAggregator extends PipelineAggregator { } else { ExecutableScript executableScript = factory.newInstance(vars); Object returned = executableScript.run(); + // no need to check for self references since only numbers are valid if (returned == null) { newBuckets.add(bucket); } else { - if (!(returned instanceof Number)) { + if ((returned instanceof Number) == false) { throw new AggregationExecutionException("series_arithmetic script for reducer [" + name() + "] must return a Number"); } diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/support/ValuesSource.java b/server/src/main/java/org/elasticsearch/search/aggregations/support/ValuesSource.java index b5a109e89cb..6dc2758fa5c 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/support/ValuesSource.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/support/ValuesSource.java @@ -30,6 +30,7 @@ import org.apache.lucene.search.Scorer; import org.apache.lucene.util.Bits; import org.apache.lucene.util.BytesRef; import org.elasticsearch.common.lucene.ScorerAware; +import org.elasticsearch.common.util.CollectionUtils; import org.elasticsearch.index.fielddata.AbstractSortingNumericDocValues; import org.elasticsearch.index.fielddata.AtomicOrdinalsFieldData; import org.elasticsearch.index.fielddata.IndexFieldData; @@ -460,7 +461,9 @@ public abstract class ValuesSource { for (int i = 0; i < count; ++i) { final BytesRef value = bytesValues.nextValue(); script.setNextAggregationValue(value.utf8ToString()); - values[i].copyChars(script.run().toString()); + Object run = script.run(); + CollectionUtils.ensureNoSelfReferences(run); + values[i].copyChars(run.toString()); } sort(); return true; diff --git a/server/src/main/java/org/elasticsearch/search/aggregations/support/values/ScriptBytesValues.java b/server/src/main/java/org/elasticsearch/search/aggregations/support/values/ScriptBytesValues.java index 38950325daa..662d856603e 100644 --- a/server/src/main/java/org/elasticsearch/search/aggregations/support/values/ScriptBytesValues.java +++ b/server/src/main/java/org/elasticsearch/search/aggregations/support/values/ScriptBytesValues.java @@ -20,6 +20,7 @@ package org.elasticsearch.search.aggregations.support.values; import org.apache.lucene.search.Scorer; import org.elasticsearch.common.lucene.ScorerAware; +import org.elasticsearch.common.util.CollectionUtils; import org.elasticsearch.index.fielddata.SortedBinaryDocValues; import org.elasticsearch.index.fielddata.SortingBinaryDocValues; import org.elasticsearch.script.SearchScript; @@ -44,6 +45,7 @@ public class ScriptBytesValues extends SortingBinaryDocValues implements ScorerA if (o == null) { values[i].clear(); } else { + CollectionUtils.ensureNoSelfReferences(o); values[i].copyChars(o.toString()); } } diff --git a/server/src/main/java/org/elasticsearch/search/fetch/subphase/ScriptFieldsFetchSubPhase.java b/server/src/main/java/org/elasticsearch/search/fetch/subphase/ScriptFieldsFetchSubPhase.java index c45734108f5..948bcc3e0b3 100644 --- a/server/src/main/java/org/elasticsearch/search/fetch/subphase/ScriptFieldsFetchSubPhase.java +++ b/server/src/main/java/org/elasticsearch/search/fetch/subphase/ScriptFieldsFetchSubPhase.java @@ -22,6 +22,7 @@ import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.ReaderUtil; import org.elasticsearch.common.document.DocumentField; +import org.elasticsearch.common.util.CollectionUtils; import org.elasticsearch.script.SearchScript; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.fetch.FetchSubPhase; @@ -64,6 +65,7 @@ public final class ScriptFieldsFetchSubPhase implements FetchSubPhase { final Object value; try { value = leafScripts[i].run(); + CollectionUtils.ensureNoSelfReferences(value); } catch (RuntimeException e) { if (scriptFields.get(i).ignoreException()) { continue; diff --git a/server/src/main/java/org/elasticsearch/search/sort/ScriptSortBuilder.java b/server/src/main/java/org/elasticsearch/search/sort/ScriptSortBuilder.java index 331988a183f..99668515de5 100644 --- a/server/src/main/java/org/elasticsearch/search/sort/ScriptSortBuilder.java +++ b/server/src/main/java/org/elasticsearch/search/sort/ScriptSortBuilder.java @@ -32,6 +32,7 @@ import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.common.logging.Loggers; +import org.elasticsearch.common.util.CollectionUtils; import org.elasticsearch.common.xcontent.ConstructingObjectParser; import org.elasticsearch.common.xcontent.ObjectParser.ValueType; import org.elasticsearch.common.xcontent.XContentBuilder; @@ -341,7 +342,9 @@ public class ScriptSortBuilder extends SortBuilder { } @Override public BytesRef binaryValue() { - spare.copyChars(leafScript.run().toString()); + final Object run = leafScript.run(); + CollectionUtils.ensureNoSelfReferences(run); + spare.copyChars(run.toString()); return spare.get(); } }; diff --git a/server/src/test/java/org/elasticsearch/common/util/CollectionUtilsTests.java b/server/src/test/java/org/elasticsearch/common/util/CollectionUtilsTests.java index 8c192a2a350..2ca8189a972 100644 --- a/server/src/test/java/org/elasticsearch/common/util/CollectionUtilsTests.java +++ b/server/src/test/java/org/elasticsearch/common/util/CollectionUtilsTests.java @@ -25,16 +25,21 @@ import org.apache.lucene.util.BytesRefBuilder; import org.apache.lucene.util.Counter; import org.elasticsearch.test.ESTestCase; +import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.SortedSet; import java.util.TreeSet; +import static java.util.Collections.emptyMap; import static org.elasticsearch.common.util.CollectionUtils.eagerPartition; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; @@ -176,4 +181,15 @@ public class CollectionUtilsTests extends ESTestCase { eagerPartition(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12), 6) ); } + + public void testEnsureNoSelfReferences() { + CollectionUtils.ensureNoSelfReferences(emptyMap()); + CollectionUtils.ensureNoSelfReferences(null); + + Map map = new HashMap<>(); + map.put("field", map); + + IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> CollectionUtils.ensureNoSelfReferences(map)); + assertThat(e.getMessage(), containsString("Iterable object is self-referencing itself")); + } } diff --git a/server/src/test/java/org/elasticsearch/common/xcontent/BaseXContentTestCase.java b/server/src/test/java/org/elasticsearch/common/xcontent/BaseXContentTestCase.java index e368163a4e9..c7205b3200f 100644 --- a/server/src/test/java/org/elasticsearch/common/xcontent/BaseXContentTestCase.java +++ b/server/src/test/java/org/elasticsearch/common/xcontent/BaseXContentTestCase.java @@ -35,6 +35,7 @@ import org.elasticsearch.common.geo.GeoPoint; import org.elasticsearch.common.io.PathUtils; import org.elasticsearch.common.text.Text; import org.elasticsearch.common.unit.DistanceUnit; +import org.elasticsearch.common.util.CollectionUtils; import org.elasticsearch.common.xcontent.XContentParser.Token; import org.elasticsearch.test.ESTestCase; import org.hamcrest.Matcher; @@ -854,19 +855,19 @@ public abstract class BaseXContentTestCase extends ESTestCase { } public void testEnsureNoSelfReferences() throws IOException { - XContentBuilder.ensureNoSelfReferences(emptyMap()); - XContentBuilder.ensureNoSelfReferences(null); + CollectionUtils.ensureNoSelfReferences(emptyMap()); + CollectionUtils.ensureNoSelfReferences(null); Map map = new HashMap<>(); map.put("field", map); IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> builder().map(map)); - assertThat(e.getMessage(), containsString("Object has already been built and is self-referencing itself")); + assertThat(e.getMessage(), containsString("Iterable object is self-referencing itself")); } /** * Test that the same map written multiple times do not trigger the self-reference check in - * {@link XContentBuilder#ensureNoSelfReferences(Object)} + * {@link CollectionUtils#ensureNoSelfReferences(Object)} */ public void testRepeatedMapsAndNoSelfReferences() throws Exception { Map mapB = singletonMap("b", "B"); @@ -899,7 +900,7 @@ public abstract class BaseXContentTestCase extends ESTestCase { map1.put("map0", map0); // map 1 -> map 0 loop IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> builder().map(map0)); - assertThat(e.getMessage(), containsString("Object has already been built and is self-referencing itself")); + assertThat(e.getMessage(), containsString("Iterable object is self-referencing itself")); } public void testSelfReferencingMapsTwoLevels() throws IOException { @@ -917,7 +918,7 @@ public abstract class BaseXContentTestCase extends ESTestCase { map2.put("map0", map0); // map 2 -> map 0 loop IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> builder().map(map0)); - assertThat(e.getMessage(), containsString("Object has already been built and is self-referencing itself")); + assertThat(e.getMessage(), containsString("Iterable object is self-referencing itself")); } public void testSelfReferencingObjectsArray() throws IOException { @@ -930,13 +931,13 @@ public abstract class BaseXContentTestCase extends ESTestCase { .startObject() .field("field", values) .endObject()); - assertThat(e.getMessage(), containsString("Object has already been built and is self-referencing itself")); + assertThat(e.getMessage(), containsString("Iterable object is self-referencing itself")); e = expectThrows(IllegalArgumentException.class, () -> builder() .startObject() .array("field", values) .endObject()); - assertThat(e.getMessage(), containsString("Object has already been built and is self-referencing itself")); + assertThat(e.getMessage(), containsString("Iterable object is self-referencing itself")); } public void testSelfReferencingIterable() throws IOException { @@ -949,7 +950,7 @@ public abstract class BaseXContentTestCase extends ESTestCase { .startObject() .field("field", (Iterable) values) .endObject()); - assertThat(e.getMessage(), containsString("Object has already been built and is self-referencing itself")); + assertThat(e.getMessage(), containsString("Iterable object is self-referencing itself")); } public void testSelfReferencingIterableOneLevel() throws IOException { @@ -964,7 +965,7 @@ public abstract class BaseXContentTestCase extends ESTestCase { .startObject() .field("field", (Iterable) values) .endObject()); - assertThat(e.getMessage(), containsString("Object has already been built and is self-referencing itself")); + assertThat(e.getMessage(), containsString("Iterable object is self-referencing itself")); } public void testSelfReferencingIterableTwoLevels() throws IOException { @@ -984,7 +985,7 @@ public abstract class BaseXContentTestCase extends ESTestCase { map2.put("map0", map0); // map 2 -> map 0 loop IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> builder().map(map0)); - assertThat(e.getMessage(), containsString("Object has already been built and is self-referencing itself")); + assertThat(e.getMessage(), containsString("Iterable object is self-referencing itself")); } public void testChecksForDuplicates() throws Exception { From 049f29710e609818d3a4558988e91a8e0bafbbc3 Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Tue, 23 Jan 2018 12:14:23 -0500 Subject: [PATCH 10/14] Reindex: log more on rare test failure The test failure tracked by #26758 occurs when we cancel a running reindex request that has been sliced into many children. The main reindex response *looks* canceled but none of the children look canceled. This is super strange because for the main request to look canceled for any length of time one of the children has to be canceled. This change adds additional logging to the test so we have more to go on to debug this the next time it fails. --- .../index/reindex/CancelTests.java | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/modules/reindex/src/test/java/org/elasticsearch/index/reindex/CancelTests.java b/modules/reindex/src/test/java/org/elasticsearch/index/reindex/CancelTests.java index 3ad48d803a4..f21fb45ed7a 100644 --- a/modules/reindex/src/test/java/org/elasticsearch/index/reindex/CancelTests.java +++ b/modules/reindex/src/test/java/org/elasticsearch/index/reindex/CancelTests.java @@ -91,6 +91,7 @@ public class CancelTests extends ReindexTestCase { int numDocs = getNumShards(INDEX).numPrimaries * 10 * builder.request().getSlices(); ALLOWED_OPERATIONS.release(numDocs); + logger.debug("setting up [{}] docs", numDocs); indexRandom(true, false, true, IntStream.range(0, numDocs) .mapToObj(i -> client().prepareIndex(INDEX, TYPE, String.valueOf(i)).setSource("n", i)) .collect(Collectors.toList())); @@ -102,16 +103,21 @@ public class CancelTests extends ReindexTestCase { // Scroll by 1 so that cancellation is easier to control builder.source().setSize(1); - /* Allow a random number of the documents less the number of workers to be modified by the reindex action. That way at least one - * worker is blocked. */ + /* Allow a random number of the documents less the number of workers + * to be modified by the reindex action. That way at least one worker + * is blocked. */ int numModifiedDocs = randomIntBetween(builder.request().getSlices() * 2, numDocs); + logger.debug("chose to modify [{}] docs", numModifiedDocs); ALLOWED_OPERATIONS.release(numModifiedDocs - builder.request().getSlices()); // Now execute the reindex action... ActionFuture future = builder.execute(); - /* ... and waits for the indexing operation listeners to block. It is important to realize that some of the workers might have - * exhausted their slice while others might have quite a bit left to work on. We can't control that. */ + /* ... and wait for the indexing operation listeners to block. It + * is important to realize that some of the workers might have + * exhausted their slice while others might have quite a bit left + * to work on. We can't control that. */ + logger.debug("waiting for updates to be blocked"); awaitBusy(() -> ALLOWED_OPERATIONS.hasQueuedThreads() && ALLOWED_OPERATIONS.availablePermits() == 0); // Status should show the task running @@ -128,15 +134,19 @@ public class CancelTests extends ReindexTestCase { cancelTasksResponse.rethrowFailures("Cancel"); assertThat(cancelTasksResponse.getTasks(), hasSize(1)); - // The status should now show canceled. The request will still be in the list because it is (or its children are) still blocked. + /* The status should now show canceled. The request will still be in the + * list because it is (or its children are) still blocked. */ mainTask = client().admin().cluster().prepareGetTask(mainTask.getTaskId()).get().getTask().getTask(); status = (BulkByScrollTask.Status) mainTask.getStatus(); + logger.debug("asserting that parent is marked canceled {}", status); assertEquals(CancelTasksRequest.DEFAULT_REASON, status.getReasonCancelled()); + if (builder.request().getSlices() > 1) { boolean foundCancelled = false; ListTasksResponse sliceList = client().admin().cluster().prepareListTasks().setParentTaskId(mainTask.getTaskId()) .setDetailed(true).get(); sliceList.rethrowFailures("Fetch slice tasks"); + logger.debug("finding at least one canceled child among {}", sliceList.getTasks()); for (TaskInfo slice: sliceList.getTasks()) { BulkByScrollTask.Status sliceStatus = (BulkByScrollTask.Status) slice.getStatus(); if (sliceStatus.getReasonCancelled() == null) continue; @@ -146,7 +156,7 @@ public class CancelTests extends ReindexTestCase { assertTrue("Didn't find at least one sub task that was cancelled", foundCancelled); } - // Unblock the last operations + logger.debug("unblocking the blocked update"); ALLOWED_OPERATIONS.release(builder.request().getSlices()); // Checks that no more operations are executed From eded5bc4f3776c9841a4995972f29c6c07d81c46 Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Tue, 23 Jan 2018 13:35:23 -0500 Subject: [PATCH 11/14] Reindex: Wait for deletion in test The test failure tracked by #28053 occurs because we fail to get the failure response from the reindex on the first try and on our second try the delete index API call that was supposed to trigger the failure actually deletes the index during document creation. This causes the test to fail catastrophically. This PR attempts to wait for the failure to finish before the test moves on to the second attempt. The failure doesn't reproduce locally for me so I can't be sure that this helps at all with the failure, but it certainly feels like it should help some. Here is hoping this prevents similar failures in the future. --- .../elasticsearch/index/reindex/ReindexFailureTests.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/modules/reindex/src/test/java/org/elasticsearch/index/reindex/ReindexFailureTests.java b/modules/reindex/src/test/java/org/elasticsearch/index/reindex/ReindexFailureTests.java index f101b125382..f5e234f66ca 100644 --- a/modules/reindex/src/test/java/org/elasticsearch/index/reindex/ReindexFailureTests.java +++ b/modules/reindex/src/test/java/org/elasticsearch/index/reindex/ReindexFailureTests.java @@ -107,6 +107,14 @@ public class ReindexFailureTests extends ReindexTestCase { response.get(); logger.info("Didn't trigger a reindex failure on the {} attempt", attempt); attempt++; + /* + * In the past we've seen the delete of the source index + * actually take effect *during* the `indexDocs` call in + * the next step. This breaks things pretty disasterously + * so we *try* and wait for the delete to be fully + * complete here. + */ + assertBusy(() -> assertFalse(client().admin().indices().prepareExists("source").get().isExists())); } catch (ExecutionException e) { logger.info("Triggered a reindex failure on the {} attempt: {}", attempt, e.getMessage()); assertThat(e.getMessage(), From 7c5619a29a789c10e2b436f83a83484d1cda732b Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Tue, 23 Jan 2018 12:29:11 -0700 Subject: [PATCH 12/14] Fix spelling error --- docs/reference/query-dsl/query-string-syntax.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/query-dsl/query-string-syntax.asciidoc b/docs/reference/query-dsl/query-string-syntax.asciidoc index 8a7b394b2e8..c73543c99a1 100644 --- a/docs/reference/query-dsl/query-string-syntax.asciidoc +++ b/docs/reference/query-dsl/query-string-syntax.asciidoc @@ -56,7 +56,7 @@ match the query string `"a* b* c*"`. [WARNING] ======= Pure wildcards `\*` are rewritten to <> queries for efficiency. -As a consequence, the wildcard `"field:*"` would match documents with an emtpy value +As a consequence, the wildcard `"field:*"` would match documents with an empty value like the following: ``` { From b94500693815f0eb39f8e53e4d2fc99b27fa7d38 Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Tue, 23 Jan 2018 12:38:31 -0800 Subject: [PATCH 13/14] Completely remove Painless Type from AnalyzerCaster in favor of Java Class. (#28329) Second part in a series of PR's to remove Painless Type in favor of Java Class. This completely removes the Painless Type dependency from AnalyzerCaster. Both casting and promotion are now based on Java Class exclusively. This also allows AnalyzerCaster to be decoupled from Definition and make cast checks be static calls again. --- .../painless/AnalyzerCaster.java | 239 ++++++++---------- .../elasticsearch/painless/Definition.java | 38 ++- .../painless/node/AExpression.java | 5 +- .../painless/node/EAssignment.java | 43 ++-- .../elasticsearch/painless/node/EBinary.java | 37 ++- .../painless/node/ECapturingFunctionRef.java | 5 +- .../elasticsearch/painless/node/EComp.java | 24 +- .../painless/node/EConditional.java | 3 +- .../elasticsearch/painless/node/EElvis.java | 4 +- .../painless/node/EFunctionRef.java | 5 +- .../elasticsearch/painless/node/ELambda.java | 5 +- .../elasticsearch/painless/node/EUnary.java | 6 +- .../painless/node/SSubEachArray.java | 11 +- .../painless/node/SSubEachIterable.java | 3 +- .../painless/AnalyzerCasterTests.java | 93 ++++--- 15 files changed, 272 insertions(+), 249 deletions(-) diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/AnalyzerCaster.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/AnalyzerCaster.java index 7bae2c7fcad..abba62de39c 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/AnalyzerCaster.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/AnalyzerCaster.java @@ -20,7 +20,6 @@ package org.elasticsearch.painless; import org.elasticsearch.painless.Definition.Cast; -import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.Definition.def; import java.util.Objects; @@ -31,26 +30,9 @@ import java.util.Objects; */ public final class AnalyzerCaster { - private Definition definition; - - public AnalyzerCaster(Definition definition) { - this.definition = definition; - } - - public Cast getLegalCast(Location location, Type actualType, Type expectedType, boolean explicit, boolean internal) { - Objects.requireNonNull(actualType); - Objects.requireNonNull(expectedType); - - Class actual = actualType.clazz; - Class expected = expectedType.clazz; - - if (actualType.dynamic) { - actual = Definition.ObjectClassTodefClass(actual); - } - - if (expectedType.dynamic) { - expected = Definition.ObjectClassTodefClass(expected); - } + public static Cast getLegalCast(Location location, Class actual, Class expected, boolean explicit, boolean internal) { + Objects.requireNonNull(actual); + Objects.requireNonNull(expected); if (actual == expected) { return null; @@ -487,7 +469,7 @@ public final class AnalyzerCaster { } } - public Object constCast(Location location, final Object constant, final Cast cast) { + public static Object constCast(Location location, Object constant, Cast cast) { Class fsort = cast.from; Class tsort = cast.to; @@ -498,7 +480,7 @@ public final class AnalyzerCaster { } else if (fsort == char.class && tsort == String.class) { return Utility.charToString((char)constant); } else if (fsort.isPrimitive() && fsort != boolean.class && tsort.isPrimitive() && tsort != boolean.class) { - final Number number; + Number number; if (fsort == char.class) { number = (int)(char)constant; @@ -523,224 +505,201 @@ public final class AnalyzerCaster { } } - public Type promoteNumeric(Type from, boolean decimal) { - Class sort = from.clazz; - - if (from.dynamic) { - return definition.DefType; - } else if ((sort == double.class) && decimal) { - return definition.doubleType; - } else if ((sort == float.class) && decimal) { - return definition.floatType; - } else if (sort == long.class) { - return definition.longType; - } else if (sort == int.class || sort == char.class || sort == short.class || sort == byte.class) { - return definition.intType; + public static Class promoteNumeric(Class from, boolean decimal) { + if (from == def.class || from == double.class && decimal || from == float.class && decimal || from == long.class) { + return from; + } else if (from == int.class || from == char.class || from == short.class || from == byte.class) { + return int.class; } return null; } - public Type promoteNumeric(Type from0, Type from1, boolean decimal) { - Class sort0 = from0.clazz; - Class sort1 = from1.clazz; - - if (from0.dynamic || from1.dynamic) { - return definition.DefType; + public static Class promoteNumeric(Class from0, Class from1, boolean decimal) { + if (from0 == def.class || from1 == def.class) { + return def.class; } if (decimal) { - if (sort0 == double.class || sort1 == double.class) { - return definition.doubleType; - } else if (sort0 == float.class || sort1 == float.class) { - return definition.floatType; + if (from0 == double.class || from1 == double.class) { + return double.class; + } else if (from0 == float.class || from1 == float.class) { + return float.class; } } - if (sort0 == long.class || sort1 == long.class) { - return definition.longType; - } else if (sort0 == int.class || sort1 == int.class || - sort0 == char.class || sort1 == char.class || - sort0 == short.class || sort1 == short.class || - sort0 == byte.class || sort1 == byte.class) { - return definition.intType; + if (from0 == long.class || from1 == long.class) { + return long.class; + } else if (from0 == int.class || from1 == int.class || + from0 == char.class || from1 == char.class || + from0 == short.class || from1 == short.class || + from0 == byte.class || from1 == byte.class) { + return int.class; } return null; } - public Type promoteAdd(Type from0, Type from1) { - Class sort0 = from0.clazz; - Class sort1 = from1.clazz; - - if (sort0 == String.class || sort1 == String.class) { - return definition.StringType; + public static Class promoteAdd(Class from0, Class from1) { + if (from0 == String.class || from1 == String.class) { + return String.class; } return promoteNumeric(from0, from1, true); } - public Type promoteXor(Type from0, Type from1) { - Class sort0 = from0.clazz; - Class sort1 = from1.clazz; - - if (from0.dynamic || from1.dynamic) { - return definition.DefType; + public static Class promoteXor(Class from0, Class from1) { + if (from0 == def.class || from1 == def.class) { + return def.class; } - if (sort0 == boolean.class || sort1 == boolean.class) { - return definition.booleanType; + if (from0 == boolean.class || from1 == boolean.class) { + return boolean.class; } return promoteNumeric(from0, from1, false); } - public Type promoteEquality(Type from0, Type from1) { - Class sort0 = from0.clazz; - Class sort1 = from1.clazz; - - if (from0.dynamic || from1.dynamic) { - return definition.DefType; + public static Class promoteEquality(Class from0, Class from1) { + if (from0 == def.class || from1 == def.class) { + return def.class; } - if (sort0.isPrimitive() && sort1.isPrimitive()) { - if (sort0 == boolean.class && sort1 == boolean.class) { - return definition.booleanType; + if (from0.isPrimitive() && from1.isPrimitive()) { + if (from0 == boolean.class && from1 == boolean.class) { + return boolean.class; } return promoteNumeric(from0, from1, true); } - return definition.ObjectType; + return Object.class; } - public Type promoteConditional(Type from0, Type from1, Object const0, Object const1) { - if (from0.equals(from1)) { + public static Class promoteConditional(Class from0, Class from1, Object const0, Object const1) { + if (from0 == from1) { return from0; } - Class sort0 = from0.clazz; - Class sort1 = from1.clazz; - - if (from0.dynamic || from1.dynamic) { - return definition.DefType; + if (from0 == def.class || from1 == def.class) { + return def.class; } - if (sort0.isPrimitive() && sort1.isPrimitive()) { - if (sort0 == boolean.class && sort1 == boolean.class) { - return definition.booleanType; + if (from0.isPrimitive() && from1.isPrimitive()) { + if (from0 == boolean.class && from1 == boolean.class) { + return boolean.class; } - if (sort0 == double.class || sort1 == double.class) { - return definition.doubleType; - } else if (sort0 == float.class || sort1 == float.class) { - return definition.floatType; - } else if (sort0 == long.class || sort1 == long.class) { - return definition.longType; + if (from0 == double.class || from1 == double.class) { + return double.class; + } else if (from0 == float.class || from1 == float.class) { + return float.class; + } else if (from0 == long.class || from1 == long.class) { + return long.class; } else { - if (sort0 == byte.class) { - if (sort1 == byte.class) { - return definition.byteType; - } else if (sort1 == short.class) { + if (from0 == byte.class) { + if (from1 == byte.class) { + return byte.class; + } else if (from1 == short.class) { if (const1 != null) { final short constant = (short)const1; if (constant <= Byte.MAX_VALUE && constant >= Byte.MIN_VALUE) { - return definition.byteType; + return byte.class; } } - return definition.shortType; - } else if (sort1 == char.class) { - return definition.intType; - } else if (sort1 == int.class) { + return short.class; + } else if (from1 == char.class) { + return int.class; + } else if (from1 == int.class) { if (const1 != null) { final int constant = (int)const1; if (constant <= Byte.MAX_VALUE && constant >= Byte.MIN_VALUE) { - return definition.byteType; + return byte.class; } } - return definition.intType; + return int.class; } - } else if (sort0 == short.class) { - if (sort1 == byte.class) { + } else if (from0 == short.class) { + if (from1 == byte.class) { if (const0 != null) { final short constant = (short)const0; if (constant <= Byte.MAX_VALUE && constant >= Byte.MIN_VALUE) { - return definition.byteType; + return byte.class; } } - return definition.shortType; - } else if (sort1 == short.class) { - return definition.shortType; - } else if (sort1 == char.class) { - return definition.intType; - } else if (sort1 == int.class) { + return short.class; + } else if (from1 == short.class) { + return short.class; + } else if (from1 == char.class) { + return int.class; + } else if (from1 == int.class) { if (const1 != null) { final int constant = (int)const1; if (constant <= Short.MAX_VALUE && constant >= Short.MIN_VALUE) { - return definition.shortType; + return short.class; } } - return definition.intType; + return int.class; } - } else if (sort0 == char.class) { - if (sort1 == byte.class) { - return definition.intType; - } else if (sort1 == short.class) { - return definition.intType; - } else if (sort1 == char.class) { - return definition.charType; - } else if (sort1 == int.class) { + } else if (from0 == char.class) { + if (from1 == byte.class) { + return int.class; + } else if (from1 == short.class) { + return int.class; + } else if (from1 == char.class) { + return char.class; + } else if (from1 == int.class) { if (const1 != null) { final int constant = (int)const1; if (constant <= Character.MAX_VALUE && constant >= Character.MIN_VALUE) { - return definition.byteType; + return byte.class; } } - return definition.intType; + return int.class; } - } else if (sort0 == int.class) { - if (sort1 == byte.class) { + } else if (from0 == int.class) { + if (from1 == byte.class) { if (const0 != null) { final int constant = (int)const0; if (constant <= Byte.MAX_VALUE && constant >= Byte.MIN_VALUE) { - return definition.byteType; + return byte.class; } } - return definition.intType; - } else if (sort1 == short.class) { + return int.class; + } else if (from1 == short.class) { if (const0 != null) { final int constant = (int)const0; if (constant <= Short.MAX_VALUE && constant >= Short.MIN_VALUE) { - return definition.byteType; + return byte.class; } } - return definition.intType; - } else if (sort1 == char.class) { + return int.class; + } else if (from1 == char.class) { if (const0 != null) { final int constant = (int)const0; if (constant <= Character.MAX_VALUE && constant >= Character.MIN_VALUE) { - return definition.byteType; + return byte.class; } } - return definition.intType; - } else if (sort1 == int.class) { - return definition.intType; + return int.class; + } else if (from1 == int.class) { + return int.class; } } } @@ -750,6 +709,10 @@ public final class AnalyzerCaster { // TODO: to calculate the highest upper bound for the two types and return that. // TODO: However, for now we just return objectType that may require an extra cast. - return definition.ObjectType; + return Object.class; + } + + private AnalyzerCaster() { + } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Definition.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Definition.java index 52f0c2c6330..36c072570ec 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Definition.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Definition.java @@ -591,7 +591,39 @@ public final class Definition { return "def"; } - return clazz.getCanonicalName(); + return clazz.getCanonicalName().replace('$', '.'); + } + + public Type ClassToType(Class clazz) { + if (clazz == null) { + return null; + } else if (clazz.isArray()) { + Class component = clazz.getComponentType(); + int dimensions = 1; + + while (component.isArray()) { + component = component.getComponentType(); + ++dimensions; + } + + if (clazz == def.class) { + return getType(structsMap.get("def"), dimensions); + } else { + return getType(runtimeMap.get(clazz).struct, dimensions); + } + } else if (clazz == def.class) { + return getType(structsMap.get("def"), 0); + } + + return getType(structsMap.get(ClassToName(clazz)), 0); + } + + public static Class TypeToClass (Type type) { + if (type.dynamic) { + return ObjectClassTodefClass(type.clazz); + } + + return type.clazz; } public RuntimeClass getRuntimeClass(Class clazz) { @@ -631,8 +663,6 @@ public final class Definition { private final Map structsMap; private final Map simpleTypesMap; - public AnalyzerCaster caster; - public Definition(List whitelists) { structsMap = new HashMap<>(); simpleTypesMap = new HashMap<>(); @@ -814,8 +844,6 @@ public final class Definition { IteratorType = getType("Iterator"); ArrayListType = getType("ArrayList"); HashMapType = getType("HashMap"); - - caster = new AnalyzerCaster(this); } private void addStruct(ClassLoader whitelistClassLoader, Whitelist.Struct whitelistStruct) { diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AExpression.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AExpression.java index 2ca0b265430..eaa13ea9a8b 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AExpression.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AExpression.java @@ -119,7 +119,8 @@ public abstract class AExpression extends ANode { * @return The new child node for the parent node calling this method. */ AExpression cast(Locals locals) { - Cast cast = locals.getDefinition().caster.getLegalCast(location, actual, expected, explicit, internal); + Cast cast = + AnalyzerCaster.getLegalCast(location, Definition.TypeToClass(actual), Definition.TypeToClass(expected), explicit, internal); if (cast == null) { if (constant == null || this instanceof EConstant) { @@ -167,7 +168,7 @@ public abstract class AExpression extends ANode { // from this node because the output data for the EConstant // will already be the same. - constant = locals.getDefinition().caster.constCast(location, constant, cast); + constant = AnalyzerCaster.constCast(location, constant, cast); EConstant econstant = new EConstant(location, constant); econstant.analyze(locals); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java index 873f109e72d..45ca4601e96 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EAssignment.java @@ -19,7 +19,10 @@ package org.elasticsearch.painless.node; + +import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.DefBootstrap; +import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition.Cast; import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.Globals; @@ -139,33 +142,41 @@ public final class EAssignment extends AExpression { boolean shift = false; if (operation == Operation.MUL) { - promote = locals.getDefinition().caster.promoteNumeric(lhs.actual, rhs.actual, true); + promote = locals.getDefinition().ClassToType( + AnalyzerCaster.promoteNumeric(Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual), true)); } else if (operation == Operation.DIV) { - promote = locals.getDefinition().caster.promoteNumeric(lhs.actual, rhs.actual, true); + promote = locals.getDefinition().ClassToType( + AnalyzerCaster.promoteNumeric(Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual), true)); } else if (operation == Operation.REM) { - promote = locals.getDefinition().caster.promoteNumeric(lhs.actual, rhs.actual, true); + promote = locals.getDefinition().ClassToType( + AnalyzerCaster.promoteNumeric(Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual), true)); } else if (operation == Operation.ADD) { - promote = locals.getDefinition().caster.promoteAdd(lhs.actual, rhs.actual); + promote = locals.getDefinition().ClassToType( + AnalyzerCaster.promoteAdd(Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual))); } else if (operation == Operation.SUB) { - promote = locals.getDefinition().caster.promoteNumeric(lhs.actual, rhs.actual, true); + promote = locals.getDefinition().ClassToType( + AnalyzerCaster.promoteNumeric(Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual), true)); } else if (operation == Operation.LSH) { - promote = locals.getDefinition().caster.promoteNumeric(lhs.actual, false); - shiftDistance = locals.getDefinition().caster.promoteNumeric(rhs.actual, false); + promote = locals.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(lhs.actual), false)); + shiftDistance = locals.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(rhs.actual), false)); shift = true; } else if (operation == Operation.RSH) { - promote = locals.getDefinition().caster.promoteNumeric(lhs.actual, false); - shiftDistance = locals.getDefinition().caster.promoteNumeric(rhs.actual, false); + promote = locals.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(lhs.actual), false)); + shiftDistance = locals.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(rhs.actual), false)); shift = true; } else if (operation == Operation.USH) { - promote = locals.getDefinition().caster.promoteNumeric(lhs.actual, false); - shiftDistance = locals.getDefinition().caster.promoteNumeric(rhs.actual, false); + promote = locals.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(lhs.actual), false)); + shiftDistance = locals.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(rhs.actual), false)); shift = true; } else if (operation == Operation.BWAND) { - promote = locals.getDefinition().caster.promoteXor(lhs.actual, rhs.actual); + promote = locals.getDefinition().ClassToType( + AnalyzerCaster.promoteXor(Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual))); } else if (operation == Operation.XOR) { - promote = locals.getDefinition().caster.promoteXor(lhs.actual, rhs.actual); + promote = locals.getDefinition().ClassToType( + AnalyzerCaster.promoteXor(Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual))); } else if (operation == Operation.BWOR) { - promote = locals.getDefinition().caster.promoteXor(lhs.actual, rhs.actual); + promote = locals.getDefinition().ClassToType( + AnalyzerCaster.promoteXor(Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual))); } else { throw createError(new IllegalStateException("Illegal tree structure.")); } @@ -199,8 +210,8 @@ public final class EAssignment extends AExpression { rhs = rhs.cast(locals); - there = locals.getDefinition().caster.getLegalCast(location, lhs.actual, promote, false, false); - back = locals.getDefinition().caster.getLegalCast(location, promote, lhs.actual, true, false); + there = AnalyzerCaster.getLegalCast(location, Definition.TypeToClass(lhs.actual), Definition.TypeToClass(promote), false, false); + back = AnalyzerCaster.getLegalCast(location, Definition.TypeToClass(promote), Definition.TypeToClass(lhs.actual), true, false); this.statement = true; this.actual = read ? lhs.actual : locals.getDefinition().voidType; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java index df92d72a3c0..55c2145acd8 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java @@ -19,6 +19,7 @@ package org.elasticsearch.painless.node; +import org.elasticsearch.painless.AnalyzerCaster; import org.elasticsearch.painless.DefBootstrap; import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition.Type; @@ -101,7 +102,8 @@ public final class EBinary extends AExpression { left.analyze(variables); right.analyze(variables); - promote = variables.getDefinition().caster.promoteNumeric(left.actual, right.actual, true); + promote = variables.getDefinition().ClassToType( + AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), true)); if (promote == null) { throw createError(new ClassCastException("Cannot apply multiply [*] to types " + @@ -145,7 +147,8 @@ public final class EBinary extends AExpression { left.analyze(variables); right.analyze(variables); - promote = variables.getDefinition().caster.promoteNumeric(left.actual, right.actual, true); + promote = variables.getDefinition().ClassToType( + AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), true)); if (promote == null) { throw createError(new ClassCastException("Cannot apply divide [/] to types " + @@ -194,7 +197,8 @@ public final class EBinary extends AExpression { left.analyze(variables); right.analyze(variables); - promote = variables.getDefinition().caster.promoteNumeric(left.actual, right.actual, true); + promote = variables.getDefinition().ClassToType( + AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), true)); if (promote == null) { throw createError(new ClassCastException("Cannot apply remainder [%] to types " + @@ -243,7 +247,8 @@ public final class EBinary extends AExpression { left.analyze(variables); right.analyze(variables); - promote = variables.getDefinition().caster.promoteAdd(left.actual, right.actual); + promote = variables.getDefinition().ClassToType( + AnalyzerCaster.promoteAdd(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual))); if (promote == null) { throw createError(new ClassCastException("Cannot apply add [+] to types " + @@ -303,7 +308,8 @@ public final class EBinary extends AExpression { left.analyze(variables); right.analyze(variables); - promote = variables.getDefinition().caster.promoteNumeric(left.actual, right.actual, true); + promote = variables.getDefinition().ClassToType( + AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), true)); if (promote == null) { throw createError(new ClassCastException("Cannot apply subtract [-] to types " + @@ -362,8 +368,8 @@ public final class EBinary extends AExpression { left.analyze(variables); right.analyze(variables); - Type lhspromote = variables.getDefinition().caster.promoteNumeric(left.actual, false); - Type rhspromote = variables.getDefinition().caster.promoteNumeric(right.actual, false); + Type lhspromote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), false)); + Type rhspromote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(right.actual), false)); if (lhspromote == null || rhspromote == null) { throw createError(new ClassCastException("Cannot apply left shift [<<] to types " + @@ -411,8 +417,8 @@ public final class EBinary extends AExpression { left.analyze(variables); right.analyze(variables); - Type lhspromote = variables.getDefinition().caster.promoteNumeric(left.actual, false); - Type rhspromote = variables.getDefinition().caster.promoteNumeric(right.actual, false); + Type lhspromote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), false)); + Type rhspromote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(right.actual), false)); if (lhspromote == null || rhspromote == null) { throw createError(new ClassCastException("Cannot apply right shift [>>] to types " + @@ -460,8 +466,8 @@ public final class EBinary extends AExpression { left.analyze(variables); right.analyze(variables); - Type lhspromote = variables.getDefinition().caster.promoteNumeric(left.actual, false); - Type rhspromote = variables.getDefinition().caster.promoteNumeric(right.actual, false); + Type lhspromote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), false)); + Type rhspromote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(right.actual), false)); actual = promote = lhspromote; shiftDistance = rhspromote; @@ -509,7 +515,8 @@ public final class EBinary extends AExpression { left.analyze(variables); right.analyze(variables); - promote = variables.getDefinition().caster.promoteNumeric(left.actual, right.actual, false); + promote = variables.getDefinition().ClassToType( + AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), false)); if (promote == null) { throw createError(new ClassCastException("Cannot apply and [&] to types " + @@ -550,7 +557,8 @@ public final class EBinary extends AExpression { left.analyze(variables); right.analyze(variables); - promote = variables.getDefinition().caster.promoteXor(left.actual, right.actual); + promote = variables.getDefinition().ClassToType( + AnalyzerCaster.promoteXor(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual))); if (promote == null) { throw createError(new ClassCastException("Cannot apply xor [^] to types " + @@ -592,7 +600,8 @@ public final class EBinary extends AExpression { left.analyze(variables); right.analyze(variables); - promote = variables.getDefinition().caster.promoteNumeric(left.actual, right.actual, false); + promote = variables.getDefinition().ClassToType( + AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), false)); if (promote == null) { throw createError(new ClassCastException("Cannot apply or [|] to types " + diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECapturingFunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECapturingFunctionRef.java index 564fcef8eef..e736b2779f9 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECapturingFunctionRef.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECapturingFunctionRef.java @@ -82,11 +82,12 @@ public final class ECapturingFunctionRef extends AExpression implements ILambda for (int i = 0; i < ref.interfaceMethod.arguments.size(); ++i) { Definition.Type from = ref.interfaceMethod.arguments.get(i); Definition.Type to = ref.delegateMethod.arguments.get(i); - locals.getDefinition().caster.getLegalCast(location, from, to, false, true); + AnalyzerCaster.getLegalCast(location, Definition.TypeToClass(from), Definition.TypeToClass(to), false, true); } if (ref.interfaceMethod.rtn.equals(locals.getDefinition().voidType) == false) { - locals.getDefinition().caster.getLegalCast(location, ref.delegateMethod.rtn, ref.interfaceMethod.rtn, false, true); + AnalyzerCaster.getLegalCast(location, + Definition.TypeToClass(ref.delegateMethod.rtn), Definition.TypeToClass(ref.interfaceMethod.rtn), false, true); } } catch (IllegalArgumentException e) { throw createError(e); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java index 020ea48cd4c..a7bb57a1a35 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java @@ -89,7 +89,8 @@ public final class EComp extends AExpression { left.analyze(variables); right.analyze(variables); - promotedType = variables.getDefinition().caster.promoteEquality(left.actual, right.actual); + promotedType = variables.getDefinition().ClassToType( + AnalyzerCaster.promoteEquality(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual))); if (promotedType == null) { throw createError(new ClassCastException("Cannot apply equals [==] to types " + @@ -140,7 +141,8 @@ public final class EComp extends AExpression { left.analyze(variables); right.analyze(variables); - promotedType = variables.getDefinition().caster.promoteEquality(left.actual, right.actual); + promotedType = variables.getDefinition().ClassToType( + AnalyzerCaster.promoteEquality(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual))); if (promotedType == null) { throw createError(new ClassCastException("Cannot apply reference equals [===] to types " + @@ -182,7 +184,8 @@ public final class EComp extends AExpression { left.analyze(variables); right.analyze(variables); - promotedType = variables.getDefinition().caster.promoteEquality(left.actual, right.actual); + promotedType = variables.getDefinition().ClassToType( + AnalyzerCaster.promoteEquality(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual))); if (promotedType == null) { throw createError(new ClassCastException("Cannot apply not equals [!=] to types " + @@ -233,7 +236,8 @@ public final class EComp extends AExpression { left.analyze(variables); right.analyze(variables); - promotedType = variables.getDefinition().caster.promoteEquality(left.actual, right.actual); + promotedType = variables.getDefinition().ClassToType( + AnalyzerCaster.promoteEquality(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual))); if (promotedType == null) { throw createError(new ClassCastException("Cannot apply reference not equals [!==] to types " + @@ -275,7 +279,8 @@ public final class EComp extends AExpression { left.analyze(variables); right.analyze(variables); - promotedType = variables.getDefinition().caster.promoteNumeric(left.actual, right.actual, true); + promotedType = variables.getDefinition().ClassToType( + AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), true)); if (promotedType == null) { throw createError(new ClassCastException("Cannot apply greater than or equals [>=] to types " + @@ -316,7 +321,8 @@ public final class EComp extends AExpression { left.analyze(variables); right.analyze(variables); - promotedType = variables.getDefinition().caster.promoteNumeric(left.actual, right.actual, true); + promotedType = variables.getDefinition().ClassToType( + AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), true)); if (promotedType == null) { throw createError(new ClassCastException("Cannot apply greater than [>] to types " + @@ -357,7 +363,8 @@ public final class EComp extends AExpression { left.analyze(variables); right.analyze(variables); - promotedType = variables.getDefinition().caster.promoteNumeric(left.actual, right.actual, true); + promotedType = variables.getDefinition().ClassToType( + AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), true)); if (promotedType == null) { throw createError(new ClassCastException("Cannot apply less than or equals [<=] to types " + @@ -398,7 +405,8 @@ public final class EComp extends AExpression { left.analyze(variables); right.analyze(variables); - promotedType = variables.getDefinition().caster.promoteNumeric(left.actual, right.actual, true); + promotedType = variables.getDefinition().ClassToType( + AnalyzerCaster.promoteNumeric(Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), true)); if (promotedType == null) { throw createError(new ClassCastException("Cannot apply less than [>=] to types " + diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConditional.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConditional.java index 571e57cad24..30a3d0d773f 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConditional.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConditional.java @@ -79,7 +79,8 @@ public final class EConditional extends AExpression { right.analyze(locals); if (expected == null) { - final Type promote = locals.getDefinition().caster.promoteConditional(left.actual, right.actual, left.constant, right.constant); + Type promote = locals.getDefinition().ClassToType(AnalyzerCaster.promoteConditional( + Definition.TypeToClass(left.actual), Definition.TypeToClass(right.actual), left.constant, right.constant)); left.expected = promote; right.expected = promote; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EElvis.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EElvis.java index e9816c524bf..6005a326fe9 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EElvis.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EElvis.java @@ -20,6 +20,7 @@ package org.elasticsearch.painless.node; import org.elasticsearch.painless.AnalyzerCaster; +import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; @@ -81,7 +82,8 @@ public class EElvis extends AExpression { } if (expected == null) { - final Type promote = locals.getDefinition().caster.promoteConditional(lhs.actual, rhs.actual, lhs.constant, rhs.constant); + Type promote = locals.getDefinition().ClassToType(AnalyzerCaster.promoteConditional( + Definition.TypeToClass(lhs.actual), Definition.TypeToClass(rhs.actual), lhs.constant, rhs.constant)); lhs.expected = promote; rhs.expected = promote; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java index ffbb344f29c..13289809e49 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java @@ -82,11 +82,12 @@ public final class EFunctionRef extends AExpression implements ILambda { for (int i = 0; i < interfaceMethod.arguments.size(); ++i) { Definition.Type from = interfaceMethod.arguments.get(i); Definition.Type to = delegateMethod.arguments.get(i); - locals.getDefinition().caster.getLegalCast(location, from, to, false, true); + AnalyzerCaster.getLegalCast(location, Definition.TypeToClass(from), Definition.TypeToClass(to), false, true); } if (interfaceMethod.rtn.equals(locals.getDefinition().voidType) == false) { - locals.getDefinition().caster.getLegalCast(location, delegateMethod.rtn, interfaceMethod.rtn, false, true); + AnalyzerCaster.getLegalCast( + location, Definition.TypeToClass(delegateMethod.rtn), Definition.TypeToClass(interfaceMethod.rtn), false, true); } } else { // whitelist lookup diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java index 07de9138e7c..68950f5ea2a 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ELambda.java @@ -192,11 +192,12 @@ public final class ELambda extends AExpression implements ILambda { for (int i = 0; i < interfaceMethod.arguments.size(); ++i) { Type from = interfaceMethod.arguments.get(i); Type to = desugared.parameters.get(i + captures.size()).type; - locals.getDefinition().caster.getLegalCast(location, from, to, false, true); + AnalyzerCaster.getLegalCast(location, Definition.TypeToClass(from), Definition.TypeToClass(to), false, true); } if (interfaceMethod.rtn.equals(locals.getDefinition().voidType) == false) { - locals.getDefinition().caster.getLegalCast(location, desugared.rtnType, interfaceMethod.rtn, false, true); + AnalyzerCaster.getLegalCast( + location, Definition.TypeToClass(desugared.rtnType), Definition.TypeToClass(interfaceMethod.rtn), false, true); } actual = expected; diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java index e9971b538f5..aa81407819e 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java @@ -90,7 +90,7 @@ public final class EUnary extends AExpression { void analyzeBWNot(Locals variables) { child.analyze(variables); - promote = variables.getDefinition().caster.promoteNumeric(child.actual, false); + promote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(child.actual), false)); if (promote == null) { throw createError(new ClassCastException("Cannot apply not [~] to type [" + child.actual.name + "].")); @@ -121,7 +121,7 @@ public final class EUnary extends AExpression { void analyzerAdd(Locals variables) { child.analyze(variables); - promote = variables.getDefinition().caster.promoteNumeric(child.actual, true); + promote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(child.actual), true)); if (promote == null) { throw createError(new ClassCastException("Cannot apply positive [+] to type [" + child.actual.name + "].")); @@ -156,7 +156,7 @@ public final class EUnary extends AExpression { void analyzerSub(Locals variables) { child.analyze(variables); - promote = variables.getDefinition().caster.promoteNumeric(child.actual, true); + promote = variables.getDefinition().ClassToType(AnalyzerCaster.promoteNumeric(Definition.TypeToClass(child.actual), true)); if (promote == null) { throw createError(new ClassCastException("Cannot apply negative [-] to type [" + child.actual.name + "].")); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachArray.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachArray.java index 09c73c525be..a4c2eb8cd22 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachArray.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachArray.java @@ -64,13 +64,10 @@ final class SSubEachArray extends AStatement { void analyze(Locals locals) { // We must store the array and index as variables for securing slots on the stack, and // also add the location offset to make the names unique in case of nested for each loops. - array = locals.addVariable(location, expression.actual, "#array" + location.getOffset(), - true); - index = locals.addVariable(location, locals.getDefinition().intType, "#index" + location.getOffset(), - true); - indexed = locals.getDefinition().getType(expression.actual.struct, - expression.actual.dimensions - 1); - cast = locals.getDefinition().caster.getLegalCast(location, indexed, variable.type, true, true); + array = locals.addVariable(location, expression.actual, "#array" + location.getOffset(), true); + index = locals.addVariable(location, locals.getDefinition().intType, "#index" + location.getOffset(), true); + indexed = locals.getDefinition().getType(expression.actual.struct, expression.actual.dimensions - 1); + cast = AnalyzerCaster.getLegalCast(location, Definition.TypeToClass(indexed), Definition.TypeToClass(variable.type), true, true); } @Override diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachIterable.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachIterable.java index a51a459f0f3..26fb4a2f845 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachIterable.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSubEachIterable.java @@ -25,6 +25,7 @@ import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Definition.Cast; import org.elasticsearch.painless.Definition.Method; import org.elasticsearch.painless.Definition.MethodKey; +import org.elasticsearch.painless.Definition.def; import org.elasticsearch.painless.Globals; import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals.Variable; @@ -85,7 +86,7 @@ final class SSubEachIterable extends AStatement { } } - cast = locals.getDefinition().caster.getLegalCast(location, locals.getDefinition().DefType, variable.type, true, true); + cast = AnalyzerCaster.getLegalCast(location, def.class, Definition.TypeToClass(variable.type), true, true); } @Override diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/AnalyzerCasterTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/AnalyzerCasterTests.java index b8fe2486017..69abc3481a1 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/AnalyzerCasterTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/AnalyzerCasterTests.java @@ -20,7 +20,6 @@ package org.elasticsearch.painless; import org.elasticsearch.painless.Definition.Cast; -import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.spi.Whitelist; import org.elasticsearch.test.ESTestCase; @@ -28,73 +27,73 @@ public class AnalyzerCasterTests extends ESTestCase { private static final Definition definition = new Definition(Whitelist.BASE_WHITELISTS); - private static void assertCast(Type actual, Type expected, boolean mustBeExplicit) { + private static void assertCast(Class actual, Class expected, boolean mustBeExplicit) { Location location = new Location("dummy", 0); if (actual.equals(expected)) { assertFalse(mustBeExplicit); - assertNull(definition.caster.getLegalCast(location, actual, expected, false, false)); - assertNull(definition.caster.getLegalCast(location, actual, expected, true, false)); + assertNull(AnalyzerCaster.getLegalCast(location, actual, expected, false, false)); + assertNull(AnalyzerCaster.getLegalCast(location, actual, expected, true, false)); return; } - Cast cast = definition.caster.getLegalCast(location, actual, expected, true, false); - assertEquals(actual.clazz, cast.from); - assertEquals(expected.clazz, cast.to); + Cast cast = AnalyzerCaster.getLegalCast(location, actual, expected, true, false); + assertEquals(actual, cast.from); + assertEquals(expected, cast.to); if (mustBeExplicit) { ClassCastException error = expectThrows(ClassCastException.class, - () -> definition.caster.getLegalCast(location, actual, expected, false, false)); + () -> AnalyzerCaster.getLegalCast(location, actual, expected, false, false)); assertTrue(error.getMessage().startsWith("Cannot cast")); } else { - cast = definition.caster.getLegalCast(location, actual, expected, false, false); - assertEquals(actual.clazz, cast.from); - assertEquals(expected.clazz, cast.to); + cast = AnalyzerCaster.getLegalCast(location, actual, expected, false, false); + assertEquals(actual, cast.from); + assertEquals(expected, cast.to); } } public void testNumericCasts() { - assertCast(definition.byteType, definition.byteType, false); - assertCast(definition.byteType, definition.shortType, false); - assertCast(definition.byteType, definition.intType, false); - assertCast(definition.byteType, definition.longType, false); - assertCast(definition.byteType, definition.floatType, false); - assertCast(definition.byteType, definition.doubleType, false); + assertCast(byte.class, byte.class, false); + assertCast(byte.class, short.class, false); + assertCast(byte.class, int.class, false); + assertCast(byte.class, long.class, false); + assertCast(byte.class, float.class, false); + assertCast(byte.class, double.class, false); - assertCast(definition.shortType, definition.byteType, true); - assertCast(definition.shortType, definition.shortType, false); - assertCast(definition.shortType, definition.intType, false); - assertCast(definition.shortType, definition.longType, false); - assertCast(definition.shortType, definition.floatType, false); - assertCast(definition.shortType, definition.doubleType, false); + assertCast(short.class, byte.class, true); + assertCast(short.class, short.class, false); + assertCast(short.class, int.class, false); + assertCast(short.class, long.class, false); + assertCast(short.class, float.class, false); + assertCast(short.class, double.class, false); - assertCast(definition.intType, definition.byteType, true); - assertCast(definition.intType, definition.shortType, true); - assertCast(definition.intType, definition.intType, false); - assertCast(definition.intType, definition.longType, false); - assertCast(definition.intType, definition.floatType, false); - assertCast(definition.intType, definition.doubleType, false); + assertCast(int.class, byte.class, true); + assertCast(int.class, short.class, true); + assertCast(int.class, int.class, false); + assertCast(int.class, long.class, false); + assertCast(int.class, float.class, false); + assertCast(int.class, double.class, false); - assertCast(definition.longType, definition.byteType, true); - assertCast(definition.longType, definition.shortType, true); - assertCast(definition.longType, definition.intType, true); - assertCast(definition.longType, definition.longType, false); - assertCast(definition.longType, definition.floatType, false); - assertCast(definition.longType, definition.doubleType, false); + assertCast(long.class, byte.class, true); + assertCast(long.class, short.class, true); + assertCast(long.class, int.class, true); + assertCast(long.class, long.class, false); + assertCast(long.class, float.class, false); + assertCast(long.class, double.class, false); - assertCast(definition.floatType, definition.byteType, true); - assertCast(definition.floatType, definition.shortType, true); - assertCast(definition.floatType, definition.intType, true); - assertCast(definition.floatType, definition.longType, true); - assertCast(definition.floatType, definition.floatType, false); - assertCast(definition.floatType, definition.doubleType, false); + assertCast(float.class, byte.class, true); + assertCast(float.class, short.class, true); + assertCast(float.class, int.class, true); + assertCast(float.class, long.class, true); + assertCast(float.class, float.class, false); + assertCast(float.class, double.class, false); - assertCast(definition.doubleType, definition.byteType, true); - assertCast(definition.doubleType, definition.shortType, true); - assertCast(definition.doubleType, definition.intType, true); - assertCast(definition.doubleType, definition.longType, true); - assertCast(definition.doubleType, definition.floatType, true); - assertCast(definition.doubleType, definition.doubleType, false); + assertCast(double.class, byte.class, true); + assertCast(double.class, short.class, true); + assertCast(double.class, int.class, true); + assertCast(double.class, long.class, true); + assertCast(double.class, float.class, true); + assertCast(double.class, double.class, false); } } From c675407a70dea661e7c7a53fa75ba458f1f8dc0a Mon Sep 17 00:00:00 2001 From: kel Date: Wed, 24 Jan 2018 14:32:46 +0800 Subject: [PATCH 14/14] Remove redundant argument for buildConfiguration of s3 plugin (#28281) --- .../repositories/s3/InternalAwsS3Service.java | 4 +-- .../s3/AwsS3ServiceImplTests.java | 27 +++++++++---------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/plugins/repository-s3/src/main/java/org/elasticsearch/repositories/s3/InternalAwsS3Service.java b/plugins/repository-s3/src/main/java/org/elasticsearch/repositories/s3/InternalAwsS3Service.java index 2b21a81d91f..d70ed9ea9aa 100644 --- a/plugins/repository-s3/src/main/java/org/elasticsearch/repositories/s3/InternalAwsS3Service.java +++ b/plugins/repository-s3/src/main/java/org/elasticsearch/repositories/s3/InternalAwsS3Service.java @@ -73,7 +73,7 @@ class InternalAwsS3Service extends AbstractLifecycleComponent implements AwsS3Se logger.debug("creating S3 client with client_name [{}], endpoint [{}]", clientName, clientSettings.endpoint); AWSCredentialsProvider credentials = buildCredentials(logger, deprecationLogger, clientSettings, repositorySettings); - ClientConfiguration configuration = buildConfiguration(clientSettings, repositorySettings); + ClientConfiguration configuration = buildConfiguration(clientSettings); client = new AmazonS3Client(credentials, configuration); @@ -86,7 +86,7 @@ class InternalAwsS3Service extends AbstractLifecycleComponent implements AwsS3Se } // pkg private for tests - static ClientConfiguration buildConfiguration(S3ClientSettings clientSettings, Settings repositorySettings) { + static ClientConfiguration buildConfiguration(S3ClientSettings clientSettings) { ClientConfiguration clientConfiguration = new ClientConfiguration(); // the response metadata cache is only there for diagnostics purposes, // but can force objects from every response to the old generation. diff --git a/plugins/repository-s3/src/test/java/org/elasticsearch/repositories/s3/AwsS3ServiceImplTests.java b/plugins/repository-s3/src/test/java/org/elasticsearch/repositories/s3/AwsS3ServiceImplTests.java index f85f2eb6f32..18c701f5fc1 100644 --- a/plugins/repository-s3/src/test/java/org/elasticsearch/repositories/s3/AwsS3ServiceImplTests.java +++ b/plugins/repository-s3/src/test/java/org/elasticsearch/repositories/s3/AwsS3ServiceImplTests.java @@ -95,7 +95,7 @@ public class AwsS3ServiceImplTests extends ESTestCase { } public void testAWSDefaultConfiguration() { - launchAWSConfigurationTest(Settings.EMPTY, Settings.EMPTY, Protocol.HTTPS, null, -1, null, null, 3, + launchAWSConfigurationTest(Settings.EMPTY, Protocol.HTTPS, null, -1, null, null, 3, ClientConfiguration.DEFAULT_THROTTLE_RETRIES, ClientConfiguration.DEFAULT_SOCKET_TIMEOUT); } @@ -110,7 +110,7 @@ public class AwsS3ServiceImplTests extends ESTestCase { .put("s3.client.default.proxy.port", 8080) .put("s3.client.default.read_timeout", "10s") .build(); - launchAWSConfigurationTest(settings, Settings.EMPTY, Protocol.HTTP, "aws_proxy_host", 8080, "aws_proxy_username", + launchAWSConfigurationTest(settings, Protocol.HTTP, "aws_proxy_host", 8080, "aws_proxy_username", "aws_proxy_password", 3, ClientConfiguration.DEFAULT_THROTTLE_RETRIES, 10000); } @@ -118,7 +118,7 @@ public class AwsS3ServiceImplTests extends ESTestCase { Settings settings = Settings.builder() .put("s3.client.default.max_retries", 5) .build(); - launchAWSConfigurationTest(settings, Settings.EMPTY, Protocol.HTTPS, null, -1, null, + launchAWSConfigurationTest(settings, Protocol.HTTPS, null, -1, null, null, 5, ClientConfiguration.DEFAULT_THROTTLE_RETRIES, 50000); } @@ -126,22 +126,21 @@ public class AwsS3ServiceImplTests extends ESTestCase { final boolean throttling = randomBoolean(); Settings settings = Settings.builder().put("s3.client.default.use_throttle_retries", throttling).build(); - launchAWSConfigurationTest(settings, Settings.EMPTY, Protocol.HTTPS, null, -1, null, null, 3, throttling, 50000); + launchAWSConfigurationTest(settings, Protocol.HTTPS, null, -1, null, null, 3, throttling, 50000); } private void launchAWSConfigurationTest(Settings settings, - Settings singleRepositorySettings, - Protocol expectedProtocol, - String expectedProxyHost, - int expectedProxyPort, - String expectedProxyUsername, - String expectedProxyPassword, - Integer expectedMaxRetries, - boolean expectedUseThrottleRetries, - int expectedReadTimeout) { + Protocol expectedProtocol, + String expectedProxyHost, + int expectedProxyPort, + String expectedProxyUsername, + String expectedProxyPassword, + Integer expectedMaxRetries, + boolean expectedUseThrottleRetries, + int expectedReadTimeout) { S3ClientSettings clientSettings = S3ClientSettings.getClientSettings(settings, "default"); - ClientConfiguration configuration = InternalAwsS3Service.buildConfiguration(clientSettings, singleRepositorySettings); + ClientConfiguration configuration = InternalAwsS3Service.buildConfiguration(clientSettings); assertThat(configuration.getResponseMetadataCacheSize(), is(0)); assertThat(configuration.getProtocol(), is(expectedProtocol));