mirror of
https://github.com/nosqlbench/nosqlbench.git
synced 2025-01-25 23:16:33 -06:00
directapi mapping logic
This commit is contained in:
parent
de26371496
commit
68c0ba277b
@ -1,8 +1,24 @@
|
|||||||
package io.nosqlbench.driver.direct;
|
package io.nosqlbench.driver.direct;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
public class DirectCall implements Runnable {
|
public class DirectCall implements Runnable {
|
||||||
|
private final Method method;
|
||||||
|
private final Object[] args;
|
||||||
|
private final Object instance;
|
||||||
|
|
||||||
|
public DirectCall(Method method, Object instance, Object[] args) {
|
||||||
|
this.method = method;
|
||||||
|
this.instance = instance;
|
||||||
|
this.args = args;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
try {
|
||||||
|
method.invoke(instance,args);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
package io.nosqlbench.driver.direct;
|
||||||
|
|
||||||
|
import io.nosqlbench.engine.api.activityimpl.OpDispenser;
|
||||||
|
import io.nosqlbench.engine.api.activityimpl.uniform.BaseDriverAdapter;
|
||||||
|
import io.nosqlbench.engine.api.activityimpl.uniform.DriverAdapter;
|
||||||
|
import io.nosqlbench.engine.api.templating.ParsedCommand;
|
||||||
|
import io.nosqlbench.nb.annotations.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This activity type driver allows you to dynamically map any available
|
||||||
|
* Java API which is exposed to the NoSQLBench runtime, executing methods
|
||||||
|
* on this API by name, (optionally) storing named results, and re-using
|
||||||
|
* these named results as arguments to subsequent calls.
|
||||||
|
*
|
||||||
|
* It supports static method dispatch, instance methods, and per-thread
|
||||||
|
* object scoping.
|
||||||
|
*/
|
||||||
|
@Service(value = DriverAdapter.class, selector = "directapi")
|
||||||
|
public class DirectCallAdapter extends BaseDriverAdapter<DirectCall> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Function<String, Optional<Map<String, Object>>>> getStmtRemappers() {
|
||||||
|
return List.of(new DirectCallStmtParser());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Function<ParsedCommand, OpDispenser<DirectCall>> getOpMapper() {
|
||||||
|
return new DirectOpMapper();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package io.nosqlbench.driver.direct;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class DirectCallStmtParser implements Function<String, Optional<Map<String, Object>>> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<Map<String, Object>> apply(String s) {
|
||||||
|
Pattern stmtPattern = Pattern.compile(
|
||||||
|
"(?<package>[a-z](\\.[a-z]+)?)?(?<class>[A-Z]\\w+)(\\.(?<staticfield>\\w+))?(\\.(?<method>\\w+))\\((?<args>.+)\\)"
|
||||||
|
);
|
||||||
|
Matcher matcher = stmtPattern.matcher(s);
|
||||||
|
if (matcher.matches()) {
|
||||||
|
LinkedHashMap<String, Object> map = new LinkedHashMap<>();
|
||||||
|
List.of("package","class","staticfield","method").forEach(n -> {
|
||||||
|
if (matcher.group(n)!=null) {
|
||||||
|
map.put(n,matcher.group(n));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (matcher.group("args")!=null) {
|
||||||
|
String args = matcher.group("args");
|
||||||
|
String[] argsplit = args.split(",");
|
||||||
|
for (int i = 0; i < argsplit.length; i++) {
|
||||||
|
String val = argsplit[i];
|
||||||
|
if (val.startsWith("\\") && val.endsWith("\\")) {
|
||||||
|
val = val.substring(1,val.length()-2);
|
||||||
|
} else if (val.startsWith("'") && val.endsWith("'")) {
|
||||||
|
val = val.substring(1,val.length()-2);
|
||||||
|
}
|
||||||
|
map.put("_arg"+i,argsplit[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Optional.of(map);
|
||||||
|
} else {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,25 +1,76 @@
|
|||||||
package io.nosqlbench.driver.direct;
|
package io.nosqlbench.driver.direct;
|
||||||
|
|
||||||
import io.nosqlbench.engine.api.activityconfig.yaml.OpTemplate;
|
|
||||||
import io.nosqlbench.engine.api.activityimpl.OpDispenser;
|
import io.nosqlbench.engine.api.activityimpl.OpDispenser;
|
||||||
|
import io.nosqlbench.engine.api.templating.ParsedCommand;
|
||||||
|
import io.nosqlbench.nb.api.errors.OpConfigError;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.function.LongFunction;
|
import java.util.function.LongFunction;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class DirectOpMapper implements OpDispenser<DirectCall> {
|
public class DirectOpMapper implements Function<ParsedCommand, OpDispenser<DirectCall>> {
|
||||||
|
|
||||||
private final OpTemplate opTemplate;
|
@Override
|
||||||
private final LongFunction<DirectCall> readyOp;
|
public OpDispenser<DirectCall> apply(ParsedCommand cmd) {
|
||||||
|
|
||||||
public DirectOpMapper(OpTemplate opTemplate) {
|
String pkg = cmd.getStaticValueOptionally("package", String.class).orElse("java.lang");
|
||||||
this.opTemplate = opTemplate;
|
String cls = cmd.getStaticValue("class");
|
||||||
this.readyOp = resolve(opTemplate);
|
String fq = pkg + "." + cls;
|
||||||
}
|
Class<?> clazz = null;
|
||||||
|
Object instance = null;
|
||||||
|
try {
|
||||||
|
clazz = Class.forName(fq);
|
||||||
|
|
||||||
private LongFunction<DirectCall> resolve(OpTemplate opTemplate) {
|
Class<?> finalClazz = clazz;
|
||||||
return new DynamicCallDispenser(opTemplate);
|
Optional<Field> staticfield =
|
||||||
}
|
cmd.getStaticValueOptionally("staticfield", String.class)
|
||||||
|
.map(name -> {
|
||||||
|
try {
|
||||||
|
return finalClazz.getDeclaredField(name);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
if (staticfield.isPresent()) {
|
||||||
|
Field sfield = staticfield.get();
|
||||||
|
if ((sfield.getModifiers() | Modifier.STATIC) > 0) {
|
||||||
|
instance = sfield.get(null);
|
||||||
|
clazz = instance.getClass();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new OpConfigError("staticfield '" + cmd.getStaticValue("staticfield", String.class) + "' is not static");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
String methodName = cmd.getStaticValue("method");
|
||||||
|
|
||||||
|
Map<String, Object> protomap = cmd.getMap(0L);
|
||||||
|
List<Class<?>> protoargs = new ArrayList<>();
|
||||||
|
List<String> argnames = protomap.keySet().stream()
|
||||||
|
.filter(n -> n.startsWith("_"))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
LongFunction<List<Object>> argsbinder = cmd.newListBinder(argnames);
|
||||||
|
List<Object> args = argsbinder.apply(0L);
|
||||||
|
List<Class<?>> types = args.stream().map(Object::getClass).collect(Collectors.toList());
|
||||||
|
|
||||||
|
Class<?>[] argTypes = types.toArray(new Class<?>[0]);
|
||||||
|
|
||||||
|
Method method = null;
|
||||||
|
try {
|
||||||
|
method = clazz.getMethod(methodName, argTypes);
|
||||||
|
return new StaticMethodOpDispenser(method, instance, cmd.newArrayBinder(argnames));
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
public DirectCall apply(long value) {
|
|
||||||
return readyOp.apply(value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
package io.nosqlbench.driver.direct;
|
||||||
|
|
||||||
|
import io.nosqlbench.engine.api.activityimpl.OpDispenser;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.function.LongFunction;
|
||||||
|
|
||||||
|
public class StaticMethodOpDispenser implements OpDispenser<DirectCall> {
|
||||||
|
private final LongFunction<Object[]> argsfunc;
|
||||||
|
private final Method method;
|
||||||
|
private final Object instance;
|
||||||
|
|
||||||
|
public StaticMethodOpDispenser(Method method, Object instance, LongFunction<Object[]> argsfunc) {
|
||||||
|
this.method = method;
|
||||||
|
this.instance = instance;
|
||||||
|
this.argsfunc = argsfunc;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DirectCall apply(long value) {
|
||||||
|
Object[] args = argsfunc.apply(value);
|
||||||
|
return new DirectCall(method, instance, args);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
io.nosqlbench.nb.annotations.ServiceProcessor
|
@ -4,6 +4,7 @@ This is a unique type of NoSQLBench driver which assumes no particular
|
|||||||
runtime API, instead relying on runtime reflection to find and invoke
|
runtime API, instead relying on runtime reflection to find and invoke
|
||||||
the methods as specified in the op template.
|
the methods as specified in the op template.
|
||||||
|
|
||||||
|
Presently, therea re two
|
||||||
```yaml
|
```yaml
|
||||||
statements:
|
statements:
|
||||||
- "java.lang.System.out.println(\"Testing\");"
|
- "java.lang.System.out.println(\"Testing\");"
|
||||||
@ -13,10 +14,10 @@ statements:
|
|||||||
class: java.lang.System
|
class: java.lang.System
|
||||||
field: out
|
field: out
|
||||||
method: println
|
method: println
|
||||||
arg0: Testing
|
_arg0: Testing
|
||||||
- op:
|
- op:
|
||||||
class: java.lang.System
|
class: java.lang.System
|
||||||
field: out
|
staticfield: out
|
||||||
method: println
|
method: println
|
||||||
_x: Testing
|
_x: Testing
|
||||||
- op:
|
- op:
|
||||||
|
Loading…
Reference in New Issue
Block a user