You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@uniffle.apache.org by ro...@apache.org on 2022/07/03 14:15:50 UTC
[incubator-uniffle] branch master updated: Introduce the asList method in ConfigOptions (#9)
This is an automated email from the ASF dual-hosted git repository.
roryqi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-uniffle.git
The following commit(s) were added to refs/heads/master by this push:
new 317780b Introduce the asList method in ConfigOptions (#9)
317780b is described below
commit 317780bbc05a431377b6ba5b22597d36ea34ba45
Author: Junfan Zhang <ju...@outlook.com>
AuthorDate: Sun Jul 3 22:15:46 2022 +0800
Introduce the asList method in ConfigOptions (#9)
### What changes were proposed in this pull request?
Introduce the asList method in ConfigOptions
### Why are the changes needed?
It’s necessary when getting the list of values from the config directly.
### Does this PR introduce _any_ user-facing change?
No
### How was this patch tested?
UT
---
.../tencent/rss/common/config/ConfigOptions.java | 79 +++++++++++++++
.../rss/common/config/ConfigOptionTest.java | 106 +++++++++++++++++++++
2 files changed, 185 insertions(+)
diff --git a/common/src/main/java/com/tencent/rss/common/config/ConfigOptions.java b/common/src/main/java/com/tencent/rss/common/config/ConfigOptions.java
index 96d32cf..d9acd01 100644
--- a/common/src/main/java/com/tencent/rss/common/config/ConfigOptions.java
+++ b/common/src/main/java/com/tencent/rss/common/config/ConfigOptions.java
@@ -17,8 +17,11 @@
package com.tencent.rss.common.config;
+import java.util.Arrays;
+import java.util.List;
import java.util.Objects;
import java.util.function.Function;
+import java.util.stream.Collectors;
/**
* {@code ConfigOptions} are used to build a {@link ConfigOption}.
@@ -53,6 +56,7 @@ import java.util.function.Function;
* }</pre>
*/
public class ConfigOptions {
+
/**
* Not intended to be instantiated.
*/
@@ -166,6 +170,10 @@ public class ConfigOptions {
this.converter = converter;
}
+ public ListConfigOptionBuilder asList() {
+ return new ListConfigOptionBuilder<T>(key, clazz, converter);
+ }
+
// todo: errorMsg shouldn't contain key
public TypedConfigOptionBuilder checkValue(Function<T, Boolean> checkValue, String errMsg) {
Function<Object, T> newConverter = (v) -> {
@@ -207,4 +215,75 @@ public class ConfigOptions {
converter);
}
}
+
+ /**
+ * Builder for {@link ConfigOption} of list of type {@link E}.
+ *
+ * @param <E> list element type of the option
+ */
+ public static class ListConfigOptionBuilder<E> {
+ private static final String LIST_SPILTTER = ",";
+
+ private final String key;
+ private final Class<E> clazz;
+ private final Function<Object, E> atomicConverter;
+ private Function<Object, List<E>> asListConverter;
+
+ public ListConfigOptionBuilder(String key, Class<E> clazz, Function<Object, E> atomicConverter) {
+ this.key = key;
+ this.clazz = clazz;
+ this.atomicConverter = atomicConverter;
+ this.asListConverter = (v) -> {
+ if (v instanceof List) {
+ return (List<E>) v;
+ } else {
+ return Arrays.stream(v.toString().split(LIST_SPILTTER))
+ .map(s -> atomicConverter.apply(s)).collect(Collectors.toList());
+ }
+ };
+ }
+
+ public ListConfigOptionBuilder checkValue(Function<E, Boolean> checkValueFunc, String errMsg) {
+ final Function<Object, List<E>> listConverFunc = asListConverter;
+ Function<Object, List<E>> newConverter = (v) -> {
+ List<E> list = listConverFunc.apply(v);
+ if (list.stream().anyMatch(x -> !checkValueFunc.apply(x))) {
+ throw new IllegalArgumentException(errMsg);
+ }
+ return list;
+ };
+ this.asListConverter = newConverter;
+ return this;
+ }
+
+ /**
+ * Creates a ConfigOption with the given default value.
+ *
+ * @param values The list of default values for the config option
+ * @return The config option with the default value.
+ */
+ @SafeVarargs
+ public final ConfigOption<List<E>> defaultValues(E... values) {
+ return new ConfigOption<>(
+ key,
+ clazz,
+ ConfigOption.EMPTY_DESCRIPTION,
+ Arrays.asList(values),
+ asListConverter);
+ }
+
+ /**
+ * Creates a ConfigOption without a default value.
+ *
+ * @return The config option without a default value.
+ */
+ public ConfigOption<List<E>> noDefaultValue() {
+ return new ConfigOption<>(
+ key,
+ clazz,
+ ConfigOption.EMPTY_DESCRIPTION,
+ null,
+ asListConverter);
+ }
+ }
}
diff --git a/common/src/test/java/com/tencent/rss/common/config/ConfigOptionTest.java b/common/src/test/java/com/tencent/rss/common/config/ConfigOptionTest.java
index 61e0d7d..fa0f454 100644
--- a/common/src/test/java/com/tencent/rss/common/config/ConfigOptionTest.java
+++ b/common/src/test/java/com/tencent/rss/common/config/ConfigOptionTest.java
@@ -21,12 +21,118 @@ import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
+import java.util.List;
+import java.util.function.Function;
+
+import com.google.common.collect.Lists;
+
public class ConfigOptionTest {
+ @Test
+ public void testSetKVWithStringTypeDirectly() {
+ final ConfigOption<Integer> intConfig = ConfigOptions
+ .key("rss.key1")
+ .intType()
+ .defaultValue(1000)
+ .withDescription("Int config key1");
+
+ RssConf conf = new RssBaseConf();
+ conf.setString("rss.key1", "2000");
+ assertEquals(2000, conf.get(intConfig));
+
+ final ConfigOption<Boolean> booleanConfig = ConfigOptions
+ .key("key2")
+ .booleanType()
+ .defaultValue(false)
+ .withDescription("Boolean config key");
+
+ conf.setString("key2", "true");
+ assertTrue(conf.get(booleanConfig));
+ conf.setString("key2", "False");
+ assertFalse(conf.get(booleanConfig));
+ }
+
+ @Test
+ public void testListTypes() {
+ // test the string type list.
+ final ConfigOption<List<String>> listStringConfigOption = ConfigOptions
+ .key("rss.key1")
+ .stringType()
+ .asList()
+ .defaultValues("h1", "h2")
+ .withDescription("List config key1");
+
+ List<String> defaultValues = listStringConfigOption.defaultValue();
+ assertEquals(2, defaultValues.size());
+ assertSame(String.class, listStringConfigOption.getClazz());
+
+ RssBaseConf conf = new RssBaseConf();
+ conf.set(listStringConfigOption, Lists.newArrayList("a", "b", "c"));
+
+ List<String> vals = conf.get(listStringConfigOption);
+ assertEquals(3, vals.size());
+ assertEquals(Lists.newArrayList("a", "b", "c"), vals);
+
+ // test the long type list
+ final ConfigOption<List<Long>> listLongConfigOption = ConfigOptions
+ .key("rss.key2")
+ .longType()
+ .asList()
+ .defaultValues(1L)
+ .withDescription("List long config key2");
+
+ List<Long> longDefaultVals = listLongConfigOption.defaultValue();
+ assertEquals(longDefaultVals.size(), 1);
+ assertEquals(Lists.newArrayList(1L), longDefaultVals);
+
+ conf.setString("rss.key2", "1,2,3");
+ List<Long> longVals = conf.get(listLongConfigOption);
+ assertEquals(Lists.newArrayList(1L, 2L, 3L), longVals);
+
+ // test overwrite the same conf key.
+ conf.set(listLongConfigOption, Lists.newArrayList(1L, 2L, 3L, 4L));
+ assertEquals(Lists.newArrayList(1L, 2L, 3L, 4L), conf.get(listLongConfigOption));
+
+ // test the no-default values
+ final ConfigOption<List<Long>> listLongConfigOptionWithoutDefault = ConfigOptions
+ .key("rss.key3")
+ .longType()
+ .asList()
+ .noDefaultValue()
+ .withDescription("List long config key3 without default values");
+ List<Long> valsWithoutDefault = listLongConfigOptionWithoutDefault.defaultValue();
+ assertNull(valsWithoutDefault);
+
+ // test the method of check
+ final ConfigOption<List<Integer>> checkLongValsOptions = ConfigOptions
+ .key("rss.key4")
+ .intType()
+ .asList()
+ .checkValue((Function<Integer, Boolean>) val -> val > 0, "Every number of list should be positive")
+ .noDefaultValue()
+ .withDescription("The key4 is illegal");
+
+ conf.set(checkLongValsOptions, Lists.newArrayList(-1, 2, 3));
+
+ try {
+ conf.get(checkLongValsOptions);
+ fail();
+ } catch (IllegalArgumentException illegalArgumentException) {
+ }
+
+ conf.set(checkLongValsOptions, Lists.newArrayList(1, 2, 3));
+ try {
+ conf.get(checkLongValsOptions);
+ } catch (IllegalArgumentException illegalArgumentException) {
+ fail();
+ }
+ }
+
@Test
public void testBasicTypes() {
final ConfigOption<Integer> intConfig = ConfigOptions