From 68c0ba277b96a519ea6faae46544f9e38d983515 Mon Sep 17 00:00:00 2001 From: Jonathan Shook Date: Tue, 6 Jul 2021 11:11:12 -0500 Subject: [PATCH] directapi mapping logic --- .../nosqlbench/driver/direct/DirectCall.java | 18 ++++- .../driver/direct/DirectCallAdapter.java | 35 +++++++++ .../driver/direct/DirectCallStmtParser.java | 44 +++++++++++ .../driver/direct/DirectOpMapper.java | 77 +++++++++++++++---- .../direct/StaticMethodOpDispenser.java | 24 ++++++ .../javax.annotation.processing.Processor | 1 + driver-direct/src/main/resources/direct.md | 5 +- 7 files changed, 188 insertions(+), 16 deletions(-) create mode 100644 driver-direct/src/main/java/io/nosqlbench/driver/direct/DirectCallAdapter.java create mode 100644 driver-direct/src/main/java/io/nosqlbench/driver/direct/DirectCallStmtParser.java create mode 100644 driver-direct/src/main/java/io/nosqlbench/driver/direct/StaticMethodOpDispenser.java create mode 100644 driver-direct/src/main/resources/META-INF/services/javax.annotation.processing.Processor diff --git a/driver-direct/src/main/java/io/nosqlbench/driver/direct/DirectCall.java b/driver-direct/src/main/java/io/nosqlbench/driver/direct/DirectCall.java index 4ef98c41a..7bcfdcf88 100644 --- a/driver-direct/src/main/java/io/nosqlbench/driver/direct/DirectCall.java +++ b/driver-direct/src/main/java/io/nosqlbench/driver/direct/DirectCall.java @@ -1,8 +1,24 @@ package io.nosqlbench.driver.direct; +import java.lang.reflect.Method; + 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 public void run() { - + try { + method.invoke(instance,args); + } catch (Exception e) { + throw new RuntimeException(e); + } } } diff --git a/driver-direct/src/main/java/io/nosqlbench/driver/direct/DirectCallAdapter.java b/driver-direct/src/main/java/io/nosqlbench/driver/direct/DirectCallAdapter.java new file mode 100644 index 000000000..631d72d4a --- /dev/null +++ b/driver-direct/src/main/java/io/nosqlbench/driver/direct/DirectCallAdapter.java @@ -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 { + + @Override + public List>>> getStmtRemappers() { + return List.of(new DirectCallStmtParser()); + } + + @Override + public Function> getOpMapper() { + return new DirectOpMapper(); + } +} diff --git a/driver-direct/src/main/java/io/nosqlbench/driver/direct/DirectCallStmtParser.java b/driver-direct/src/main/java/io/nosqlbench/driver/direct/DirectCallStmtParser.java new file mode 100644 index 000000000..218230409 --- /dev/null +++ b/driver-direct/src/main/java/io/nosqlbench/driver/direct/DirectCallStmtParser.java @@ -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>> { + + @Override + public Optional> apply(String s) { + Pattern stmtPattern = Pattern.compile( + "(?[a-z](\\.[a-z]+)?)?(?[A-Z]\\w+)(\\.(?\\w+))?(\\.(?\\w+))\\((?.+)\\)" + ); + Matcher matcher = stmtPattern.matcher(s); + if (matcher.matches()) { + LinkedHashMap 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(); + } + } +} diff --git a/driver-direct/src/main/java/io/nosqlbench/driver/direct/DirectOpMapper.java b/driver-direct/src/main/java/io/nosqlbench/driver/direct/DirectOpMapper.java index cd7692f4f..7e2420a40 100644 --- a/driver-direct/src/main/java/io/nosqlbench/driver/direct/DirectOpMapper.java +++ b/driver-direct/src/main/java/io/nosqlbench/driver/direct/DirectOpMapper.java @@ -1,25 +1,76 @@ 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.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.stream.Collectors; -public class DirectOpMapper implements OpDispenser { +public class DirectOpMapper implements Function> { - private final OpTemplate opTemplate; - private final LongFunction readyOp; + @Override + public OpDispenser apply(ParsedCommand cmd) { - public DirectOpMapper(OpTemplate opTemplate) { - this.opTemplate = opTemplate; - this.readyOp = resolve(opTemplate); - } + String pkg = cmd.getStaticValueOptionally("package", String.class).orElse("java.lang"); + String cls = cmd.getStaticValue("class"); + String fq = pkg + "." + cls; + Class clazz = null; + Object instance = null; + try { + clazz = Class.forName(fq); - private LongFunction resolve(OpTemplate opTemplate) { - return new DynamicCallDispenser(opTemplate); - } + Class finalClazz = clazz; + Optional 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 protomap = cmd.getMap(0L); + List> protoargs = new ArrayList<>(); + List argnames = protomap.keySet().stream() + .filter(n -> n.startsWith("_")) + .collect(Collectors.toList()); + + LongFunction> argsbinder = cmd.newListBinder(argnames); + List args = argsbinder.apply(0L); + List> 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); } } diff --git a/driver-direct/src/main/java/io/nosqlbench/driver/direct/StaticMethodOpDispenser.java b/driver-direct/src/main/java/io/nosqlbench/driver/direct/StaticMethodOpDispenser.java new file mode 100644 index 000000000..bb7df96aa --- /dev/null +++ b/driver-direct/src/main/java/io/nosqlbench/driver/direct/StaticMethodOpDispenser.java @@ -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 { + private final LongFunction argsfunc; + private final Method method; + private final Object instance; + + public StaticMethodOpDispenser(Method method, Object instance, LongFunction 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); + } +} diff --git a/driver-direct/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/driver-direct/src/main/resources/META-INF/services/javax.annotation.processing.Processor new file mode 100644 index 000000000..ceb8ce941 --- /dev/null +++ b/driver-direct/src/main/resources/META-INF/services/javax.annotation.processing.Processor @@ -0,0 +1 @@ +io.nosqlbench.nb.annotations.ServiceProcessor diff --git a/driver-direct/src/main/resources/direct.md b/driver-direct/src/main/resources/direct.md index 452636134..0e01e5867 100644 --- a/driver-direct/src/main/resources/direct.md +++ b/driver-direct/src/main/resources/direct.md @@ -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 the methods as specified in the op template. +Presently, therea re two ```yaml statements: - "java.lang.System.out.println(\"Testing\");" @@ -13,10 +14,10 @@ statements: class: java.lang.System field: out method: println - arg0: Testing + _arg0: Testing - op: class: java.lang.System - field: out + staticfield: out method: println _x: Testing - op: