diff --git a/pom.xml b/pom.xml index fd1b38226..13b0cd76d 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.baidu.hugegraph hugegraph-common - 1.6.4 + 1.6.5 hugegraph-common https://github.com/hugegraph/hugegraph-common @@ -212,7 +212,7 @@ - 1.6.4.0 + 1.6.5.0 diff --git a/src/main/java/com/baidu/hugegraph/config/ConfigConvOption.java b/src/main/java/com/baidu/hugegraph/config/ConfigConvOption.java new file mode 100644 index 000000000..9f354d086 --- /dev/null +++ b/src/main/java/com/baidu/hugegraph/config/ConfigConvOption.java @@ -0,0 +1,47 @@ +/* + * Copyright 2017 HugeGraph Authors + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * 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 com.baidu.hugegraph.config; + +import java.util.function.Function; + +import com.google.common.base.Predicate; + +public class ConfigConvOption extends TypedOption { + + private final Function converter; + + public ConfigConvOption(String name, String desc, Predicate pred, + Function convert, String value) { + this(name, false, desc, pred, convert, value); + } + + public ConfigConvOption(String name, boolean required, String desc, + Predicate pred, Function convert, + String value) { + super(name, required, desc, pred, String.class, value); + this.converter = convert; + } + + @Override + public R convert(Object value) { + assert value instanceof String; + return this.converter.apply((String) value); + } +} diff --git a/src/main/java/com/baidu/hugegraph/config/ConfigListConvOption.java b/src/main/java/com/baidu/hugegraph/config/ConfigListConvOption.java new file mode 100644 index 000000000..6d5fa9589 --- /dev/null +++ b/src/main/java/com/baidu/hugegraph/config/ConfigListConvOption.java @@ -0,0 +1,72 @@ +/* + * Copyright 2017 HugeGraph Authors + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * 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 com.baidu.hugegraph.config; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.function.Function; + +import com.baidu.hugegraph.util.E; +import com.google.common.base.Predicate; + +public class ConfigListConvOption extends TypedOption, List> { + + private final Class elemClass; + private final Function converter; + + @SuppressWarnings("unchecked") + public ConfigListConvOption(String name, String desc, + Predicate> pred, Function convert, + T value) { + this(name, desc, pred, convert, (Class) value.getClass(), value); + } + + @SuppressWarnings("unchecked") + public ConfigListConvOption(String name, String desc, + Predicate> pred, Function convert, + Class clazz, T... values) { + this(name, false, desc, pred, convert, clazz, Arrays.asList(values)); + } + + @SuppressWarnings("unchecked") + public ConfigListConvOption(String name, boolean required, String desc, + Predicate> pred, Function convert, + Class clazz, List values) { + super(name, required, desc, pred, + (Class>) values.getClass(), values); + E.checkArgumentNotNull(clazz, "Element class can't be null"); + this.elemClass = clazz; + this.converter = convert; + } + + @Override + public List convert(Object value) { + List results = ConfigListOption.convert(value, part -> { + return super.convert(part, this.elemClass); + }); + + List enums = new ArrayList<>(results.size()); + for (T elem : results) { + enums.add(this.converter.apply(elem)); + } + return enums; + } +} diff --git a/src/main/java/com/baidu/hugegraph/config/ConfigListOption.java b/src/main/java/com/baidu/hugegraph/config/ConfigListOption.java index ff3a6f287..9add0bc94 100644 --- a/src/main/java/com/baidu/hugegraph/config/ConfigListOption.java +++ b/src/main/java/com/baidu/hugegraph/config/ConfigListOption.java @@ -22,6 +22,7 @@ package com.baidu.hugegraph.config; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.function.Function; import com.baidu.hugegraph.util.E; import com.google.common.base.Predicate; @@ -32,30 +33,37 @@ public class ConfigListOption extends ConfigOption> { @SuppressWarnings("unchecked") public ConfigListOption(String name, String desc, - Predicate> func, T value) { - this(name, false, desc, func, (Class) value.getClass(), value); + Predicate> pred, T value) { + this(name, desc, pred, (Class) value.getClass(), value); } @SuppressWarnings("unchecked") - public ConfigListOption(String name, boolean required, String desc, - Predicate> func, Class clazz, + public ConfigListOption(String name, String desc, + Predicate> pred, Class clazz, T... values) { - this(name, required, desc, func, clazz, Arrays.asList(values)); + this(name, false, desc, pred, clazz, Arrays.asList(values)); } @SuppressWarnings("unchecked") public ConfigListOption(String name, boolean required, String desc, - Predicate> func, Class clazz, + Predicate> pred, Class clazz, List values) { - super(name, required, desc, func, + super(name, required, desc, pred, (Class>) values.getClass(), values); E.checkArgumentNotNull(clazz, "Element class can't be null"); this.elemClass = clazz; } @Override - @SuppressWarnings("unchecked") public List convert(Object value) { + return convert(value, part -> super.convert(part, this.elemClass)); + } + + @SuppressWarnings("unchecked") + public static List convert(Object value, Function conv) { + if (value instanceof List) { + return (List) value; + } // If target data type is List, parse it as a list String str = (String) value; if (str.startsWith("[") && str.endsWith("]")) { @@ -69,7 +77,7 @@ public class ConfigListOption extends ConfigOption> { String[] parts = str.split(","); List results = new ArrayList<>(parts.length); for (String part : parts) { - results.add((T) super.convert(part.trim(), this.elemClass)); + results.add((T) conv.apply(part.trim())); } return results; } diff --git a/src/main/java/com/baidu/hugegraph/config/ConfigOption.java b/src/main/java/com/baidu/hugegraph/config/ConfigOption.java index 06fb43a23..cb958744b 100644 --- a/src/main/java/com/baidu/hugegraph/config/ConfigOption.java +++ b/src/main/java/com/baidu/hugegraph/config/ConfigOption.java @@ -19,151 +19,21 @@ package com.baidu.hugegraph.config; -import java.lang.reflect.Method; -import java.util.List; -import java.util.Set; - -import org.apache.commons.configuration.PropertyConverter; -import org.slf4j.Logger; - -import com.baidu.hugegraph.util.E; -import com.baidu.hugegraph.util.Log; -import com.google.common.base.Joiner; import com.google.common.base.Predicate; -import com.google.common.collect.ImmutableSet; -public class ConfigOption { - - private static final Logger LOG = Log.logger(ConfigOption.class); - - private static final Set> ACCEPTED_DATA_TYPES; - private static final String ACCEPTED_DATA_TYPES_STRING; - - static { - ACCEPTED_DATA_TYPES = ImmutableSet.of( - Boolean.class, - Short.class, - Integer.class, - Byte.class, - Long.class, - Float.class, - Double.class, - String.class, - String[].class, - List.class - ); - - ACCEPTED_DATA_TYPES_STRING = Joiner.on(", ").join(ACCEPTED_DATA_TYPES); - } - - private final String name; - private final String desc; - private final boolean required; - private final Class dataType; - private final T defaultValue; - private final Predicate checkFunc; +public class ConfigOption extends TypedOption { public ConfigOption(String name, String desc, T value) { this(name, desc, null, value); } @SuppressWarnings("unchecked") - public ConfigOption(String name, String desc, Predicate func, T value) { - this(name, false, desc, func, (Class) value.getClass(), value); + public ConfigOption(String name, String desc, Predicate pred, T value) { + this(name, false, desc, pred, (Class) value.getClass(), value); } - @SuppressWarnings("unchecked") public ConfigOption(String name, boolean required, String desc, - Predicate func, Class type, T value) { - E.checkNotNull(name, "name"); - E.checkNotNull(type, "dataType"); - - this.name = name; - this.dataType = (Class) this.checkAndAssignDataType(type); - this.defaultValue = value; - this.required = required; - this.desc = desc; - this.checkFunc = func; - - this.check(this.defaultValue); - } - - private Class checkAndAssignDataType(Class dataType) { - for (Class clazz : ACCEPTED_DATA_TYPES) { - if (clazz.isAssignableFrom(dataType)) { - return clazz; - } - } - - String msg = String.format("Input data type '%s' doesn't belong " + - "to acceptable type set: [%s]", - dataType, ACCEPTED_DATA_TYPES_STRING); - throw new IllegalArgumentException(msg); - } - - public String name() { - return this.name; - } - - public Class dataType() { - return this.dataType; - } - - public String desc() { - return this.desc; - } - - public boolean required() { - return this.required; - } - - public T defaultValue() { - return this.defaultValue; - } - - @SuppressWarnings("unchecked") - public T convert(Object value) { - return (T) this.convert(value, this.dataType); - } - - public Object convert(Object value, Class dataType) { - if (dataType.equals(String.class)) { - return value; - } - - // Use PropertyConverter method `toXXX` convert value - String methodTo = "to" + dataType.getSimpleName(); - try { - Method method = PropertyConverter.class.getMethod( - methodTo, Object.class); - return method.invoke(null, value); - } catch (ReflectiveOperationException e) { - LOG.error("Invalid type of value '{}' for option '{}'", - value, this.name, e); - throw new ConfigException( - "Invalid type of value '%s' for option '%s', " + - "expect '%s' type", - value, this.name, dataType.getSimpleName()); - } - } - - public void check(Object value) { - E.checkNotNull(value, "value", this.name); - E.checkArgument(this.dataType.isInstance(value), - "Invalid type of value '%s' for option '%s'", - value, this.name); - if (this.checkFunc != null) { - @SuppressWarnings("unchecked") - T result = (T) value; - E.checkArgument(this.checkFunc.apply(result), - "Invalid option value for '%s': %s", - this.name, value); - } - } - - @Override - public String toString() { - return String.format("[%s]%s=%s", this.dataType.getSimpleName(), - this.name, this.defaultValue); + Predicate pred, Class type, T value) { + super(name, required, desc, pred, type, value); } } diff --git a/src/main/java/com/baidu/hugegraph/config/HugeConfig.java b/src/main/java/com/baidu/hugegraph/config/HugeConfig.java index c61b8fd7e..7dc6ec8c1 100644 --- a/src/main/java/com/baidu/hugegraph/config/HugeConfig.java +++ b/src/main/java/com/baidu/hugegraph/config/HugeConfig.java @@ -110,9 +110,9 @@ public class HugeConfig extends PropertiesConfiguration { } @SuppressWarnings("unchecked") - public T get(ConfigOption option) { + public R get(TypedOption option) { Object value = this.getProperty(option.name()); - return value != null ? (T) value : option.defaultValue(); + return value != null ? (R) value : option.defaultValue(); } public Map getMap(ConfigListOption option) { @@ -144,7 +144,7 @@ public class HugeConfig extends PropertiesConfiguration { E.checkArgument(value instanceof String, "Invalid value for key '%s': %s", key, value); - ConfigOption option = OptionSpace.get(key); + TypedOption option = OptionSpace.get(key); Class dataType = option.dataType(); if (List.class.isAssignableFrom(dataType)) { diff --git a/src/main/java/com/baidu/hugegraph/config/OptionChecker.java b/src/main/java/com/baidu/hugegraph/config/OptionChecker.java index ff70581a8..f3e116f41 100644 --- a/src/main/java/com/baidu/hugegraph/config/OptionChecker.java +++ b/src/main/java/com/baidu/hugegraph/config/OptionChecker.java @@ -21,6 +21,7 @@ package com.baidu.hugegraph.config; import java.lang.reflect.Array; import java.util.Arrays; +import java.util.List; import javax.annotation.Nullable; @@ -62,6 +63,16 @@ public final class OptionChecker { }; } + @SuppressWarnings("unchecked") + public static Predicate> inValues(O... values) { + return new Predicate>() { + @Override + public boolean apply(@Nullable List o) { + return o != null && Arrays.asList(values).containsAll(o); + } + }; + } + public static Predicate positiveInt() { return new Predicate() { @Override diff --git a/src/main/java/com/baidu/hugegraph/config/OptionHolder.java b/src/main/java/com/baidu/hugegraph/config/OptionHolder.java index f306741a2..6b5c398d9 100644 --- a/src/main/java/com/baidu/hugegraph/config/OptionHolder.java +++ b/src/main/java/com/baidu/hugegraph/config/OptionHolder.java @@ -32,7 +32,7 @@ public class OptionHolder { private static final Logger LOG = Log.logger(HugeConfig.class); - protected Map> options; + protected Map> options; public OptionHolder() { this.options = new HashMap<>(); @@ -41,7 +41,7 @@ public class OptionHolder { protected void registerOptions() { for (Field field : this.getClass().getFields()) { try { - ConfigOption option = (ConfigOption) field.get(this); + TypedOption option = (TypedOption) field.get(this); // Fields of subclass first, don't overwrite by superclass this.options.putIfAbsent(option.name(), option); } catch (Exception e) { @@ -52,7 +52,7 @@ public class OptionHolder { } } - public Map> options() { + public Map> options() { return Collections.unmodifiableMap(this.options); } } diff --git a/src/main/java/com/baidu/hugegraph/config/OptionSpace.java b/src/main/java/com/baidu/hugegraph/config/OptionSpace.java index 632f37e5d..485fb81d2 100644 --- a/src/main/java/com/baidu/hugegraph/config/OptionSpace.java +++ b/src/main/java/com/baidu/hugegraph/config/OptionSpace.java @@ -34,7 +34,7 @@ public final class OptionSpace { private static final Logger LOG = Log.logger(OptionSpace.class); private static final Map> holders; - private static final Map> options; + private static final Map> options; private static final String INSTANCE_METHOD = "instance"; static { @@ -105,7 +105,7 @@ public final class OptionSpace { return options.containsKey(key); } - public static ConfigOption get(String key) { + public static TypedOption get(String key) { return options.get(key); } } diff --git a/src/main/java/com/baidu/hugegraph/config/TypedOption.java b/src/main/java/com/baidu/hugegraph/config/TypedOption.java new file mode 100644 index 000000000..91fb7ea33 --- /dev/null +++ b/src/main/java/com/baidu/hugegraph/config/TypedOption.java @@ -0,0 +1,160 @@ +/* + * Copyright 2017 HugeGraph Authors + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * 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 com.baidu.hugegraph.config; + +import java.lang.reflect.Method; +import java.util.List; +import java.util.Set; + +import org.apache.commons.configuration.PropertyConverter; +import org.slf4j.Logger; + +import com.baidu.hugegraph.util.E; +import com.baidu.hugegraph.util.Log; +import com.google.common.base.Joiner; +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableSet; + +public class TypedOption { + + private static final Logger LOG = Log.logger(TypedOption.class); + + private static final Set> ACCEPTED_DATA_TYPES; + private static final String ACCEPTED_DATA_TYPES_STRING; + + static { + ACCEPTED_DATA_TYPES = ImmutableSet.of( + Boolean.class, + Short.class, + Integer.class, + Byte.class, + Long.class, + Float.class, + Double.class, + String.class, + String[].class, + List.class + ); + + ACCEPTED_DATA_TYPES_STRING = Joiner.on(", ").join(ACCEPTED_DATA_TYPES); + } + + private final String name; + private final String desc; + private final boolean required; + private final Class dataType; + private final T defaultValue; + private final Predicate checkFunc; + + @SuppressWarnings("unchecked") + public TypedOption(String name, boolean required, String desc, + Predicate pred, Class type, T value) { + E.checkNotNull(name, "name"); + E.checkNotNull(type, "dataType"); + + this.name = name; + this.dataType = (Class) this.checkAndAssignDataType(type); + this.defaultValue = value; + this.required = required; + this.desc = desc; + this.checkFunc = pred; + + this.check(this.defaultValue); + } + + private Class checkAndAssignDataType(Class dataType) { + for (Class clazz : ACCEPTED_DATA_TYPES) { + if (clazz.isAssignableFrom(dataType)) { + return clazz; + } + } + + String msg = String.format("Input data type '%s' doesn't belong " + + "to acceptable type set: [%s]", + dataType, ACCEPTED_DATA_TYPES_STRING); + throw new IllegalArgumentException(msg); + } + + public String name() { + return this.name; + } + + public Class dataType() { + return this.dataType; + } + + public String desc() { + return this.desc; + } + + public boolean required() { + return this.required; + } + + public R defaultValue() { + return this.convert(this.defaultValue); + } + + @SuppressWarnings("unchecked") + public R convert(Object value) { + return (R) this.convert(value, this.dataType); + } + + public Object convert(Object value, Class dataType) { + if (dataType.equals(String.class)) { + return value; + } + + // Use PropertyConverter method `toXXX` convert value + String methodTo = "to" + dataType.getSimpleName(); + try { + Method method = PropertyConverter.class.getMethod( + methodTo, Object.class); + return method.invoke(null, value); + } catch (ReflectiveOperationException e) { + LOG.error("Invalid type of value '{}' for option '{}'", + value, this.name, e); + throw new ConfigException( + "Invalid type of value '%s' for option '%s', " + + "expect '%s' type", + value, this.name, dataType.getSimpleName()); + } + } + + public void check(Object value) { + E.checkNotNull(value, "value", this.name); + E.checkArgument(this.dataType.isInstance(value), + "Invalid type of value '%s' for option '%s'", + value, this.name); + if (this.checkFunc != null) { + @SuppressWarnings("unchecked") + T result = (T) value; + E.checkArgument(this.checkFunc.apply(result), + "Invalid option value for '%s': %s", + this.name, value); + } + } + + @Override + public String toString() { + return String.format("[%s]%s=%s", this.dataType.getSimpleName(), + this.name, this.defaultValue); + } +} diff --git a/src/main/java/com/baidu/hugegraph/version/CommonVersion.java b/src/main/java/com/baidu/hugegraph/version/CommonVersion.java index 5843330cc..55585ad67 100644 --- a/src/main/java/com/baidu/hugegraph/version/CommonVersion.java +++ b/src/main/java/com/baidu/hugegraph/version/CommonVersion.java @@ -27,5 +27,5 @@ public class CommonVersion { // The second parameter of Version.of() is for all-in-one JAR public static final Version VERSION = Version.of(CommonVersion.class, - "1.6.4"); + "1.6.5"); } diff --git a/src/test/java/com/baidu/hugegraph/unit/config/HugeConfigTest.java b/src/test/java/com/baidu/hugegraph/unit/config/HugeConfigTest.java index 5e23e5071..131cedc9c 100644 --- a/src/test/java/com/baidu/hugegraph/unit/config/HugeConfigTest.java +++ b/src/test/java/com/baidu/hugegraph/unit/config/HugeConfigTest.java @@ -21,6 +21,7 @@ package com.baidu.hugegraph.unit.config; import static com.baidu.hugegraph.config.OptionChecker.allowValues; import static com.baidu.hugegraph.config.OptionChecker.disallowEmpty; +import static com.baidu.hugegraph.config.OptionChecker.inValues; import static com.baidu.hugegraph.config.OptionChecker.nonNegativeInt; import static com.baidu.hugegraph.config.OptionChecker.positiveInt; import static com.baidu.hugegraph.config.OptionChecker.rangeDouble; @@ -33,6 +34,8 @@ import org.apache.commons.configuration.PropertiesConfiguration; import org.junit.BeforeClass; import org.junit.Test; +import com.baidu.hugegraph.config.ConfigConvOption; +import com.baidu.hugegraph.config.ConfigListConvOption; import com.baidu.hugegraph.config.ConfigListOption; import com.baidu.hugegraph.config.ConfigOption; import com.baidu.hugegraph.config.HugeConfig; @@ -102,6 +105,10 @@ public class HugeConfigTest extends BaseUnitTest { Assert.assertEquals(true, config.get(TestOptions.bool)); + Assert.assertEquals(WeekDay.WEDNESDAY, config.get(TestOptions.weekday)); + Assert.assertEquals(Arrays.asList(WeekDay.SATURDAY, WeekDay.SUNDAY), + config.get(TestOptions.weekdays)); + Assert.assertEquals(Arrays.asList("list-value1", "list-value2"), config.get(TestOptions.list)); @@ -251,10 +258,30 @@ public class HugeConfigTest extends BaseUnitTest { true ); + public static final ConfigConvOption weekday = + new ConfigConvOption<>( + "group1.weekday", + "description of group1.weekday", + allowValues("SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY", + "THURSDAY", "FRIDAY", "SATURDAY"), + WeekDay::valueOf, + "WEDNESDAY" + ); + + public static final ConfigListConvOption weekdays = + new ConfigListConvOption<>( + "group1.weekdays", + "description of group1.weekdays", + inValues("SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY", + "THURSDAY", "FRIDAY", "SATURDAY"), + WeekDay::valueOf, + String.class, + "SATURDAY", "SUNDAY" + ); + public static final ConfigListOption list = new ConfigListOption<>( "group1.list", - false, "description of group1.list", disallowEmpty(), String.class, @@ -264,7 +291,6 @@ public class HugeConfigTest extends BaseUnitTest { public static final ConfigListOption map = new ConfigListOption<>( "group1.map", - false, "description of group1.map", disallowEmpty(), String.class, @@ -290,4 +316,9 @@ public class HugeConfigTest extends BaseUnitTest { "textsub-value" ); } + + public enum WeekDay { + + SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY; + } }