Skip to content

Commit 210aab0

Browse files
authored
Settings: AffixSettings as validator dependencies (#52973) (#52982)
Allow AffixSetting as validator dependencies. If a validator specifies AffixSettings as a dependency, then `validate(T, Map)` will have the concrete setting in a map. Backport of: #52973, 1e0ba70 Fixes: #52933
1 parent e6755af commit 210aab0

File tree

2 files changed

+63
-1
lines changed

2 files changed

+63
-1
lines changed

server/src/main/java/org/elasticsearch/common/settings/Setting.java

+10-1
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,16 @@ private T get(Settings settings, boolean validate) {
438438
map = new HashMap<>();
439439
while (it.hasNext()) {
440440
final Setting<?> setting = it.next();
441-
map.put(setting, setting.get(settings, false)); // we have to disable validation or we will stack overflow
441+
if (setting instanceof AffixSetting) {
442+
// Collect all possible concrete settings
443+
AffixSetting<?> as = ((AffixSetting<?>)setting);
444+
for (String ns : as.getNamespaces(settings)) {
445+
Setting<?> s = as.getConcreteSettingForNamespace(ns);
446+
map.put(s, s.get(settings, false));
447+
}
448+
} else {
449+
map.put(setting, setting.get(settings, false)); // we have to disable validation or we will stack overflow
450+
}
442451
}
443452
} else {
444453
map = Collections.emptyMap();

server/src/test/java/org/elasticsearch/common/settings/SettingTests.java

+53
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,59 @@ public void testAffixSettingsFailOnGet() {
830830
assertEquals("[\"testelement\"]", listAffixSetting.getDefaultRaw(Settings.EMPTY));
831831
}
832832

833+
public void testAffixSettingsValidatorDependencies() {
834+
Setting<Integer> affix = Setting.affixKeySetting("abc.", "def", k -> Setting.intSetting(k, 10));
835+
Setting<Integer> fix0 = Setting.intSetting("abc.tuv", 20, 0);
836+
Setting<Integer> fix1 = Setting.intSetting("abc.qrx", 20, 0, new Setting.Validator<Integer>() {
837+
@Override
838+
public void validate(Integer value) {}
839+
840+
String toString(Map<Setting<?>, Object> s) {
841+
return s.entrySet().stream().map(e -> e.getKey().getKey() + ":" + e.getValue().toString()).sorted()
842+
.collect(Collectors.joining(","));
843+
}
844+
845+
@Override
846+
public void validate(Integer value, Map<Setting<?>, Object> settings, boolean isPresent) {
847+
if (settings.get(fix0).equals(fix0.getDefault(Settings.EMPTY))) {
848+
settings.remove(fix0);
849+
}
850+
if (settings.size() == 1) {
851+
throw new IllegalArgumentException(toString(settings));
852+
} else if (settings.size() == 2) {
853+
throw new IllegalArgumentException(toString(settings));
854+
}
855+
}
856+
857+
@Override
858+
public Iterator<Setting<?>> settings() {
859+
List<Setting<?>> a = Arrays.asList(affix, fix0);
860+
return a.iterator();
861+
}
862+
});
863+
864+
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
865+
() -> fix1.get(Settings.builder().put("abc.1.def", 11).put("abc.2.def", 12).put("abc.qrx", 11).build()));
866+
assertThat(e.getMessage(), is("abc.1.def:11,abc.2.def:12"));
867+
868+
e = expectThrows(IllegalArgumentException.class,
869+
() -> fix1.get(Settings.builder().put("abc.3.def", 13).put("abc.qrx", 20).build()));
870+
assertThat(e.getMessage(), is("abc.3.def:13"));
871+
872+
e = expectThrows(IllegalArgumentException.class,
873+
() -> fix1.get(Settings.builder().put("abc.4.def", 14).put("abc.qrx", 20).put("abc.tuv", 50).build()));
874+
assertThat(e.getMessage(), is("abc.4.def:14,abc.tuv:50"));
875+
876+
assertEquals(
877+
fix1.get(Settings.builder()
878+
.put("abc.3.def", 13).put("abc.1.def", 11).put("abc.2.def", 12).put("abc.qrx", 20)
879+
.build()),
880+
Integer.valueOf(20)
881+
);
882+
883+
assertEquals(fix1.get(Settings.builder().put("abc.qrx", 30).build()), Integer.valueOf(30));
884+
}
885+
833886
public void testMinMaxInt() {
834887
Setting<Integer> integerSetting = Setting.intSetting("foo.bar", 1, 0, 10, Property.NodeScope);
835888
try {

0 commit comments

Comments
 (0)