remove deprecated CommandTemplate

This commit is contained in:
Jonathan Shook 2023-12-08 19:37:06 -06:00
parent 59f40b36f4
commit c46e097e50
4 changed files with 2 additions and 453 deletions

View File

@ -1,342 +0,0 @@
/*
* Copyright (c) 2022-2023 nosqlbench
*
* Licensed 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 io.nosqlbench.adapters.api.templating;
import io.nosqlbench.adapters.api.activityconfig.yaml.OpTemplate;
import io.nosqlbench.nb.api.config.params.ParamsParser;
import io.nosqlbench.nb.api.errors.BasicError;
import io.nosqlbench.virtdata.core.bindings.BindingsTemplate;
import io.nosqlbench.virtdata.core.templates.ParsedTemplateString;
import io.nosqlbench.virtdata.core.templates.StringBindings;
import io.nosqlbench.virtdata.core.templates.StringBindingsTemplate;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import java.util.*;
import java.util.function.Function;
/**
* This is a general purpose template which uses a map of named parameters.
* The result is a template which is comprised of a map of names and values, which can
* be used to create a cycle-specific map of values that can describe a literal operation
* for some native driver. How this map is used is context dependent.
*
* Generally speaking, the properties in this map are taken as parameters or field values,
* or a command verb. How the keys in the resulting map are used to construct an operation
* for execution is entirely dependent on how a developer wants to map these fields to
* a native driver's API.
*
* A CommandTemplate can be crated directly, or from an OpTemplate. Additional map parsers
* may be provided when needed for specialized forms of syntax or variations which should also
* be supported. See the constructor docs for details on these variations.
*/
@Deprecated(forRemoval = true)
public class CommandTemplate {
private final static Logger logger = LogManager.getLogger(CommandTemplate.class);
private final String name;
private final Map<String, String> statics = new HashMap<>();
private final Map<String, StringBindings> dynamics = new HashMap<>();
transient private final int mapsize;
/**
* Create a CommandTemplate directly from an OpTemplate.
*
* In this form, if {@link OpTemplate#getOp()}
* is non-null, then it taken as a line-oriented value and parsed according to default {@link ParamsParser} behavior.
*
* Additionally, any op params provided are considered as entries to add to the command template's map.
*
* @param optpl An OpTemplate
*/
public CommandTemplate(OpTemplate optpl) {
this(optpl.getName(), optpl.getOp().toString(), optpl.getParamsAsValueType(String.class), optpl.getBindings(), List.of());
}
/**
* Create a CommandTemplate directly from an OpTemplate, as in {@link #CommandTemplate(OpTemplate)},
* with added support for parsing the oneline form with the provided parsers.
*
* In this form, if {@link OpTemplate#getOp()}
* is non-null, then it taken as a line-oriented value and parsed according to default {@link ParamsParser} behavior.
* However, the provided parsers (if any) are used first in order to match alternate forms of syntax.
*
* See {@link CommandTemplate#CommandTemplate(String, String, Map, Map, List)} for full details on the provided
* parsers.
*
* @param optpl An OpTemplate
* @param parsers A list of parser functions
*/
public CommandTemplate(OpTemplate optpl, List<Function<String, Map<String, String>>> parsers) {
this(optpl.getName(), optpl.getStmt().orElseThrow(), optpl.getParamsAsValueType(String.class), optpl.getBindings(), parsers);
}
/**
* Create a command template from a set of optional properties.
*
* <P>The parsers provided should honor these expectations:
* <UL>
* <LI>If the one-line format is not recognized, the parser should return null.</LI>
* <LI>If the one-line format is recognized, and the values provided are valid, then they should be
* returned as a {@link Map} of {@link String} to {@link String}.</LI>
* <LI>Otherwise the parser should throw an exception, signifying either an internal parser error or
* invalid data.</LI>
* </UL>
*
* If none of the provided parsers (if any) return a map of values for the one-line format, then the default
* behavior of {@link ParamsParser} is used.
* </P>
*
* @param name The name of the command template
* @param op An object version of the parameters to be parsed by {@link ParamsParser}
* @param params A set of named parameters and values in name:value form.
* @param bindings A set of named bindings in name:recipe form.
* @param optionalParsers A set of functions which, if provided, will be used to read the oneline form.
*/
public CommandTemplate(
String name,
String op,
Map<String, String> params,
Map<String, String> bindings,
List<Function<String, Map<String, String>>> optionalParsers
) {
this.name = name;
Map<String, String> cmd = new HashMap<>();
// Only parse and inject the one-line form if it is defined.
// The first parser to match and return a map will be the last one tried.
// If none of the supplemental parsers work, the default params parser is used
String oneline;
if (op instanceof CharSequence) {
oneline = op;
} else {
throw new BasicError("Unable to create a oneline version of the CommandTemplate with op type of " + op.getClass().getSimpleName());
}
if (oneline != null) {
List<Function<String, Map<String, String>>> parserlist = new ArrayList<>(optionalParsers);
parserlist.add(s -> ParamsParser.parse(s, false));
boolean didParse = false;
for (Function<String, Map<String, String>> parser : parserlist) {
Map<String, String> parsed = parser.apply(oneline);
if (parsed != null) {
logger.debug(() -> "parsed request: " + parsed);
cmd.putAll(parsed);
didParse = true;
break;
}
}
if (!didParse) {
throw new RuntimeException("A oneline form was provided for the command template, but none of the " +
"provided" +
" parsers were able to parse it, not even ParamsParser.parse(...)");
}
}
// Always add the named params, but warn if they overwrite any oneline named params
params.forEach((k, v) -> {
if (cmd.containsKey(k)) {
logger.warn("command property override: '" + k + "' superseded by param form with value '" + v + "'");
}
});
cmd.putAll(params);
cmd.forEach((param, value) -> {
ParsedTemplateString paramTemplate = new ParsedTemplateString(value, bindings);
if (paramTemplate.getBindPoints().size() > 0) {
BindingsTemplate paramBindings = new BindingsTemplate(paramTemplate.getBindPoints());
StringBindings paramStringBindings = new StringBindingsTemplate(value, paramBindings).resolve();
dynamics.put(param, paramStringBindings);
} else {
statics.put(param, value);
}
});
this.mapsize = statics.size() + dynamics.size();
}
/**
* Apply the provided binding functions to the command template, yielding a map with concrete values
* to be used by a native command.
*
* @param cycle The cycle value which will be used by the binding functions
* @return A map of specific values
*/
public Map<String, String> getCommand(long cycle) {
HashMap<String, String> map = new HashMap<>(mapsize);
map.putAll(statics);
dynamics.forEach((k, v) -> {
map.put(k, v.bind(cycle));
});
return map;
}
/**
* The name of the operation
*/
public String getName() {
return name;
}
/**
* True if the command template contains all static (non-binding) values.
*/
public boolean isStatic() {
return this.dynamics.size() == 0;
}
public boolean isStatic(String keyname) {
return this.statics.containsKey(keyname);
}
public boolean isStaticSet(String... keynames) {
for (String keyname : keynames) {
if (!isStatic(keyname)) {
return false;
}
}
return true;
}
public boolean isDynamicSet(String... keynames) {
for (String keyname : keynames) {
if (!isDynamic(keyname)) {
return false;
}
}
return true;
}
public boolean isDynamic(String keyname) {
return this.dynamics.containsKey(keyname);
}
public boolean containsKey(String keyname) {
return this.statics.containsKey(keyname) || this.dynamics.containsKey(keyname);
}
/**
* The set of key names known by this command template.
*/
public Set<String> getPropertyNames() {
return this.statics.keySet();
}
@Override
public String toString() {
return "CommandTemplate{" +
"name='" + name + '\'' +
", statics=" + statics +
", dynamics=" + dynamics +
'}';
}
public String getStatic(String staticVar) {
return statics.get(staticVar);
}
public String getDynamic(String dynamicVar, long input) {
return dynamics.get(dynamicVar).bind(input);
}
public String get(String var, long input) {
if (statics.containsKey(var)) {
return statics.get(var);
}
if (dynamics.containsKey(var)) {
return dynamics.get(var).bind(input);
}
return null;
}
public String getOr(String var, long input, String defaultVal) {
if (statics.containsKey(var)) {
return statics.get(var);
}
if (dynamics.containsKey(var)) {
return dynamics.get(var).bind(input);
}
return defaultVal;
}
public String getStaticOr(String staticVar, String defaultVal) {
if (statics.containsKey(staticVar)) {
return statics.get(staticVar);
}
return defaultVal;
}
public String getDynamicOr(String dynamicVar, long input, String defaultVal) {
if (dynamics.containsKey(dynamicVar)) {
return getDynamic(dynamicVar, input);
} else {
return defaultVal;
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CommandTemplate that = (CommandTemplate) o;
return Objects.equals(name, that.name) && Objects.equals(statics, that.statics) && Objects.equals(dynamics, that.dynamics);
}
@Override
public int hashCode() {
return Objects.hash(name, statics, dynamics);
}
public boolean containsAny(String... varNames) {
for (String varName : varNames) {
if (this.containsKey(varName)) {
return true;
}
}
return false;
}
public boolean isStaticOrUnsetSet(String... varnames) {
for (String varname : varnames) {
if (isDynamic(varname)) {
return false;
}
}
return true;
}
/**
* This should only be used to provide a view of a field definition, never for actual use in a payload.
* @param varname The field name which you want to explain
* @return A string representation of the field name
*/
public String getFieldDescription(String varname) {
if (this.isDynamic(varname)) {
return "dynamic: " + this.dynamics.get(varname).toString();
} else if (this.isStatic(varname)) {
return "static: " + this.getStatic(varname);
} else {
return "UNDEFINED";
}
}
}

View File

@ -38,7 +38,7 @@ To clarify the differences, here are some basic examples:
jmxOp.execute();
kafkaSequencer.get(cycle).write(cycle);
mongoResultDoc = activity.getDatabase().runCommand(queryBson, rms.getReadPreference());
WebDriverVerbs.execute(cycle, commandTemplate, context, dryrun);
WebDriverVerbs.execute(cycle, cmdTemplate, context, dryrun);
ActivityType<A extends Activity>

View File

@ -51,7 +51,6 @@ import io.nosqlbench.adapters.api.activityimpl.uniform.DriverAdapter;
import io.nosqlbench.adapters.api.activityimpl.uniform.DryRunOpDispenserWrapper;
import io.nosqlbench.adapters.api.activityimpl.uniform.decorators.SyntheticOpTemplateProvider;
import io.nosqlbench.adapters.api.activityimpl.uniform.flowtypes.Op;
import io.nosqlbench.adapters.api.templating.CommandTemplate;
import io.nosqlbench.adapters.api.templating.ParsedOp;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@ -416,31 +415,6 @@ public class SimpleActivity extends NBBaseComponent implements Activity {
}
}
/**
* Given a function that can create an op of type <O> from a CommandTemplate, generate
* an indexed sequence of ready to call operations.
* <p>
* This method works almost exactly like the ,
* except that it uses the {@link CommandTemplate} semantics, which are more general and allow
* for map-based specification of operations with bindings in each field.
* <p>
* It is recommended to use the CommandTemplate form
* than the
*
* @param <O>
* @param opinit
* @param strict
* @return
*/
protected <O extends Op> OpSequence<OpDispenser<? extends O>> createOpSequenceFromCommands(
Function<CommandTemplate, OpDispenser<O>> opinit,
boolean strict
) {
Function<OpTemplate, CommandTemplate> f = CommandTemplate::new;
Function<OpTemplate, OpDispenser<? extends O>> opTemplateOFunction = f.andThen(opinit);
return createOpSequence(opTemplateOFunction, strict, Optional.empty());
}
protected <O extends Op> OpSequence<OpDispenser<? extends O>> createOpSourceFromParsedOps(
Map<String, DriverAdapter> adapterCache,
@ -502,27 +476,7 @@ public class SimpleActivity extends NBBaseComponent implements Activity {
}
protected <O extends Op> OpSequence<OpDispenser<? extends O>> createOpSourceFromCommands(
Function<ParsedOp, OpDispenser<? extends O>> opinit,
NBConfiguration cfg,
List<Function<Map<String, Object>, Map<String, Object>>> parsers,
boolean strict
) {
Function<OpTemplate, ParsedOp> f = t -> new ParsedOp(t, cfg, parsers, this);
Function<OpTemplate, OpDispenser<? extends O>> opTemplateOFunction = f.andThen(opinit);
return createOpSequence(opTemplateOFunction, strict, Optional.empty());
}
protected List<ParsedOp> loadParsedOps(NBConfiguration cfg, Optional<DriverAdapter> defaultAdapter) {
List<ParsedOp> parsedOps = loadOpTemplates(defaultAdapter).stream().map(
ot -> new ParsedOp(ot, cfg, List.of(), this)
).toList();
return parsedOps;
}
protected List<OpTemplate> loadOpTemplates(Optional<DriverAdapter> defaultDriverAdapter) {
protected List<OpTemplate> loadOpTemplates(Optional<DriverAdapter<?,?>> defaultDriverAdapter) {
String tagfilter = activityDef.getParams().getOptionalString("tags").orElse("");

View File

@ -1,63 +0,0 @@
/*
* Copyright (c) 2022-2023 nosqlbench
*
* Licensed 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 io.nosqlbench.engine.api.templating;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import io.nosqlbench.adapters.api.activityconfig.OpsLoader;
import io.nosqlbench.adapters.api.activityconfig.yaml.OpTemplate;
import io.nosqlbench.adapters.api.activityconfig.yaml.OpTemplateFormat;
import io.nosqlbench.adapters.api.activityconfig.yaml.OpsDocList;
import io.nosqlbench.adapters.api.templating.CommandTemplate;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.jupiter.api.Test;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
public class CommandTemplateTest {
private final static Logger logger = LogManager.getLogger(CommandTemplateTest.class);
@Test
public void testCommandTemplate() {
OpsDocList opsDocs = OpsLoader.loadString("ops:\n" +
" - s1: test1=foo test2=bar",
OpTemplateFormat.yaml, Map.of(), null);
OpTemplate optpl = opsDocs.getOps(true).get(0);
CommandTemplate ct = new CommandTemplate(optpl);
assertThat(ct.isStatic()).isTrue();
}
@Test
public void testCommandTemplateFormat() {
Gson gson = new GsonBuilder().setPrettyPrinting().create();
OpsDocList stmtsDocs = OpsLoader.loadString("ops:\n" +
" - s1: test1=foo test2={bar}\n" +
" bindings:\n" +
" bar: NumberNameToString();\n",
OpTemplateFormat.yaml, Map.of(), null
);
OpTemplate optpl = stmtsDocs.getOps(true).get(0);
CommandTemplate ct = new CommandTemplate(optpl);
String format = gson.toJson(ct);
logger.debug(format);
}
}