allow param defs to expand config models

This commit is contained in:
Jonathan Shook 2022-06-09 15:01:35 -05:00
parent d1541f0dd2
commit 0631f4aa05
3 changed files with 84 additions and 26 deletions

View File

@ -22,6 +22,7 @@ import io.nosqlbench.nb.api.errors.BasicError;
import java.math.BigDecimal;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
public class ConfigModel implements NBConfigModel {
@ -29,6 +30,7 @@ public class ConfigModel implements NBConfigModel {
private final List<Param<?>> params = new ArrayList<>();
private Param<?> lastAdded = null;
private final Class<?> ofType;
private final List<NBConfigModelExpander> expanders = new ArrayList<>();
private ConfigModel(Class<?> ofType, Param<?>... params) {
this.ofType = ofType;
@ -40,6 +42,7 @@ public class ConfigModel implements NBConfigModel {
public static ConfigModel of(Class<?> ofType, Param<?>... params) {
return new ConfigModel(ofType, params);
}
public static ConfigModel of(Class<?> ofType) {
return new ConfigModel(ofType);
}
@ -47,7 +50,7 @@ public class ConfigModel implements NBConfigModel {
public static NBConfiguration defacto(ActivityDef def) {
ConfigModel configModel = new ConfigModel(Object.class);
for (Map.Entry<String, Object> entry : def.getParams().entrySet()) {
configModel.add(Param.defaultTo(entry.getKey(),entry.getValue().toString()));
configModel.add(Param.defaultTo(entry.getKey(), entry.getValue().toString()));
}
return configModel.apply(def.getParams());
}
@ -61,6 +64,13 @@ public class ConfigModel implements NBConfigModel {
return this;
}
/**
* Add a param that, when present in a runtime configuration, will cause the config
* model to be expanded dynamically. This is for scenarios in which you have external
* configurable resources or templates which contain their own models that can
* only be known at runtime.
*/
public NBConfigModel asReadOnly() {
return this;
}
@ -140,14 +150,19 @@ public class ConfigModel implements NBConfigModel {
@Override
public NBConfiguration extractConfig(Map<String, ?> sharedConfig) {
NBConfiguration matchedConfig = matchConfig(sharedConfig);
matchedConfig.getMap().keySet().forEach(sharedConfig::remove);
return new NBConfiguration(this, matchedConfig.getMap());
}
@Override
public NBConfiguration matchConfig(Map<String, ?> sharedConfig) {
LinkedHashMap<String, Object> extracted = new LinkedHashMap<>();
for (String providedCfgField : sharedConfig.keySet()) {
if (getNamedParams().containsKey(providedCfgField)) {
extracted.put(providedCfgField, sharedConfig.get(providedCfgField));
}
}
extracted.keySet().forEach(sharedConfig::remove);
return new NBConfiguration(this, extracted);
}
@ -156,6 +171,11 @@ public class ConfigModel implements NBConfigModel {
return extractConfig(cfg.getMap());
}
@Override
public NBConfiguration matchConfig(NBConfiguration cfg) {
return matchConfig(cfg.getMap());
}
private void assertDistinctSynonyms(Map<String, ?> config) {
List<String> names = new ArrayList<>();
for (Param<?> param : getParams()) {
@ -173,10 +193,12 @@ public class ConfigModel implements NBConfigModel {
@Override
public NBConfiguration apply(Map<String, ?> config) {
ConfigModel expanded = expand(this, config);
assertValidConfig(config);
LinkedHashMap<String, Object> validConfig = new LinkedHashMap<>();
for (Param<?> param : params) {
for (Param<?> param : expanded.params) {
Class<?> type = param.getType();
List<String> found = new ArrayList<>();
String activename = null;
@ -188,7 +210,7 @@ public class ConfigModel implements NBConfigModel {
break;
}
}
if (activename==null) {
if (activename == null) {
activename = param.getNames().get(0);
}
if (cval == null && param.isRequired()) {
@ -205,9 +227,28 @@ public class ConfigModel implements NBConfigModel {
@Override
public void assertValidConfig(Map<String, ?> config) {
assertRequiredFields(config);
assertNoExtraneousFields(config);
assertDistinctSynonyms(config);
ConfigModel expanded = expand(this, config);
expanded.assertRequiredFields(config);
expanded.assertNoExtraneousFields(config);
expanded.assertDistinctSynonyms(config);
}
private ConfigModel expand(ConfigModel configModel, Map<String, ?> config) {
List<Param<?>> expanders = configModel.params.stream()
.filter(p -> p.getExpander()!=null).toList();
for (Param<?> expandingParameter : expanders) {
for (String name : expandingParameter.getNames()) {
if (config.containsKey(name)) {
Object triggeringValue = config.get(name);
expandingParameter.validate(triggeringValue);
NBConfigModelExpander expander = expandingParameter.getExpander();
NBConfigModel newModel = expander.apply(triggeringValue);
configModel = configModel.add(newModel);
}
}
}
return configModel;
}
@Override
@ -274,4 +315,14 @@ public class ConfigModel implements NBConfigModel {
}
return this;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[").append(
params.stream().map(p -> p.getNames().get(0)).collect(Collectors.joining(",")))
.append("]");
return sb.toString();
}
}

View File

@ -14,12 +14,8 @@
* limitations under the License.
*/
package io.nosqlbench.adapter.diag.optasks;
package io.nosqlbench.nb.api.config.standard;
import io.nosqlbench.nb.api.config.standard.NBConfigurable;
import java.util.Map;
import java.util.function.BiFunction;
public interface DiagOpTask extends BiFunction<Long,Map<String,Object>, Map<String,Object>>, NBConfigurable {
public interface NBConfigModelExpander {
NBConfigModel apply(Object value);
}

View File

@ -34,19 +34,22 @@ public class Param<T> {
private final T defaultValue;
public boolean required;
private Pattern regex;
private final NBConfigModelExpander expander;
public Param(
List<String> names,
Class<? extends T> type,
String description,
boolean required,
T defaultValue
T defaultValue,
NBConfigModelExpander expander
) {
this.names = names;
this.type = type;
this.description = description;
this.required = required;
this.defaultValue = defaultValue;
this.expander = expander;
}
/**
@ -78,7 +81,7 @@ public class Param<T> {
* @param <V> Generic type for inference.
*/
public static <V> Param<V> optional(List<String> names, Class<V> type) {
return new Param<V>(names, type, null, false, null);
return new Param<V>(names, type, null, false, null, null);
}
/**
@ -92,7 +95,7 @@ public class Param<T> {
* @param <V> Generic type for inference.
*/
public static <V> Param<V> optional(List<String> names, Class<V> type, String description) {
return new Param<V>(names, type, description, false, null);
return new Param<V>(names, type, description, false, null, null);
}
@ -106,7 +109,7 @@ public class Param<T> {
* @param <V> Generic type for inference.
*/
public static <V> Param<V> optional(String name, Class<V> type) {
return new Param<V>(List.of(name), type, null, false, null);
return new Param<V>(List.of(name), type, null, false, null, null);
}
/**
@ -120,7 +123,7 @@ public class Param<T> {
* @param <V> Generic type for inference.
*/
public static <V> Param<V> optional(String name, Class<V> type, String description) {
return new Param<V>(List.of(name), type, description, false, null);
return new Param<V>(List.of(name), type, description, false, null, null);
}
/**
@ -133,7 +136,7 @@ public class Param<T> {
* @return
*/
public static <V> Param<V> defaultTo(String name, V defaultValue) {
return new Param<V>(List.of(name), (Class<V>) defaultValue.getClass(), null, true, defaultValue);
return new Param<V>(List.of(name), (Class<V>) defaultValue.getClass(), null, true, defaultValue, null);
}
/**
@ -146,7 +149,7 @@ public class Param<T> {
* @return
*/
public static <V> Param<V> defaultTo(String name, V defaultValue, String description) {
return new Param<V>(List.of(name), (Class<V>) defaultValue.getClass(), description, true, defaultValue);
return new Param<V>(List.of(name), (Class<V>) defaultValue.getClass(), description, true, defaultValue, null);
}
/**
@ -159,15 +162,15 @@ public class Param<T> {
* @return
*/
public static <V> Param<V> defaultTo(List<String> names, V defaultValue) {
return new Param<V>(names, (Class<V>) defaultValue.getClass(), null, true, defaultValue);
return new Param<V>(names, (Class<V>) defaultValue.getClass(), null, true, defaultValue, null);
}
public static <V> Param<V> required(String name, Class<V> type) {
return new Param<V>(List.of(name), type, null, true, null);
return new Param<V>(List.of(name), type, null, true, null, null);
}
public static <V> Param<V> required(List<String> names, Class<V> type) {
return new Param<V>(names, type, null, true, null);
return new Param<V>(names, type, null, true, null, null);
}
@ -228,7 +231,6 @@ public class Param<T> {
public CheckResult<T> validate(Object value) {
if (value == null) {
if (isRequired()) {
return CheckResult.INVALID(this, null, "Value is null but " + this.getNames() + " is required");
@ -255,6 +257,15 @@ public class Param<T> {
return CheckResult.VALID(this, value, "All validators passed for field '" + getNames() + "'");
}
public NBConfigModelExpander getExpander() {
return this.expander;
}
public Param<T> expand(NBConfigModelExpander expander) {
return new Param<>(names, type, description, required, defaultValue, expander);
}
public final static class CheckResult<T> {
public final Param<T> element;
public final Object value;