From 87a1dcd95770e74db5671d3e9131ad60e866b9c7 Mon Sep 17 00:00:00 2001 From: rschoene <rene.schoene@tu-dresden.de> Date: Mon, 2 May 2022 11:06:34 +0200 Subject: [PATCH 1/7] Updated initial version of Java handler. - also missing fix for CI (ragdoc-view should always run) --- .gitlab-ci.yml | 3 - .../src/main/jastadd/Handlers.jrag | 1 + .../jastadd/ragconnect/compiler/Compiler.java | 3 + .../src/main/resources/JavaHandler.mustache | 88 +++++++++++++++++++ .../src/main/resources/handler.mustache | 10 ++- .../main/resources/receiveDefinition.mustache | 12 +++ .../main/resources/sendDefinition.mustache | 22 +++++ ragconnect.tests/build.gradle | 29 +++++- .../src/test/01-input/java/README.md | 3 + .../src/test/01-input/java/Test.connect | 25 ++++++ .../src/test/01-input/java/Test.jadd | 30 +++++++ .../src/test/01-input/java/Test.relast | 9 ++ .../jastadd/ragconnect/tests/JavaTest.java | 43 +++++++++ 13 files changed, 270 insertions(+), 8 deletions(-) create mode 100644 ragconnect.base/src/main/resources/JavaHandler.mustache create mode 100644 ragconnect.tests/src/test/01-input/java/README.md create mode 100644 ragconnect.tests/src/test/01-input/java/Test.connect create mode 100644 ragconnect.tests/src/test/01-input/java/Test.jadd create mode 100644 ragconnect.tests/src/test/01-input/java/Test.relast create mode 100644 ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/JavaTest.java diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 87d2c9c..44a279a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -94,9 +94,6 @@ ragdoc_view: - OUTPUT_DIR=$(pwd -P)/pages/docs/ragdoc - cd /ragdoc-view/src/ && rm -rf data && ln -s $DATA_DIR - /ragdoc-view/build-view.sh --output-path=$OUTPUT_DIR - only: - - dev - - master artifacts: paths: - "pages/docs/ragdoc" diff --git a/ragconnect.base/src/main/jastadd/Handlers.jrag b/ragconnect.base/src/main/jastadd/Handlers.jrag index 57c7ccd..e64a8c5 100644 --- a/ragconnect.base/src/main/jastadd/Handlers.jrag +++ b/ragconnect.base/src/main/jastadd/Handlers.jrag @@ -1,4 +1,5 @@ aspect RagConnectHandlers { + syn Handler RagConnect.javaHandler() = resolveHandlerByName("java"); syn Handler RagConnect.mqttHandler() = resolveHandlerByName("mqtt"); syn Handler RagConnect.restHandler() = resolveHandlerByName("rest"); diff --git a/ragconnect.base/src/main/java/org/jastadd/ragconnect/compiler/Compiler.java b/ragconnect.base/src/main/java/org/jastadd/ragconnect/compiler/Compiler.java index 8d4ab2c..e255b3b 100644 --- a/ragconnect.base/src/main/java/org/jastadd/ragconnect/compiler/Compiler.java +++ b/ragconnect.base/src/main/java/org/jastadd/ragconnect/compiler/Compiler.java @@ -35,6 +35,7 @@ public class Compiler extends AbstractCompiler { private static final String OPTION_LOGGING_TARGET_CONSOLE = "console"; private static final String OPTION_LOGGING_TARGET_SLF4J = "slf4j"; + private static final String OPTION_PROTOCOL_JAVA = "java"; private static final String OPTION_PROTOCOL_MQTT = "mqtt"; private static final String OPTION_PROTOCOL_REST = "rest"; @@ -179,6 +180,7 @@ public class Compiler extends AbstractCompiler { new ValueOption("protocols", "Protocols to enable") .acceptMultipleValues(true) .addDefaultValue(OPTION_PROTOCOL_MQTT, "Enable MQTT") + .addAcceptedValue(OPTION_PROTOCOL_JAVA, "Enable Java") .addAcceptedValue(OPTION_PROTOCOL_REST, "Enable REST") ); optionPrintYaml = addOption( @@ -331,6 +333,7 @@ public class Compiler extends AbstractCompiler { ragConnect.getConfiguration().setRootNode(rootNode); // Handler ::= <ClassName> <UniqueName> <InUse:boolean>; + ragConnect.addHandler(new Handler("JavaHandler", "java", optionProtocols.hasValue(OPTION_PROTOCOL_JAVA))); ragConnect.addHandler(new Handler("MqttServerHandler", "mqtt", optionProtocols.hasValue(OPTION_PROTOCOL_MQTT))); ragConnect.addHandler(new Handler("RestServerHandler", "rest", optionProtocols.hasValue(OPTION_PROTOCOL_REST))); } diff --git a/ragconnect.base/src/main/resources/JavaHandler.mustache b/ragconnect.base/src/main/resources/JavaHandler.mustache new file mode 100644 index 0000000..bc73c91 --- /dev/null +++ b/ragconnect.base/src/main/resources/JavaHandler.mustache @@ -0,0 +1,88 @@ +/** + * Singleton class providing routing functionality for byte[] based message calls. + */ +public class JavaHandler { + public static JavaHandler JAVA_HANDLER_INSTANCE = null; + private java.util.Map<String, java.util.List<Pair<String, java.util.function.BiConsumer<String, byte[]>>>> callbackList = new java.util.concurrent.ConcurrentHashMap<>(); + private String name; + + private JavaHandler() { + this("RagConnect"); + } + + public JavaHandler(String name) { + this.name = name; + } + + public synchronized static JavaHandler getInstance() { + if (JAVA_HANDLER_INSTANCE == null) { + JAVA_HANDLER_INSTANCE = new JavaHandler(); + } + return JAVA_HANDLER_INSTANCE; + } + + public String registerCallback(String topic, java.util.function.BiConsumer<String, byte[]> callback) { + {{logInfo}}("[JAVA_HANDLER] Registering new callback for {{log_}}.", topic); + + String callbackUUID = java.util.UUID.randomUUID().toString(); + + java.util.List<Pair<String, java.util.function.BiConsumer<String, byte[]>>> registeredCallbacks = getAllCallbacks().get(topic); + + if (registeredCallbacks == null) { + java.util.List<Pair<String, java.util.function.BiConsumer<String, byte[]>>> newCallbackList = java.util.Collections.synchronizedList(new java.util.ArrayList<>()); + newCallbackList.add(new Pair<>(callbackUUID, callback)); + callbackList.put(topic, newCallbackList); + } else { + registeredCallbacks.add(new Pair<>(callbackUUID, callback)); + } + + return callbackUUID; + } + + public boolean unregisterCallback(String path, String uuid) { + {{logInfo}}("[JAVA_HANDLER] Unregistering callback with uuid: {{log_}}", uuid + " on path: {{log_}}", path); + + java.util.List<Pair<String, java.util.function.BiConsumer<String, byte[]>>> callbacks = getAllCallbacks().get(path); + + int count = 0; + + if (callbacks != null) { + for (Pair<String, java.util.function.BiConsumer<String, byte[]>> callbackPair : callbacks) { + if (callbackPair._1.equals(uuid)) { + callbacks.remove(count); + return true; + } else { + count++; + } + } + } + return false; + } + + public void close() { + } + + public boolean push(String topic, byte[] data) { + {{logDebug}}("[JAVA_HANDLER] Pushing a message."); + String dataString = new String(data); + {{logDebug}}("[JAVA_HANDLER] Data: {{log_}}", dataString); + + java.util.List<Pair<String, java.util.function.BiConsumer<String, byte[]>>> callbacks = getAllCallbacks().get(topic); + + if (callbacks == null) { + {{logError}}("[JAVA_HANDLER] Could not publish message. No callback registered for topic {{log_}}", topic); + return false; + } + + for (Pair<String, java.util.function.BiConsumer<String, byte[]>> callbackPair : callbacks) { + {{logDebug}}("[JAVA_HANDLER] Calling callback: {{log_}}", callbackPair._1); + callbackPair._2.accept(topic, data); + } + + return true; + } + + public java.util.Map<String, java.util.List<Pair<String, java.util.function.BiConsumer<String, byte[]>>>> getAllCallbacks() { + return callbackList; + } +} diff --git a/ragconnect.base/src/main/resources/handler.mustache b/ragconnect.base/src/main/resources/handler.mustache index 4919426..2c4cf96 100644 --- a/ragconnect.base/src/main/resources/handler.mustache +++ b/ragconnect.base/src/main/resources/handler.mustache @@ -19,18 +19,24 @@ aspect RagConnectHandler { {{/configIncrementalOptionActive}} } +{{#javaHandler}} + {{#InUse}} + {{> JavaHandler}} + {{/InUse}} +{{/javaHandler}} + {{#mqttHandler}} {{#InUse}} public void {{rootNodeName}}.{{setupWaitUntilReadyMethodName}}(long time, java.util.concurrent.TimeUnit unit) { {{fieldName}}.setupWaitUntilReady(time, unit); } + {{> MqttHandler}} {{/InUse}} -{{> MqttHandler}} {{/mqttHandler}} {{#restHandler}} {{#InUse}} -{{> RestHandler}} + {{> RestHandler}} {{/InUse}} {{/restHandler}} diff --git a/ragconnect.base/src/main/resources/receiveDefinition.mustache b/ragconnect.base/src/main/resources/receiveDefinition.mustache index cb4dc8d..c4f070c 100644 --- a/ragconnect.base/src/main/resources/receiveDefinition.mustache +++ b/ragconnect.base/src/main/resources/receiveDefinition.mustache @@ -93,6 +93,13 @@ private boolean {{parentTypeName}}.{{internalConnectMethodName}}(String {{connec RagConnectToken connectToken = new RagConnectToken(uri, "{{entityName}}"); boolean success; switch (scheme) { + {{#javaHandler}} + {{#InUse}} + case "java": + success = {{attributeName}}().registerCallback(path, consumer, connectToken); + break; + {{/InUse}} + {{/javaHandler}} {{#mqttHandler}} {{#InUse}} case "mqtt": @@ -130,6 +137,11 @@ public boolean {{parentTypeName}}.{{disconnectMethodName}}(String {{connectParam } RagConnectDisconnectHandlerMethod disconnectingMethod; switch (scheme) { + {{#javaHandler}} + {{#InUse}} + case "java": return {{attributeName}}().unregisterCallback(uri.getPath(), connectTokens.get(this).get(uri).globalId); + {{/InUse}} + {{/javaHandler}} {{#mqttHandler}} {{#InUse}} case "mqtt": disconnectingMethod = {{attributeName}}()::disconnect; diff --git a/ragconnect.base/src/main/resources/sendDefinition.mustache b/ragconnect.base/src/main/resources/sendDefinition.mustache index 1e66fde..1485c17 100644 --- a/ragconnect.base/src/main/resources/sendDefinition.mustache +++ b/ragconnect.base/src/main/resources/sendDefinition.mustache @@ -5,6 +5,21 @@ public boolean {{parentTypeName}}.{{connectMethodName}}(String {{connectParamete RagConnectToken connectToken = new RagConnectToken(uri, "{{entityName}}"); boolean success; switch (scheme) { + {{#javaHandler}} + {{#InUse}} + case "java": + final JavaHandler handler = {{attributeName}}().getInstance(); + + {{senderName}}.add(() -> { + handler.push(path, {{lastValueGetterCall}}); + }{{#IndexBasedListAccess}}, index{{/IndexBasedListAccess}}, connectToken); + {{updateMethodName}}(); + if (writeCurrentValue) { + {{writeMethodName}}({{#IndexBasedListAccess}}index, {{/IndexBasedListAccess}}connectToken); + } + break; + {{/InUse}} + {{/javaHandler}} {{#mqttHandler}} {{#InUse}} case "mqtt": @@ -78,6 +93,13 @@ public boolean {{parentTypeName}}.{{disconnectMethodName}}(String {{connectParam {{/configIncrementalOptionActive}} RagConnectDisconnectHandlerMethod disconnectingMethod; switch (scheme) { + {{#javaHandler}} + {{#InUse}} + case "java": + disconnectingMethod = {{senderName}}::remove; + break; + {{/InUse}} + {{/javaHandler}} {{#mqttHandler}} {{#InUse}} case "mqtt": diff --git a/ragconnect.tests/build.gradle b/ragconnect.tests/build.gradle index 18dd839..d41a73c 100644 --- a/ragconnect.tests/build.gradle +++ b/ragconnect.tests/build.gradle @@ -649,8 +649,6 @@ task compileRelationIncremental(type: RagConnectTest) { inputFiles = [file('src/test/01-input/relation/Test.relast'), file('src/test/01-input/relation/Test.connect')] rootNode = 'Root' - logWrites = true - logIncremental = true extraOptions = defaultRagConnectOptionsAnd(['--experimental-jastadd-329']) } relast { @@ -666,9 +664,34 @@ task compileRelationIncremental(type: RagConnectTest) { } } +// --- Test: java-incremental --- +task compileJavaIncremental(type: RagConnectTest) { + ragconnect { + outputDir = file('src/test/02-after-ragconnect/javaInc') + inputFiles = [file('src/test/01-input/java/Test.relast'), + file('src/test/01-input/java/Test.connect')] + rootNode = 'Root' + logWrites = true + logIncremental = true + protocols = ['java'] + extraOptions = defaultRagConnectOptionsAnd(['--experimental-jastadd-329']) + } + relast { + useJastAddNames = true + grammarName = 'src/test/03-after-relast/javaInc/javaInc' + serializer = 'jackson' + } + jastadd { + jastAddList = 'JastAddList' + packageName = 'javaInc.ast' + inputFiles = [file('src/test/01-input/java/Test.jadd')] + extraOptions = JASTADD_INCREMENTAL_OPTIONS_TRACING_FULL + } +} + // --- Task order --- classes.dependsOn(':ragconnect.base:jar') -//compileAttributeIncremental.outputs.upToDateWhen { false } +compileJavaIncremental.outputs.upToDateWhen { false } // --- Misc --- static ArrayList<String> defaultRagConnectOptionsAnd(ArrayList<String> options = []) { diff --git a/ragconnect.tests/src/test/01-input/java/README.md b/ragconnect.tests/src/test/01-input/java/README.md new file mode 100644 index 0000000..272a851 --- /dev/null +++ b/ragconnect.tests/src/test/01-input/java/README.md @@ -0,0 +1,3 @@ +# Java + +Idea: Use receive and send definitions using the Java handler. diff --git a/ragconnect.tests/src/test/01-input/java/Test.connect b/ragconnect.tests/src/test/01-input/java/Test.connect new file mode 100644 index 0000000..dcb6a56 --- /dev/null +++ b/ragconnect.tests/src/test/01-input/java/Test.connect @@ -0,0 +1,25 @@ +send SenderRoot.SendToken ; +send SenderRoot.SendNode ; +send SenderRoot.SendManyNode ; +send SenderRoot.SendNTA ; + +AddSuffix maps A a to A {: + A result = new A(); + String changedValue = a.getValue() + "post"; + result.setValue(changedValue); + result.setInner(new Inner("inner" + a.getInner().getInnerValue())); + return result; +:} + +AddStringSuffix maps String s to String {: + return s + "post"; +:} + +AddPlusOne maps int i to int {: + return i + 1; +:} + +receive ReceiverRoot.SomeToken; +receive ReceiverRoot.SomeNode; +receive ReceiverRoot.SomeNodeWithMapping using AddSuffix; +receive ReceiverRoot.ManyNode; diff --git a/ragconnect.tests/src/test/01-input/java/Test.jadd b/ragconnect.tests/src/test/01-input/java/Test.jadd new file mode 100644 index 0000000..0bb643e --- /dev/null +++ b/ragconnect.tests/src/test/01-input/java/Test.jadd @@ -0,0 +1,30 @@ +aspect Computation { + syn String SenderRoot.basic() = getInput(); + syn String SenderRoot.simple() = getInput() + "Post"; + syn A SenderRoot.getSendNTA() { + A result = new A(); + result.setValue(getInput()); + Inner inner = new Inner(); + inner.setInnerValue("1"); + result.setInner(inner); + return result; + } +} +aspect MakeCodeCompile { + +} +aspect MakeCodeWork { + +} +aspect NameResolution { + // overriding customID guarantees to produce the same JSON representation for equal lists + // otherwise, the value for id is different each time + @Override + protected String A.customID() { + return getClass().getSimpleName() + getValue(); + } + @Override + protected String Inner.customID() { + return getClass().getSimpleName() + getInnerValue(); + } +} diff --git a/ragconnect.tests/src/test/01-input/java/Test.relast b/ragconnect.tests/src/test/01-input/java/Test.relast new file mode 100644 index 0000000..13c7ba3 --- /dev/null +++ b/ragconnect.tests/src/test/01-input/java/Test.relast @@ -0,0 +1,9 @@ +Root ::= SenderRoot* ReceiverRoot; +SenderRoot ::= <Input> <SendToken> SendNode:A SendManyNode:A* /SendNTA:A/ ; +ReceiverRoot ::= + <SomeToken> + SomeNode:A + SomeNodeWithMapping:A + ManyNode:A*; +A ::= <Value> Inner ; +Inner ::= <InnerValue> ; diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/JavaTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/JavaTest.java new file mode 100644 index 0000000..2d22b3c --- /dev/null +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/JavaTest.java @@ -0,0 +1,43 @@ +package org.jastadd.ragconnect.tests; + +import javaInc.ast.Root; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Testing the Java handler. + * + * @author rschoene - Initial contribution + */ +@Tag("New") +public class JavaTest { + + protected Logger logger = LoggerFactory.getLogger(getClass()); + private Root model; + + void createModel() { + model = new Root(); + } + + @Test + public void testCommunicateSendInitialValue() { + createModel(); + } + + @Test + public void testCommunicateOnlyUpdatedValue() { + createModel(); + } + + @AfterEach + public void alwaysCloseConnections() { + logger.debug("Closing connections"); + if (model != null) { + model.ragconnectCloseConnections(); + } + } + +} -- GitLab From b9c399cb09c19451ed6c3b2fcff574adee5e21e2 Mon Sep 17 00:00:00 2001 From: rschoene <rene.schoene@tu-dresden.de> Date: Mon, 2 May 2022 18:47:49 +0200 Subject: [PATCH 2/7] fixed errors in JavaHandler --- .../src/main/resources/JavaHandler.mustache | 67 ++++++++----------- .../main/resources/receiveDefinition.mustache | 5 +- .../main/resources/sendDefinition.mustache | 1 + ragconnect.tests/build.gradle | 7 ++ .../tests/relation/RelationTest.java | 1 - 5 files changed, 40 insertions(+), 41 deletions(-) diff --git a/ragconnect.base/src/main/resources/JavaHandler.mustache b/ragconnect.base/src/main/resources/JavaHandler.mustache index bc73c91..9efd0ba 100644 --- a/ragconnect.base/src/main/resources/JavaHandler.mustache +++ b/ragconnect.base/src/main/resources/JavaHandler.mustache @@ -3,7 +3,8 @@ */ public class JavaHandler { public static JavaHandler JAVA_HANDLER_INSTANCE = null; - private java.util.Map<String, java.util.List<Pair<String, java.util.function.BiConsumer<String, byte[]>>>> callbackList = new java.util.concurrent.ConcurrentHashMap<>(); + private java.util.Map<String, java.util.List<java.util.function.BiConsumer<String, byte[]>>> callbackList = new java.util.concurrent.ConcurrentHashMap<>(); + private final java.util.Map<RagConnectToken, java.util.function.BiConsumer<String, byte[]>> tokensForRemoval = new java.util.HashMap<>(); private String name; private JavaHandler() { @@ -21,68 +22,58 @@ public class JavaHandler { return JAVA_HANDLER_INSTANCE; } - public String registerCallback(String topic, java.util.function.BiConsumer<String, byte[]> callback) { - {{logInfo}}("[JAVA_HANDLER] Registering new callback for {{log_}}.", topic); + private static String extractPath(java.net.URI uri) { + String path = uri.getPath(); + if (path.charAt(0) == '/') { + path = path.substring(1); + } + return path; + } + - String callbackUUID = java.util.UUID.randomUUID().toString(); + public boolean registerCallback(RagConnectToken connectToken, java.util.function.BiConsumer<String, byte[]> callback) { + String path = extractPath(connectToken.uri); + {{logInfo}}("[JAVA_HANDLER] Registering new callback for {{log_}}.", path); - java.util.List<Pair<String, java.util.function.BiConsumer<String, byte[]>>> registeredCallbacks = getAllCallbacks().get(topic); + java.util.List<java.util.function.BiConsumer<String, byte[]>> registeredCallbacks = callbackList.get(path); if (registeredCallbacks == null) { - java.util.List<Pair<String, java.util.function.BiConsumer<String, byte[]>>> newCallbackList = java.util.Collections.synchronizedList(new java.util.ArrayList<>()); - newCallbackList.add(new Pair<>(callbackUUID, callback)); - callbackList.put(topic, newCallbackList); - } else { - registeredCallbacks.add(new Pair<>(callbackUUID, callback)); + registeredCallbacks = java.util.Collections.synchronizedList(new java.util.ArrayList<>()); + callbackList.put(path, registeredCallbacks); } + registeredCallbacks.add(callback); + tokensForRemoval.put(connectToken, callback); - return callbackUUID; + return true; } - public boolean unregisterCallback(String path, String uuid) { - {{logInfo}}("[JAVA_HANDLER] Unregistering callback with uuid: {{log_}}", uuid + " on path: {{log_}}", path); - - java.util.List<Pair<String, java.util.function.BiConsumer<String, byte[]>>> callbacks = getAllCallbacks().get(path); + public boolean unregisterCallback(RagConnectToken connectToken) { + String path = extractPath(connectToken.uri); + java.util.function.BiConsumer<String, byte[]> callback = tokensForRemoval.get(connectToken); + {{logInfo}}("[JAVA_HANDLER] Unregistering callback with uuid: on path: {{log_}}", path); - int count = 0; - - if (callbacks != null) { - for (Pair<String, java.util.function.BiConsumer<String, byte[]>> callbackPair : callbacks) { - if (callbackPair._1.equals(uuid)) { - callbacks.remove(count); - return true; - } else { - count++; - } - } - } - return false; + return callbackList.get(path).remove(callback); } public void close() { } - public boolean push(String topic, byte[] data) { + public boolean push(String path, byte[] data) { {{logDebug}}("[JAVA_HANDLER] Pushing a message."); String dataString = new String(data); {{logDebug}}("[JAVA_HANDLER] Data: {{log_}}", dataString); - java.util.List<Pair<String, java.util.function.BiConsumer<String, byte[]>>> callbacks = getAllCallbacks().get(topic); + java.util.List<java.util.function.BiConsumer<String, byte[]>> callbacks = callbackList.get(path); if (callbacks == null) { - {{logError}}("[JAVA_HANDLER] Could not publish message. No callback registered for topic {{log_}}", topic); + {{logError}}("[JAVA_HANDLER] Could not publish message. No callback registered for path {{log_}}", path); return false; } - for (Pair<String, java.util.function.BiConsumer<String, byte[]>> callbackPair : callbacks) { - {{logDebug}}("[JAVA_HANDLER] Calling callback: {{log_}}", callbackPair._1); - callbackPair._2.accept(topic, data); + for (java.util.function.BiConsumer<String, byte[]> callback : callbacks) { + callback.accept(path, data); } return true; } - - public java.util.Map<String, java.util.List<Pair<String, java.util.function.BiConsumer<String, byte[]>>>> getAllCallbacks() { - return callbackList; - } } diff --git a/ragconnect.base/src/main/resources/receiveDefinition.mustache b/ragconnect.base/src/main/resources/receiveDefinition.mustache index c4f070c..28a9bb5 100644 --- a/ragconnect.base/src/main/resources/receiveDefinition.mustache +++ b/ragconnect.base/src/main/resources/receiveDefinition.mustache @@ -96,7 +96,7 @@ private boolean {{parentTypeName}}.{{internalConnectMethodName}}(String {{connec {{#javaHandler}} {{#InUse}} case "java": - success = {{attributeName}}().registerCallback(path, consumer, connectToken); + success = {{attributeName}}().registerCallback(connectToken, consumer); break; {{/InUse}} {{/javaHandler}} @@ -139,7 +139,8 @@ public boolean {{parentTypeName}}.{{disconnectMethodName}}(String {{connectParam switch (scheme) { {{#javaHandler}} {{#InUse}} - case "java": return {{attributeName}}().unregisterCallback(uri.getPath(), connectTokens.get(this).get(uri).globalId); + case "java": disconnectingMethod = {{attributeName}}()::unregisterCallback; + break; {{/InUse}} {{/javaHandler}} {{#mqttHandler}} diff --git a/ragconnect.base/src/main/resources/sendDefinition.mustache b/ragconnect.base/src/main/resources/sendDefinition.mustache index 1485c17..fae0fd2 100644 --- a/ragconnect.base/src/main/resources/sendDefinition.mustache +++ b/ragconnect.base/src/main/resources/sendDefinition.mustache @@ -17,6 +17,7 @@ public boolean {{parentTypeName}}.{{connectMethodName}}(String {{connectParamete if (writeCurrentValue) { {{writeMethodName}}({{#IndexBasedListAccess}}index, {{/IndexBasedListAccess}}connectToken); } + success = true; break; {{/InUse}} {{/javaHandler}} diff --git a/ragconnect.tests/build.gradle b/ragconnect.tests/build.gradle index d41a73c..5a2a82a 100644 --- a/ragconnect.tests/build.gradle +++ b/ragconnect.tests/build.gradle @@ -691,7 +691,14 @@ task compileJavaIncremental(type: RagConnectTest) { // --- Task order --- classes.dependsOn(':ragconnect.base:jar') +// TODO remove special handling of compileJavaIncremental once finished +compileJavaIncremental { + doFirst { + fileTree(dir: 'src/test/java-gen/javaInc/ast/', exclude: '.gitignore') + } +} compileJavaIncremental.outputs.upToDateWhen { false } +compileJavaIncremental.dependsOn(':ragconnect.base:assemble') // --- Misc --- static ArrayList<String> defaultRagConnectOptionsAnd(ArrayList<String> options = []) { diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/relation/RelationTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/relation/RelationTest.java index a88f97f..d9c4979 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/relation/RelationTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/relation/RelationTest.java @@ -21,7 +21,6 @@ import static org.junit.jupiter.api.Assertions.*; * @author rschoene - Initial contribution */ @Tag("Incremental") -@Tag("New") public class RelationTest extends AbstractMqttTest { private static final String TOPIC_WILDCARD = "rel/#"; -- GitLab From 853711571efd03429b4020e7d4ada6c9ac223b1f Mon Sep 17 00:00:00 2001 From: rschoene <rene.schoene@tu-dresden.de> Date: Sat, 21 May 2022 14:42:05 +0200 Subject: [PATCH 3/7] working on JavaHandler - add registerConsumer - remove singleton - working on tests --- .../src/main/resources/JavaHandler.mustache | 22 ++- .../main/resources/sendDefinition.mustache | 2 +- ragconnect.tests/build.gradle | 5 +- .../src/test/01-input/java/Test.connect | 1 + .../src/test/01-input/java/Test.relast | 3 +- .../jastadd/ragconnect/tests/JavaTest.java | 179 +++++++++++++++++- .../jastadd/ragconnect/tests/TestUtils.java | 13 +- 7 files changed, 209 insertions(+), 16 deletions(-) diff --git a/ragconnect.base/src/main/resources/JavaHandler.mustache b/ragconnect.base/src/main/resources/JavaHandler.mustache index 9efd0ba..90caae3 100644 --- a/ragconnect.base/src/main/resources/JavaHandler.mustache +++ b/ragconnect.base/src/main/resources/JavaHandler.mustache @@ -15,13 +15,6 @@ public class JavaHandler { this.name = name; } - public synchronized static JavaHandler getInstance() { - if (JAVA_HANDLER_INSTANCE == null) { - JAVA_HANDLER_INSTANCE = new JavaHandler(); - } - return JAVA_HANDLER_INSTANCE; - } - private static String extractPath(java.net.URI uri) { String path = uri.getPath(); if (path.charAt(0) == '/') { @@ -30,6 +23,12 @@ public class JavaHandler { return path; } + public RagConnectToken registerConsumer(String path, java.util.function.Consumer<byte[]> consumer) { + RagConnectToken token = new RagConnectToken(java.net.URI.create("internal://host/" + path), null); + registerCallback(token, (s, bytes) -> consumer.accept(bytes)); + return token; + } + public boolean registerCallback(RagConnectToken connectToken, java.util.function.BiConsumer<String, byte[]> callback) { String path = extractPath(connectToken.uri); @@ -58,8 +57,13 @@ public class JavaHandler { public void close() { } - public boolean push(String path, byte[] data) { - {{logDebug}}("[JAVA_HANDLER] Pushing a message."); + public boolean push(String uriString, byte[] data) { + String path = extractPath(java.net.URI.create(uriString)); + {{logDebug}}("[JAVA_HANDLER] Pushing a message for {{log_}}.", path); + if (data == null) { + {{logDebug}}("[JAVA_HANDLER] data was null, aborting"); + return false; + } String dataString = new String(data); {{logDebug}}("[JAVA_HANDLER] Data: {{log_}}", dataString); diff --git a/ragconnect.base/src/main/resources/sendDefinition.mustache b/ragconnect.base/src/main/resources/sendDefinition.mustache index fae0fd2..0829973 100644 --- a/ragconnect.base/src/main/resources/sendDefinition.mustache +++ b/ragconnect.base/src/main/resources/sendDefinition.mustache @@ -8,7 +8,7 @@ public boolean {{parentTypeName}}.{{connectMethodName}}(String {{connectParamete {{#javaHandler}} {{#InUse}} case "java": - final JavaHandler handler = {{attributeName}}().getInstance(); + final JavaHandler handler = {{attributeName}}(); {{senderName}}.add(() -> { handler.push(path, {{lastValueGetterCall}}); diff --git a/ragconnect.tests/build.gradle b/ragconnect.tests/build.gradle index 5a2a82a..719b55d 100644 --- a/ragconnect.tests/build.gradle +++ b/ragconnect.tests/build.gradle @@ -70,6 +70,8 @@ dependencies { testImplementation group: 'net.sf.beaver', name: 'beaver-rt', version: '0.9.11' api group: 'com.google.protobuf', name: 'protobuf-java', version: '3.0.0' + + implementation group: 'de.tudresden.inf.st', name: 'dumpAst', version: "1.0.2-68" } // --- Preprocessors --- @@ -671,6 +673,7 @@ task compileJavaIncremental(type: RagConnectTest) { inputFiles = [file('src/test/01-input/java/Test.relast'), file('src/test/01-input/java/Test.connect')] rootNode = 'Root' + logReads = true logWrites = true logIncremental = true protocols = ['java'] @@ -697,7 +700,7 @@ compileJavaIncremental { fileTree(dir: 'src/test/java-gen/javaInc/ast/', exclude: '.gitignore') } } -compileJavaIncremental.outputs.upToDateWhen { false } +//compileJavaIncremental.outputs.upToDateWhen { false } compileJavaIncremental.dependsOn(':ragconnect.base:assemble') // --- Misc --- diff --git a/ragconnect.tests/src/test/01-input/java/Test.connect b/ragconnect.tests/src/test/01-input/java/Test.connect index dcb6a56..d24dde5 100644 --- a/ragconnect.tests/src/test/01-input/java/Test.connect +++ b/ragconnect.tests/src/test/01-input/java/Test.connect @@ -23,3 +23,4 @@ receive ReceiverRoot.SomeToken; receive ReceiverRoot.SomeNode; receive ReceiverRoot.SomeNodeWithMapping using AddSuffix; receive ReceiverRoot.ManyNode; +receive ReceiverRoot.NTA; diff --git a/ragconnect.tests/src/test/01-input/java/Test.relast b/ragconnect.tests/src/test/01-input/java/Test.relast index 13c7ba3..62a23c2 100644 --- a/ragconnect.tests/src/test/01-input/java/Test.relast +++ b/ragconnect.tests/src/test/01-input/java/Test.relast @@ -4,6 +4,7 @@ ReceiverRoot ::= <SomeToken> SomeNode:A SomeNodeWithMapping:A - ManyNode:A*; + ManyNode:A* + NTA:A; A ::= <Value> Inner ; Inner ::= <InnerValue> ; diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/JavaTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/JavaTest.java index 2d22b3c..5d6e492 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/JavaTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/JavaTest.java @@ -1,12 +1,21 @@ package org.jastadd.ragconnect.tests; -import javaInc.ast.Root; +import javaInc.ast.*; +import org.assertj.core.groups.Tuple; +import org.jastadd.ragconnect.tests.TestUtils.TestChecker; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.IOException; +import java.util.List; + +import static org.assertj.core.api.Assertions.tuple; +import static org.jastadd.ragconnect.tests.TestUtils.javaUri; +import static org.junit.jupiter.api.Assertions.*; + /** * Testing the Java handler. * @@ -15,21 +24,140 @@ import org.slf4j.LoggerFactory; @Tag("New") public class JavaTest { + private static final String TOPIC_RECEIVE_TOKEN = "receiveToken"; + private static final String TOPIC_RECEIVE_NODE_PLAIN = "receiveNode/plain"; + private static final String TOPIC_RECEIVE_NODE_MAPPED = "receiveNode/mapped"; + private static final String TOPIC_RECEIVE_MANY = "receiveMany"; + private static final String TOPIC_RECEIVE_NTA = "receiveNTA"; + + private static final String TOPIC_SEND_TOKEN = "sendToken"; + private static final String TOPIC_SEND_NODE = "sendNode"; + private static final String TOPIC_SEND_MANY = "sendMany"; + private static final String TOPIC_SEND_NTA = "sendNTA"; + protected Logger logger = LoggerFactory.getLogger(getClass()); private Root model; + private SenderRoot senderRoot; + private ReceiverRoot receiverRoot; + + private String lastValueToken; + private A lastValueNode; + private JastAddList<A> lastValueMany; + private A lastValueNTA; + private TestChecker checker; + private JavaHandler handler; void createModel() { model = new Root(); + senderRoot = new SenderRoot().setInput("1").setSendNode(createA("1")); + receiverRoot = new ReceiverRoot(); + model.addSenderRoot(senderRoot); + model.setReceiverRoot(receiverRoot); + } + + private static A createA(String value) { + return new A().setValue(value).setInner(new Inner("inner")); + } + + private void setupReceiverAndConnect(boolean writeCurrentValue) throws IOException { + // checker + checker = new TestChecker(); + checker.setActualString(TOPIC_SEND_TOKEN, () -> lastValueToken) + .setCheckForString(TOPIC_SEND_NODE, (name, expected) -> checkA(expected, lastValueNode, name)) + .setCheckForTuple(TOPIC_SEND_MANY, (name, expected) -> checkAList(expected, lastValueMany, name)) + .setCheckForString(TOPIC_SEND_NTA, (name, expected) -> checkA(expected, lastValueNTA, name)) + .setActualString(TOPIC_RECEIVE_TOKEN, () -> receiverRoot.getSomeToken()) + .put(TOPIC_RECEIVE_TOKEN, "") + .setActualNumberOfValues(() -> 0) + .disableManualWait(); + + // callbacks + handler = model._ragconnect_javaHandler(); + handler.registerConsumer(TOPIC_SEND_TOKEN, bytes -> lastValueToken = new String(bytes)); + handler.registerConsumer(TOPIC_SEND_NODE, bytes -> lastValueNode = ExposingASTNode.INSTANCE.bytesToA(bytes)); + handler.registerConsumer(TOPIC_SEND_MANY, bytes -> lastValueMany = ExposingASTNode.INSTANCE.bytesToList(bytes)); + handler.registerConsumer(TOPIC_SEND_NTA, bytes -> lastValueNTA = ExposingASTNode.INSTANCE.bytesToA(bytes)); + + // receive + receiverRoot.connectSomeToken(javaUri(TOPIC_RECEIVE_TOKEN)); + receiverRoot.connectSomeNode(javaUri(TOPIC_RECEIVE_NODE_PLAIN)); + receiverRoot.connectSomeNodeWithMapping(javaUri(TOPIC_RECEIVE_NODE_MAPPED)); + receiverRoot.connectManyNodeList(javaUri(TOPIC_RECEIVE_MANY)); + receiverRoot.connectNTA(javaUri(TOPIC_RECEIVE_NTA)); + + // send + senderRoot.connectSendToken(javaUri(TOPIC_SEND_TOKEN), writeCurrentValue); + senderRoot.connectSendNode(javaUri(TOPIC_SEND_NODE), writeCurrentValue); + senderRoot.connectSendManyNodeList(javaUri(TOPIC_SEND_MANY), writeCurrentValue); + senderRoot.connectSendNTA(javaUri(TOPIC_SEND_NTA), writeCurrentValue); } @Test - public void testCommunicateSendInitialValue() { + public void testCommunicateSendInitialValue() throws IOException { createModel(); + setupReceiverAndConnect(true); + checker.put(TOPIC_SEND_TOKEN, "") + .put(TOPIC_SEND_NODE, "1") + .put(TOPIC_SEND_MANY, tuple()) + .put(TOPIC_SEND_NTA, "1") + ; + + communicateBoth(); + + handler.push(TOPIC_RECEIVE_TOKEN, ExposingASTNode.INSTANCE.stringToBytes("7")); + checker.put(TOPIC_RECEIVE_TOKEN, "7").check(); } @Test - public void testCommunicateOnlyUpdatedValue() { + public void testCommunicateOnlyUpdatedValue() throws IOException { createModel(); + setupReceiverAndConnect(false); + + checker.put(TOPIC_SEND_TOKEN, (String) null) + .put(TOPIC_SEND_NODE, (String) null) + .put(TOPIC_SEND_MANY, (Tuple) null) + .put(TOPIC_SEND_NTA, (String) null) + ; + + communicateBoth(); + } + + private void communicateBoth() { + checker.check(); + + senderRoot.setInput("2"); + checker.put(TOPIC_SEND_NTA, "2").check(); + + senderRoot.getSendNode().setValue("3"); + checker.put(TOPIC_SEND_NODE, "3").check(); + + senderRoot.setSendToken("test-4"); + checker.put(TOPIC_SEND_TOKEN, "test-4").check(); + + senderRoot.addSendManyNode(createA("5")); + checker.put(TOPIC_SEND_MANY, tuple("5")).check(); + } + + private void checkA(String expectedValue, A actual, String alias) { + if (expectedValue == null) { + assertNull(actual, alias); + } else { + assertNotNull(actual, alias); + assertEquals(expectedValue, actual.getValue(), alias); + } + } + + private void checkAList(Tuple expectedTuple, JastAddList<A> actual, String alias) { + if (expectedTuple == null) { + assertNull(actual, alias); + return; + } + List<Object> expected = expectedTuple.toList(); + assertEquals(expected.size(), actual.getNumChild(), alias + ".size"); + for (int i = 0, expectedSize = expected.size(); i < expectedSize; i++) { + String s = (String) expected.get(i); + checkA(s, actual.getChild(i), alias + "[" + i + "]"); + } } @AfterEach @@ -40,4 +168,49 @@ public class JavaTest { } } + @SuppressWarnings({"rawtypes" , "unchecked"}) + static class ExposingASTNode extends ASTNode { + static ExposingASTNode INSTANCE = new ExposingASTNode(); + + public A bytesToA(byte[] bytes) { + try { + return _ragconnect__apply__TreeDefaultBytesToAMapping(bytes); + } catch (Exception e) { + return null; + } + } + + public JastAddList<A> bytesToList(byte[] input) { + try { + return _ragconnect__apply__TreeDefaultBytesToJastAddListAListMapping(input); + } catch (Exception e) { + return null; + } + } + + public byte[] aToBytes(A input) { + try { + return _ragconnect__apply__TreeDefaultAToBytesMapping(input); + } catch (Exception e) { + return null; + } + } + + public byte[] listToBytes(JastAddList<A> input) { + try { + return _ragconnect__apply__TreeDefaultJastAddListToBytesMapping(input); + } catch (Exception e) { + return null; + } + } + + public byte[] stringToBytes(String input) { + try { + return _ragconnect__apply__DefaultStringToBytesMapping(input); + } catch (Exception e) { + return null; + } + } + } + } diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/TestUtils.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/TestUtils.java index 3457ce0..13700ef 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/TestUtils.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/TestUtils.java @@ -62,6 +62,10 @@ public class TestUtils { return "rest://localhost:" + port + "/" + path; } + public static String javaUri(String path) { + return "java://localhost/" + path; + } + public static int getMqttDefaultPort() { return 1883; } @@ -218,6 +222,7 @@ public class TestUtils { private final Map<String, ActualAndExpected<Tuple>> tupleValues = new HashMap<>(); private final Map<String, ActualAndExpected<Integer>> intValues = new HashMap<>(); private boolean needManualWait = true; + private boolean useManualWait = true; public TestChecker incNumberOfValues() { return addToNumberOfValues(1); @@ -281,6 +286,12 @@ public class TestUtils { return this; } + public TestChecker disableManualWait() { + useManualWait = false; + needManualWait = false; + return this; + } + public void check() { if (needManualWait) { try { @@ -298,7 +309,7 @@ public class TestUtils { aae.check(name); } }); - needManualWait = true; + needManualWait = useManualWait; } } -- GitLab From 2b726f1aae76a1d5033ca92257b95970761fac82 Mon Sep 17 00:00:00 2001 From: rschoene <rene.schoene@tu-dresden.de> Date: Sun, 22 May 2022 17:43:53 +0200 Subject: [PATCH 4/7] working on EvaluationCounter (not directly related to JavaHandler) - add EvaluationCounter commandline arg - counting receive/send, stages of mapping application - make mappings non-static --- .../src/main/jastadd/Intermediate.jadd | 8 ++ .../src/main/jastadd/Mappings.jrag | 4 +- .../src/main/jastadd/RagConnect.relast | 1 + .../jastadd/ragconnect/compiler/Compiler.java | 9 +- .../src/main/resources/handleUri.mustache | 6 +- .../resources/mappingApplication.mustache | 15 +++ .../main/resources/mappingDefinition.mustache | 2 +- .../src/main/resources/ragconnect.mustache | 95 +++++++++++++++++++ .../main/resources/receiveDefinition.mustache | 6 ++ .../main/resources/sendDefinition.mustache | 11 +++ ragconnect.tests/build.gradle | 4 +- .../jastadd/ragconnect/tests/JavaTest.java | 2 + .../tests/relation/RelationTest.java | 1 + 13 files changed, 154 insertions(+), 10 deletions(-) diff --git a/ragconnect.base/src/main/jastadd/Intermediate.jadd b/ragconnect.base/src/main/jastadd/Intermediate.jadd index 69ff5d8..f7a12a6 100644 --- a/ragconnect.base/src/main/jastadd/Intermediate.jadd +++ b/ragconnect.base/src/main/jastadd/Intermediate.jadd @@ -15,6 +15,10 @@ aspect SharedMustache { syn boolean RagConnect.configExperimentalJastAdd329() = getConfiguration().getExperimentalJastAdd329(); + syn boolean RagConnect.configEvaluationCounter() = getConfiguration().getEvaluationCounter(); + + syn String RagConnect.evaluationCounterVariable() = internalRagConnectPrefix() + "evaluationCounter"; + syn String RagConnect.internalRagConnectPrefix() = "_ragconnect_"; syn String RagConnect.logDebug() = logStatement("debug"); @@ -99,6 +103,10 @@ aspect MustacheHandler { // === RagConnect === syn String RagConnect.closeMethodName() = "ragconnectCloseConnections"; + syn String RagConnect.evaluationCounterInnerClass() = internalRagConnectPrefix() + "Counter"; + + syn String RagConnect.evaluationCounterSummaryMethodName() = "ragconnectEvaluationCounterSummary"; + syn boolean RagConnect.hasRootTypeComponents() = !rootTypeComponents().isEmpty(); syn List<TypeComponent> RagConnect.rootTypeComponents() { diff --git a/ragconnect.base/src/main/jastadd/Mappings.jrag b/ragconnect.base/src/main/jastadd/Mappings.jrag index 9fd55aa..e92fc4f 100644 --- a/ragconnect.base/src/main/jastadd/Mappings.jrag +++ b/ragconnect.base/src/main/jastadd/Mappings.jrag @@ -243,7 +243,7 @@ aspect Mappings { return getEndpointTarget().isTypeEndpointTarget() && typeIsList() && !getIndexBasedListAccess() ? ragconnect().defaultBytesToListMapping(typeDecl.getName()) : ragconnect().defaultBytesToTreeMapping(typeDecl.getName()); } catch (Exception ignore) { } - System.err.println("Could not find suitable default mapping for " + targetTypeName() + " on " + this); + System.err.println("Could not find suitable default receive mapping for " + targetTypeName() + " on " + this); return null; } } @@ -287,7 +287,7 @@ aspect Mappings { } catch (Exception ignore) { // exception should be logged to debug/fine } - System.err.println("Could not find suitable default mapping for " + targetTypeName() + " on " + this); + System.err.println("Could not find suitable default send mapping for " + targetTypeName() + " on " + this); return null; } } diff --git a/ragconnect.base/src/main/jastadd/RagConnect.relast b/ragconnect.base/src/main/jastadd/RagConnect.relast index cf12d73..df50e3d 100644 --- a/ragconnect.base/src/main/jastadd/RagConnect.relast +++ b/ragconnect.base/src/main/jastadd/RagConnect.relast @@ -40,5 +40,6 @@ Configuration ::= <JastAddOpt:String> <IncrementalOptionActive:boolean> <CacheAllOptionActive:boolean> +<EvaluationCounter:boolean> <ExperimentalJastAdd329:boolean>; rel Configuration.RootNode -> TypeDecl ; diff --git a/ragconnect.base/src/main/java/org/jastadd/ragconnect/compiler/Compiler.java b/ragconnect.base/src/main/java/org/jastadd/ragconnect/compiler/Compiler.java index e255b3b..772cebb 100644 --- a/ragconnect.base/src/main/java/org/jastadd/ragconnect/compiler/Compiler.java +++ b/ragconnect.base/src/main/java/org/jastadd/ragconnect/compiler/Compiler.java @@ -31,6 +31,7 @@ public class Compiler extends AbstractCompiler { private BooleanOption optionLogIncremental; private ValueOption optionLogTarget; private BooleanOption optionExperimentalJastAdd329; + private BooleanOption optionEvaluationCounter; private static final String OPTION_LOGGING_TARGET_CONSOLE = "console"; private static final String OPTION_LOGGING_TARGET_SLF4J = "slf4j"; @@ -206,6 +207,9 @@ public class Compiler extends AbstractCompiler { optionExperimentalJastAdd329 = addOption( new BooleanOption("experimental-jastadd-329", "Use trace events INC_FLUSH_START and INC_FLUSH_END (JastAdd issue #329).") .defaultValue(false)); + optionEvaluationCounter = addOption( + new BooleanOption("evaluationCounter", "Enable counters for evaluation.") + .defaultValue(false)); } private RagConnect parseProgram(Collection<String> files) throws CompilerException { @@ -301,13 +305,14 @@ public class Compiler extends AbstractCompiler { * Set all configuration values. * @param ragConnect the RagConnect instance to set configuration values */ - private void setConfiguration(RagConnect ragConnect) { + private void setConfiguration(RagConnect ragConnect) throws CompilerException { ragConnect.setConfiguration(new Configuration()); ragConnect.getConfiguration().setLoggingEnabledForReads(optionLogReads.value()); ragConnect.getConfiguration().setLoggingEnabledForWrites(optionLogWrites.value()); ragConnect.getConfiguration().setLoggingEnabledForIncremental(optionLogIncremental.value()); ragConnect.getConfiguration().setLoggingTarget(optionLogTarget.value()); ragConnect.getConfiguration().setExperimentalJastAdd329(optionExperimentalJastAdd329.value()); + ragConnect.getConfiguration().setEvaluationCounter(optionEvaluationCounter.value()); // reuse "--incremental" and "--trace=flush" options of JastAdd boolean incrementalOptionActive = this.getConfiguration().incremental() && this.getConfiguration().traceFlush(); @@ -328,7 +333,7 @@ public class Compiler extends AbstractCompiler { rootNode = ragConnect.getProgram().resolveTypeDecl(optionRootNode.value()); } catch (RuntimeException re) { // root node was not found - throw new RuntimeException("Could not resolve root node '" + optionRootNode.value() + "'!", re); + throw new CompilerException("Could not resolve root node '" + optionRootNode.value() + "'!", re); } ragConnect.getConfiguration().setRootNode(rootNode); diff --git a/ragconnect.base/src/main/resources/handleUri.mustache b/ragconnect.base/src/main/resources/handleUri.mustache index 2312cd6..efb4aac 100644 --- a/ragconnect.base/src/main/resources/handleUri.mustache +++ b/ragconnect.base/src/main/resources/handleUri.mustache @@ -10,14 +10,14 @@ try { return false; } if (scheme == null || scheme.isBlank()) { - {{logError}}("Missing or empty scheme in " + uri); + {{logError}}("Missing or empty scheme in {{log_}}", uri); return false; } if (host == null || host.isBlank()) { - {{logError}}("Missing or empty host in " + uri); + {{logError}}("Missing or empty host in {{log_}}", uri); return false; } if (path == null || path.isBlank()) { - {{logError}}("Missing or empty path in " + uri); + {{logError}}("Missing or empty path in {{log_}}", uri); return false; } diff --git a/ragconnect.base/src/main/resources/mappingApplication.mustache b/ragconnect.base/src/main/resources/mappingApplication.mustache index 482d547..efd17af 100644 --- a/ragconnect.base/src/main/resources/mappingApplication.mustache +++ b/ragconnect.base/src/main/resources/mappingApplication.mustache @@ -1,6 +1,12 @@ +{{#configEvaluationCounter}} + {{evaluationCounterVariable}}.incrementCall("{{parentTypeName}}", "{{entityName}}"); +{{/configEvaluationCounter}} {{#Send}} {{^PrimitiveType}} if ({{firstInputVarName}} == null) { + {{#configEvaluationCounter}} + {{evaluationCounterVariable}}.incrementFirstNull("{{parentTypeName}}", "{{entityName}}"); + {{/configEvaluationCounter}} {{preemptiveReturn}} } {{/PrimitiveType}} @@ -12,13 +18,22 @@ try { {{/innerMappingDefinitions}} } catch (RagConnectRejectMappingException e) { // do not print message in case of rejection + {{#configEvaluationCounter}} + {{evaluationCounterVariable}}.incrementReject("{{parentTypeName}}", "{{entityName}}"); + {{/configEvaluationCounter}} {{preemptiveReturn}} } catch (Exception e) { e.printStackTrace(); + {{#configEvaluationCounter}} + {{evaluationCounterVariable}}.incrementException("{{parentTypeName}}", "{{entityName}}"); + {{/configEvaluationCounter}} {{preemptiveReturn}} } {{^AlwaysApply}} if ({{{condition}}}) { + {{#configEvaluationCounter}} + {{evaluationCounterVariable}}.incrementSkip("{{parentTypeName}}", "{{entityName}}"); + {{/configEvaluationCounter}} {{preemptiveReturn}} } {{/AlwaysApply}} diff --git a/ragconnect.base/src/main/resources/mappingDefinition.mustache b/ragconnect.base/src/main/resources/mappingDefinition.mustache index 5be93e4..b6a035e 100644 --- a/ragconnect.base/src/main/resources/mappingDefinition.mustache +++ b/ragconnect.base/src/main/resources/mappingDefinition.mustache @@ -1,3 +1,3 @@ -protected static {{{toType}}} ASTNode.{{methodName}}({{{fromType}}} {{FromVariableName}}) throws Exception { +protected {{{toType}}} ASTNode.{{methodName}}({{{fromType}}} {{FromVariableName}}) throws Exception { {{{Content}}} } diff --git a/ragconnect.base/src/main/resources/ragconnect.mustache b/ragconnect.base/src/main/resources/ragconnect.mustache index ac7b906..7e054a4 100644 --- a/ragconnect.base/src/main/resources/ragconnect.mustache +++ b/ragconnect.base/src/main/resources/ragconnect.mustache @@ -285,3 +285,98 @@ aspect RagConnectObserver { } } {{/configIncrementalOptionActive}} + +aspect EvaluationCounter { + public String ASTNode.{{evaluationCounterSummaryMethodName}}() { + {{#configEvaluationCounter}} + return {{evaluationCounterVariable}}.summary(); + {{/configEvaluationCounter}} + {{^configEvaluationCounter}} + String message = "Option --evaluationCounter was not set. No Summary available"; + {{logWarn}}(message); + return message; + {{/configEvaluationCounter}} + } +{{#configEvaluationCounter}} + static EvaluationCounter ASTNode.{{evaluationCounterVariable}} = new EvaluationCounter(); + + public class EvaluationCounter { + private java.util.Map<String, java.util.Map<String, {{evaluationCounterInnerClass}}>> counters = new java.util.HashMap<>(); + private final java.util.function.Function<? super String, ? extends java.util.Map<String, {{evaluationCounterInnerClass}}>> parentAbsent = key -> { + return new java.util.HashMap<>(); + }; + private final java.util.function.Function<? super String, ? extends {{evaluationCounterInnerClass}}> entityAbsent = key -> { + return new {{evaluationCounterInnerClass}}(); + }; + + public void incrementReceive(String parentTypeName, String entityName) { + getCounter(parentTypeName, entityName).receive += 1; + } + + public void incrementSend(String parentTypeName, String entityName) { + getCounter(parentTypeName, entityName).send += 1; + } + + public void incrementCall(String parentTypeName, String entityName) { + getCounter(parentTypeName, entityName).call += 1; + } + + public void incrementFirstNull(String parentTypeName, String entityName) { + getCounter(parentTypeName, entityName).firstNull += 1; + } + + public void incrementSkip(String parentTypeName, String entityName) { + getCounter(parentTypeName, entityName).skip += 1; + } + + public void incrementException(String parentTypeName, String entityName) { + getCounter(parentTypeName, entityName).exception += 1; + } + + public void incrementReject(String parentTypeName, String entityName) { + getCounter(parentTypeName, entityName).reject += 1; + } + + public String summary() { + StringBuilder sb = new StringBuilder(); + // header + sb.append("parentTypeName,entityName,receive,send,call,firstNull,skip,exception,reject").append("\n"); + // values + java.util.Set<String> sortedParentTypes = new java.util.TreeSet<>(counters.keySet()); + for (String parentType : sortedParentTypes) { + java.util.Set<String> sortedEntityNames = new java.util.TreeSet<>(counters.get(parentType).keySet()); + for (String entityName : sortedEntityNames) { + {{evaluationCounterInnerClass}} count = getCounter(parentType, entityName); + java.util.StringJoiner sj = new java.util.StringJoiner(",", "", "\n"); + sj.add(parentType) + .add(entityName) + .add(Integer.toString(count.receive)) + .add(Integer.toString(count.send)) + .add(Integer.toString(count.call)) + .add(Integer.toString(count.firstNull)) + .add(Integer.toString(count.skip)) + .add(Integer.toString(count.exception)) + .add(Integer.toString(count.reject)) + ; + sb.append(sj); + } + } + return sb.toString(); + } + + private {{evaluationCounterInnerClass}} getCounter(String parentTypeName, String entityName) { + return counters.computeIfAbsent(parentTypeName, parentAbsent).computeIfAbsent(entityName, entityAbsent); + } + } + + class {{evaluationCounterInnerClass}} { + int receive = 0; + int send = 0; + int call = 0; + int firstNull = 0; + int skip = 0; + int exception = 0; + int reject = 0; + } +{{/configEvaluationCounter}} +} diff --git a/ragconnect.base/src/main/resources/receiveDefinition.mustache b/ragconnect.base/src/main/resources/receiveDefinition.mustache index 28a9bb5..81b0ecb 100644 --- a/ragconnect.base/src/main/resources/receiveDefinition.mustache +++ b/ragconnect.base/src/main/resources/receiveDefinition.mustache @@ -25,6 +25,9 @@ private int {{parentTypeName}}.{{resolveInListMethodName}}(String topic) { */ public boolean {{parentTypeName}}.{{connectMethodName}}(String {{connectParameterName}}{{#typeIsList}}{{#IndexBasedListAccess}}{{^WithAdd}}, int index{{/WithAdd}}{{/IndexBasedListAccess}}{{/typeIsList}}) throws java.io.IOException { java.util.function.BiConsumer<String, byte[]> consumer = (topic, message) -> { + {{#configEvaluationCounter}} + {{evaluationCounterVariable}}.incrementReceive("{{parentTypeName}}", "{{entityName}}"); + {{/configEvaluationCounter}} {{> mappingApplication}} {{#configLoggingEnabledForReads}} {{logDebug}}("[Receive] {{log_}} -> {{entityName}} = {{log_}}", {{connectParameterName}}, {{lastResult}}); @@ -70,6 +73,9 @@ public boolean {{parentTypeName}}.{{connectMethodName}}(String {{connectParamete */ public boolean {{parentTypeName}}.{{connectMethodName}}(String {{connectParameterName}}) throws java.io.IOException { java.util.function.BiConsumer<String, byte[]> consumer = (topic, message) -> { + {{#configEvaluationCounter}} + {{evaluationCounterVariable}}.incrementReceive("{{parentTypeName}}", "{{entityName}}"); + {{/configEvaluationCounter}} int index = {{resolveInListMethodName}}(topic); {{> mappingApplication}} {{#configLoggingEnabledForReads}} diff --git a/ragconnect.base/src/main/resources/sendDefinition.mustache b/ragconnect.base/src/main/resources/sendDefinition.mustache index 0829973..abcbdff 100644 --- a/ragconnect.base/src/main/resources/sendDefinition.mustache +++ b/ragconnect.base/src/main/resources/sendDefinition.mustache @@ -134,14 +134,25 @@ protected boolean {{parentTypeName}}.{{updateMethodName}}({{#IndexBasedListAcces {{> mappingApplication}} {{lastValueSetter}}({{#IndexBasedListAccess}}index, {{/IndexBasedListAccess}}{{lastResult}}); // normally we would return true here. unless no connect method was called so far to initialize {{senderName}} yet + {{#configEvaluationCounter}} + if ({{senderName}} == null) { + {{evaluationCounterVariable}}.incrementSkip("{{parentTypeName}}", "{{entityName}}"); + } + {{/configEvaluationCounter}} return {{senderName}} != null; } protected void {{parentTypeName}}.{{writeMethodName}}({{#IndexBasedListAccess}}int index{{/IndexBasedListAccess}}) { + {{#configEvaluationCounter}} + {{evaluationCounterVariable}}.incrementSend("{{parentTypeName}}", "{{entityName}}"); + {{/configEvaluationCounter}} {{senderName}}.run({{#IndexBasedListAccess}}index{{/IndexBasedListAccess}}); } protected void {{parentTypeName}}.{{writeMethodName}}({{#IndexBasedListAccess}}int index, {{/IndexBasedListAccess}}RagConnectToken token) { + {{#configEvaluationCounter}} + {{evaluationCounterVariable}}.incrementSend("{{parentTypeName}}", "{{entityName}}"); + {{/configEvaluationCounter}} {{senderName}}.run({{#IndexBasedListAccess}}index, {{/IndexBasedListAccess}}token); } diff --git a/ragconnect.tests/build.gradle b/ragconnect.tests/build.gradle index 719b55d..42c2cf6 100644 --- a/ragconnect.tests/build.gradle +++ b/ragconnect.tests/build.gradle @@ -651,7 +651,7 @@ task compileRelationIncremental(type: RagConnectTest) { inputFiles = [file('src/test/01-input/relation/Test.relast'), file('src/test/01-input/relation/Test.connect')] rootNode = 'Root' - extraOptions = defaultRagConnectOptionsAnd(['--experimental-jastadd-329']) + extraOptions = defaultRagConnectOptionsAnd(['--experimental-jastadd-329', '--evaluationCounter']) } relast { useJastAddNames = true @@ -677,7 +677,7 @@ task compileJavaIncremental(type: RagConnectTest) { logWrites = true logIncremental = true protocols = ['java'] - extraOptions = defaultRagConnectOptionsAnd(['--experimental-jastadd-329']) + extraOptions = defaultRagConnectOptionsAnd(['--experimental-jastadd-329', '--evaluationCounter']) } relast { useJastAddNames = true diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/JavaTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/JavaTest.java index 5d6e492..fa4319c 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/JavaTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/JavaTest.java @@ -106,6 +106,8 @@ public class JavaTest { handler.push(TOPIC_RECEIVE_TOKEN, ExposingASTNode.INSTANCE.stringToBytes("7")); checker.put(TOPIC_RECEIVE_TOKEN, "7").check(); + + System.out.println(model.ragconnectEvaluationCounterSummary()); } @Test diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/relation/RelationTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/relation/RelationTest.java index d9c4979..a245387 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/relation/RelationTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/relation/RelationTest.java @@ -616,6 +616,7 @@ public class RelationTest extends AbstractMqttTest { biB(3).getInner().setInnerValue("inner-bi-b3"); checker.check(); + System.out.println(model.ragconnectEvaluationCounterSummary()); } private void assertNullOrA(String expectedValue, A actual, String alias) { -- GitLab From 31979651befe350b16a1091325690911373a1b35 Mon Sep 17 00:00:00 2001 From: rschoene <rene.schoene@tu-dresden.de> Date: Sun, 22 May 2022 17:54:52 +0200 Subject: [PATCH 5/7] fix tests after making mappings non-static --- .../jastadd/ragconnect/tests/JavaTest.java | 12 ++- .../jastadd/ragconnect/tests/TestUtils.java | 99 ++++++++++--------- 2 files changed, 58 insertions(+), 53 deletions(-) diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/JavaTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/JavaTest.java index fa4319c..7655c07 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/JavaTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/JavaTest.java @@ -103,11 +103,6 @@ public class JavaTest { ; communicateBoth(); - - handler.push(TOPIC_RECEIVE_TOKEN, ExposingASTNode.INSTANCE.stringToBytes("7")); - checker.put(TOPIC_RECEIVE_TOKEN, "7").check(); - - System.out.println(model.ragconnectEvaluationCounterSummary()); } @Test @@ -138,6 +133,13 @@ public class JavaTest { senderRoot.addSendManyNode(createA("5")); checker.put(TOPIC_SEND_MANY, tuple("5")).check(); + + handler.push(TOPIC_RECEIVE_TOKEN, ExposingASTNode.INSTANCE.stringToBytes("7")); + checker.put(TOPIC_RECEIVE_TOKEN, "7").check(); + + // TODO check other receive ports + + System.out.println(model.ragconnectEvaluationCounterSummary()); } private void checkA(String expectedValue, A actual, String alias) { diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/TestUtils.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/TestUtils.java index 13700ef..91bbd40 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/TestUtils.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/TestUtils.java @@ -335,56 +335,56 @@ public class TestUtils { @SuppressWarnings({"unused", "rawtypes"}) public static class DefaultMappings { static class ReadNode extends defaultOnlyRead.ast.ASTNode { - public static boolean DefaultBytesToBooleanMapping(byte[] input) throws Exception { - return defaultOnlyRead.ast.ASTNode._ragconnect__apply__DefaultBytesToBooleanMapping(input); + public boolean DefaultBytesToBooleanMapping(byte[] input) throws Exception { + return _ragconnect__apply__DefaultBytesToBooleanMapping(input); } - public static int DefaultBytesToIntMapping(byte[] input) throws Exception { - return defaultOnlyRead.ast.ASTNode._ragconnect__apply__DefaultBytesToIntMapping(input); + public int DefaultBytesToIntMapping(byte[] input) throws Exception { + return _ragconnect__apply__DefaultBytesToIntMapping(input); } - public static short DefaultBytesToShortMapping(byte[] input) throws Exception { - return defaultOnlyRead.ast.ASTNode._ragconnect__apply__DefaultBytesToShortMapping(input); + public short DefaultBytesToShortMapping(byte[] input) throws Exception { + return _ragconnect__apply__DefaultBytesToShortMapping(input); } - public static long DefaultBytesToLongMapping(byte[] input) throws Exception { - return defaultOnlyRead.ast.ASTNode._ragconnect__apply__DefaultBytesToLongMapping(input); + public long DefaultBytesToLongMapping(byte[] input) throws Exception { + return _ragconnect__apply__DefaultBytesToLongMapping(input); } - public static float DefaultBytesToFloatMapping(byte[] input) throws Exception { - return defaultOnlyRead.ast.ASTNode._ragconnect__apply__DefaultBytesToFloatMapping(input); + public float DefaultBytesToFloatMapping(byte[] input) throws Exception { + return _ragconnect__apply__DefaultBytesToFloatMapping(input); } - public static double DefaultBytesToDoubleMapping(byte[] input) throws Exception { - return defaultOnlyRead.ast.ASTNode._ragconnect__apply__DefaultBytesToDoubleMapping(input); + public double DefaultBytesToDoubleMapping(byte[] input) throws Exception { + return _ragconnect__apply__DefaultBytesToDoubleMapping(input); } - public static char DefaultBytesToCharMapping(byte[] input) throws Exception { - return defaultOnlyRead.ast.ASTNode._ragconnect__apply__DefaultBytesToCharMapping(input); + public char DefaultBytesToCharMapping(byte[] input) throws Exception { + return _ragconnect__apply__DefaultBytesToCharMapping(input); } - public static String DefaultBytesToStringMapping(byte[] input) throws Exception { - return defaultOnlyRead.ast.ASTNode._ragconnect__apply__DefaultBytesToStringMapping(input); + public String DefaultBytesToStringMapping(byte[] input) throws Exception { + return _ragconnect__apply__DefaultBytesToStringMapping(input); } } static class WriteNode extends defaultOnlyWrite.ast.ASTNode { - public static byte[] DefaultBooleanToBytesMapping(boolean input) throws Exception { - return defaultOnlyWrite.ast.ASTNode._ragconnect__apply__DefaultBooleanToBytesMapping(input); + public byte[] DefaultBooleanToBytesMapping(boolean input) throws Exception { + return _ragconnect__apply__DefaultBooleanToBytesMapping(input); } - public static byte[] DefaultIntToBytesMapping(int input) throws Exception { - return defaultOnlyWrite.ast.ASTNode._ragconnect__apply__DefaultIntToBytesMapping(input); + public byte[] DefaultIntToBytesMapping(int input) throws Exception { + return _ragconnect__apply__DefaultIntToBytesMapping(input); } - public static byte[] DefaultShortToBytesMapping(short input) throws Exception { - return defaultOnlyWrite.ast.ASTNode._ragconnect__apply__DefaultShortToBytesMapping(input); + public byte[] DefaultShortToBytesMapping(short input) throws Exception { + return _ragconnect__apply__DefaultShortToBytesMapping(input); } - public static byte[] DefaultLongToBytesMapping(long input) throws Exception { - return defaultOnlyWrite.ast.ASTNode._ragconnect__apply__DefaultLongToBytesMapping(input); + public byte[] DefaultLongToBytesMapping(long input) throws Exception { + return _ragconnect__apply__DefaultLongToBytesMapping(input); } - public static byte[] DefaultFloatToBytesMapping(float input) throws Exception { - return defaultOnlyWrite.ast.ASTNode._ragconnect__apply__DefaultFloatToBytesMapping(input); + public byte[] DefaultFloatToBytesMapping(float input) throws Exception { + return _ragconnect__apply__DefaultFloatToBytesMapping(input); } - public static byte[] DefaultDoubleToBytesMapping(double input) throws Exception { - return defaultOnlyWrite.ast.ASTNode._ragconnect__apply__DefaultDoubleToBytesMapping(input); + public byte[] DefaultDoubleToBytesMapping(double input) throws Exception { + return _ragconnect__apply__DefaultDoubleToBytesMapping(input); } - public static byte[] DefaultCharToBytesMapping(char input) throws Exception { - return defaultOnlyWrite.ast.ASTNode._ragconnect__apply__DefaultCharToBytesMapping(input); + public byte[] DefaultCharToBytesMapping(char input) throws Exception { + return _ragconnect__apply__DefaultCharToBytesMapping(input); } - public static byte[] DefaultStringToBytesMapping(String input) throws Exception { - return defaultOnlyWrite.ast.ASTNode._ragconnect__apply__DefaultStringToBytesMapping(input); + public byte[] DefaultStringToBytesMapping(String input) throws Exception { + return _ragconnect__apply__DefaultStringToBytesMapping(input); } } @FunctionalInterface @@ -392,9 +392,12 @@ public class TestUtils { void accept(JsonGenerator g, String fieldName) throws E; } + static ReadNode readNode = new ReadNode(); + static WriteNode writeNode = new WriteNode(); + public static boolean BytesToBool(byte[] input) { try { - return ReadNode.DefaultBytesToBooleanMapping(input); + return readNode.DefaultBytesToBooleanMapping(input); } catch (Exception e) { e.printStackTrace(); return false; @@ -402,7 +405,7 @@ public class TestUtils { } public static int BytesToInt(byte[] input) { try { - return ReadNode.DefaultBytesToIntMapping(input); + return readNode.DefaultBytesToIntMapping(input); } catch (Exception e) { e.printStackTrace(); return 0; @@ -410,7 +413,7 @@ public class TestUtils { } public static short BytesToShort(byte[] input) { try { - return ReadNode.DefaultBytesToShortMapping(input); + return readNode.DefaultBytesToShortMapping(input); } catch (Exception e) { e.printStackTrace(); return 0; @@ -418,7 +421,7 @@ public class TestUtils { } public static long BytesToLong(byte[] input) { try { - return ReadNode.DefaultBytesToLongMapping(input); + return readNode.DefaultBytesToLongMapping(input); } catch (Exception e) { e.printStackTrace(); return 0; @@ -426,7 +429,7 @@ public class TestUtils { } public static float BytesToFloat(byte[] input) { try { - return ReadNode.DefaultBytesToFloatMapping(input); + return readNode.DefaultBytesToFloatMapping(input); } catch (Exception e) { e.printStackTrace(); return 0; @@ -434,7 +437,7 @@ public class TestUtils { } public static double BytesToDouble(byte[] input) { try { - return ReadNode.DefaultBytesToDoubleMapping(input); + return readNode.DefaultBytesToDoubleMapping(input); } catch (Exception e) { e.printStackTrace(); return 0; @@ -442,7 +445,7 @@ public class TestUtils { } public static char BytesToChar(byte[] input) { try { - return ReadNode.DefaultBytesToCharMapping(input); + return readNode.DefaultBytesToCharMapping(input); } catch (Exception e) { e.printStackTrace(); return 0; @@ -450,7 +453,7 @@ public class TestUtils { } public static String BytesToString(byte[] input) { try { - return ReadNode.DefaultBytesToStringMapping(input); + return readNode.DefaultBytesToStringMapping(input); } catch (Exception e) { e.printStackTrace(); return null; @@ -458,7 +461,7 @@ public class TestUtils { } public static byte[] BoolToBytes(boolean input) { try { - return WriteNode.DefaultBooleanToBytesMapping(input); + return writeNode.DefaultBooleanToBytesMapping(input); } catch (Exception e) { e.printStackTrace(); return null; @@ -466,7 +469,7 @@ public class TestUtils { } public static byte[] IntToBytes(int input) { try { - return WriteNode.DefaultIntToBytesMapping(input); + return writeNode.DefaultIntToBytesMapping(input); } catch (Exception e) { e.printStackTrace(); return null; @@ -474,7 +477,7 @@ public class TestUtils { } public static byte[] ShortToBytes(short input) { try { - return WriteNode.DefaultShortToBytesMapping(input); + return writeNode.DefaultShortToBytesMapping(input); } catch (Exception e) { e.printStackTrace(); return null; @@ -482,7 +485,7 @@ public class TestUtils { } public static byte[] LongToBytes(long input) { try { - return WriteNode.DefaultLongToBytesMapping(input); + return writeNode.DefaultLongToBytesMapping(input); } catch (Exception e) { e.printStackTrace(); return null; @@ -490,7 +493,7 @@ public class TestUtils { } public static byte[] FloatToBytes(float input) { try { - return WriteNode.DefaultFloatToBytesMapping(input); + return writeNode.DefaultFloatToBytesMapping(input); } catch (Exception e) { e.printStackTrace(); return null; @@ -498,7 +501,7 @@ public class TestUtils { } public static byte[] DoubleToBytes(double input) { try { - return WriteNode.DefaultDoubleToBytesMapping(input); + return writeNode.DefaultDoubleToBytesMapping(input); } catch (Exception e) { e.printStackTrace(); return null; @@ -506,7 +509,7 @@ public class TestUtils { } public static byte[] CharToBytes(char input) { try { - return WriteNode.DefaultCharToBytesMapping(input); + return writeNode.DefaultCharToBytesMapping(input); } catch (Exception e) { e.printStackTrace(); return null; @@ -514,7 +517,7 @@ public class TestUtils { } public static byte[] StringToBytes(String input) { try { - return WriteNode.DefaultStringToBytesMapping(input); + return writeNode.DefaultStringToBytesMapping(input); } catch (Exception e) { e.printStackTrace(); return null; -- GitLab From bd4174314121238c46337130d3d73b0bcc029dca Mon Sep 17 00:00:00 2001 From: rschoene <rene.schoene@tu-dresden.de> Date: Mon, 30 May 2022 16:15:47 +0200 Subject: [PATCH 6/7] Finalize tests for initial JavaHandler - moved methods "registerConsumer" and "push" up to root node (prefixed) - mark Java handler as experimental - update documentation - begin with changelog for 1.0.0 --- pages/docs/changelog.md | 15 +++ pages/docs/compiler.md | 24 +++-- pages/docs/dsl.md | 24 ++--- pages/docs/using.md | 2 +- .../src/main/jastadd/Intermediate.jadd | 4 + .../jastadd/ragconnect/compiler/Compiler.java | 4 +- .../src/main/resources/JavaHandler.mustache | 11 +-- .../src/main/resources/handler.mustache | 6 ++ ragconnect.tests/build.gradle | 11 --- .../src/test/01-input/java/Test.connect | 4 +- .../jastadd/ragconnect/tests/JavaTest.java | 50 +++++++--- .../jastadd/ragconnect/tests/TestUtils.java | 97 +++++++++++++------ 12 files changed, 172 insertions(+), 80 deletions(-) diff --git a/pages/docs/changelog.md b/pages/docs/changelog.md index fe3b87a..1f41f95 100644 --- a/pages/docs/changelog.md +++ b/pages/docs/changelog.md @@ -1,5 +1,20 @@ # Changelog +## 1.0.0 (dev) + +### Changes + +- Allow connection endpoints for relations ([#37](https://git-st.inf.tu-dresden.de/jastadd/ragconnect/-/issues/37)) and attributes ([#38](https://git-st.inf.tu-dresden.de/jastadd/ragconnect/-/issues/38)) +- Allow send connection endpoints non-NTA nonterminals ([#36](https://git-st.inf.tu-dresden.de/jastadd/ragconnect/-/issues/36)) +- Allow context-free context endpoints ([#34](https://git-st.inf.tu-dresden.de/jastadd/ragconnect/-/issues/34)) +- Experimental support for Java handler ([#52](https://git-st.inf.tu-dresden.de/jastadd/ragconnect/-/issues/52)) +- Make specification language more concise ([#33](https://git-st.inf.tu-dresden.de/jastadd/ragconnect/-/issues/33)) + +### Development Changes + +- Make grammar(s) more concise ([#40](https://git-st.inf.tu-dresden.de/jastadd/ragconnect/-/issues/40)) +- Enhance documentation, adding a DSL description + ## 0.3.2 - Allow connection endpoints for list nonterminals ([#21](https://git-st.inf.tu-dresden.de/jastadd/ragconnect/-/issues/21)) diff --git a/pages/docs/compiler.md b/pages/docs/compiler.md index d60822b..80a9acb 100644 --- a/pages/docs/compiler.md +++ b/pages/docs/compiler.md @@ -6,16 +6,16 @@ Additional options are as follows. | Name | Required (Default) | Description | |---|---|---| | `--rootNode` | Yes | Root node in the base grammar. | -| `--protocols` | No (`mqtt`) | Protocols to enable, currently available: `mqtt, rest`. | +| `--protocols` | No (`mqtt`) | Protocols to enable, currently available: `java` (experimental), `mqtt`, `rest`. | | `--printYaml` | No (false) | Print out YAML instead of generating files. | | `--verbose` | No (false) | Print more messages while compiling. | | `--logReads` | No (false) | Enable logging for every received message. | | `--logWrites` | No (false) | Enable logging for every sent message. | | `--logIncremental` | No (false) | Enable logging for observer in incremental dependency tracking. | | `--logTarget` | No (`console`) | Logging target to use, currently available: `console, slf4j`. | -| `--experimental-jastadd-329` | No (false) | Use trace events `INC_FLUSH_START` and `INC_FLUSH_END` ([JastAdd issue #329][jastadd-issue-329]), see [section about automatic dependency tracking](/using#dependency-tracking-automatically-derived). | -| `--incremental` | No (false) | Enables incremental dependency tracking (if `trace` is also set appropriately). | -| `--trace[=flush]` | No (false) | Enables incremental dependency tracking (if `incremental` is also set appropriately). | +| `--experimental-jastadd-329` | No (false) | Use tracing events `INC_FLUSH_START` and `INC_FLUSH_END` ([JastAdd issue #329][jastadd-issue-329]), see [section about automatic dependency tracking](/using#dependency-tracking-automatically-derived). | +| `--incremental` | No (false) | Enables incremental dependency tracking (if `tracing` is also set appropriately). | +| `--tracing[=flush]` | No (false) | Enables incremental dependency tracking (if `incremental` is also set appropriately). | | `--version` | No (false) | Print version info and exit (reused JastAdd option) | | `--o` | No (`.`) | Output directory (reused JastAdd option) | @@ -29,6 +29,16 @@ However, depending on the selected protocols and/or used features, additional de ## Communication protocol characteristics +### Java + +- Protocol identifier: `java` +- URI scheme: `java://<ignored-host>[:ignored-port]/<topic>` + - the value for host and port are always ignored, but are necessary to form a legal URI +- No required runtime dependencies +- Additional remarks: + - First leading slash not included in topic. + - Currently, the default mappings are applied, which requires a consumer to expect `byte[]` (instead of a more intuitive token or node value). This might change in future versions. + ### MQTT - Protocol identifier: `mqtt` @@ -59,15 +69,15 @@ However, depending on the selected protocols and/or used features, additional de ### Automatic dependency tracking -- Condition: When passing `--incremental` and `--trace=flush` to RagConnect +- Condition: When passing `--incremental` and `--tracing=flush` to RagConnect - Required runtime dependencies: _none_ - Required options for RelAST compiler: _none_ - Required options for JastAdd: - `--incremental` - - `--trace=flush` + - `--tracing=flush` - Remarks: - Other (additional) values passed to those two options must be equal (e.g., `--incremental=param` passed to RagConnect must be also passed to JastAdd) - - Other values besides `flush` can be added to `--trace` + - Other values besides `flush` can be added to `--tracing` - [Feature description](/using#dependency-tracking-automatically-derived) ### (Safer) Automatic dependency tracking diff --git a/pages/docs/dsl.md b/pages/docs/dsl.md index e8b6b2b..98ee13c 100644 --- a/pages/docs/dsl.md +++ b/pages/docs/dsl.md @@ -21,19 +21,19 @@ A breakdown of the parts of that syntax: - The first word (`send` or `receive`) defines the kind of endpoint - sending or receiving, respectively. - The optional `indexed` applies only for list children and lets the endpoint act on elements of that list. This only works for receiving endpoints, and is further changed by `with add`. - - A lonely `indexed` assigns each incoming "topic" to an index in a list. - This can be useful if multiple instances of this endpoint are connected, or the communication protocol supports wildcard topics. - For the former case, the connect method with an explicit index can be used, whereas the "normal" connect method without the index acts as a method for "wildcard-connect". - - Combining `indexed with add`, incoming data is required to be an element of the list, and will be appended to the list. + - A lonely `indexed` assigns each incoming "topic" to an index in a list. + This can be useful if multiple instances of this endpoint are connected, or the communication protocol supports wildcard topics. + For the former case, the connect method with an explicit index can be used, whereas the "normal" connect method without the index acts as a method for "wildcard-connect". + - Combining `indexed with add`, incoming data is required to be an element of the list, and will be appended to the list. - The second optional keyword `with add` can also be used only for receiving endpoints targeting a list children. As described above, it can be combined with `indexed`. If used on its own, the incoming data is interpreted as a complete list and its elements will be appended to the current list. - The `<Non-Terminal>[.<Target>["(<AttributeType>)"]]` notation describes the actual affected node. - - If the target is omitted, all nodes of that non-terminal type can be connected, irrespective of their context. This is a context-free endpoint definition. - - The target can be any child on the right-hand side of a production rule, a role of a relation, or an attribute. - The brackets `(<AttributeType>)` after the target must be used in case of an attribute, and only then. - Here, the return type of the attribute has to be specified, as aspect files are not parsed by RagConnect. - Hence, RagConnect can not and will not verify the existence of the attribute, and the possible non-existence of an attribute will be found by the Java compiler. + - If the target is omitted, all nodes of that non-terminal type can be connected, irrespective of their context. This is a context-free endpoint definition. + - The target can be any child on the right-hand side of a production rule, a role of a relation, or an attribute. + The brackets `(<AttributeType>)` after the target must be used in case of an attribute, and only then. + Here, the return type of the attribute has to be specified, as aspect files are not parsed by RagConnect. + Hence, RagConnect can not and will not verify the existence of the attribute, and the possible non-existence of an attribute will be found by the Java compiler. - Optionally, an endpoint can use one or more [mappings](#mappings). They will be applied before sending, or after receiving a message. Mappings will always be applied in the order they are listed after `using`. @@ -49,7 +49,7 @@ Specifying such an endpoint has several consequences: **Example**: -```java +``` // grammar Root ::= A SingleA:A [OptA:A] ListA:A* ; A ::= <Value> ; @@ -60,13 +60,15 @@ receive Root.SingleA using MyMapping; // specialized endpoint ``` Implied, additional connect specifications: -```java + +``` receive Root.A; receive Root.OptA; receive indexed Root.ListA; ``` Application code: + ```java A a = root.getOptA(); // new method on A: diff --git a/pages/docs/using.md b/pages/docs/using.md index d4d2a30..87d9192 100644 --- a/pages/docs/using.md +++ b/pages/docs/using.md @@ -47,7 +47,7 @@ Otherwise, the deprecated manual dependencies must be used. ### Dependency tracking: Automatically derived -To automatically track dependencies, the two additional parameters `--incremental` and `--trace=flush` have to be provided to both RagConnect and (in the later stage) JastAdd. +To automatically track dependencies, the two additional parameters `--incremental` and `--tracing=flush` have to be provided to both RagConnect and (in the later stage) JastAdd. This will generate a different implementation of RagConnect relying on enabled incremental evaluation of JastAdd. The value for `incremental` has only been tested for `incremental=param`. The value for `trace` can include other values besides `flush`. diff --git a/ragconnect.base/src/main/jastadd/Intermediate.jadd b/ragconnect.base/src/main/jastadd/Intermediate.jadd index f7a12a6..95f9b86 100644 --- a/ragconnect.base/src/main/jastadd/Intermediate.jadd +++ b/ragconnect.base/src/main/jastadd/Intermediate.jadd @@ -126,6 +126,10 @@ aspect MustacheHandler { syn String Handler.fieldName() = ragconnect().internalRagConnectPrefix() + getUniqueName() + "Handler"; + syn String Handler.pushMethodName() = "ragconnect" + capitalize(getUniqueName()) + "Push"; + + syn String Handler.registerConsumerMethodName() = "ragconnect" + capitalize(getUniqueName()) + "RegisterConsumer"; + syn String Handler.setupWaitUntilReadyMethodName() = "ragconnectSetup" + capitalize(getUniqueName()) + "WaitUntilReady"; } diff --git a/ragconnect.base/src/main/java/org/jastadd/ragconnect/compiler/Compiler.java b/ragconnect.base/src/main/java/org/jastadd/ragconnect/compiler/Compiler.java index 772cebb..fdb5215 100644 --- a/ragconnect.base/src/main/java/org/jastadd/ragconnect/compiler/Compiler.java +++ b/ragconnect.base/src/main/java/org/jastadd/ragconnect/compiler/Compiler.java @@ -181,7 +181,7 @@ public class Compiler extends AbstractCompiler { new ValueOption("protocols", "Protocols to enable") .acceptMultipleValues(true) .addDefaultValue(OPTION_PROTOCOL_MQTT, "Enable MQTT") - .addAcceptedValue(OPTION_PROTOCOL_JAVA, "Enable Java") + .addAcceptedValue(OPTION_PROTOCOL_JAVA, "Enable Java (experimental)") .addAcceptedValue(OPTION_PROTOCOL_REST, "Enable REST") ); optionPrintYaml = addOption( @@ -314,7 +314,7 @@ public class Compiler extends AbstractCompiler { ragConnect.getConfiguration().setExperimentalJastAdd329(optionExperimentalJastAdd329.value()); ragConnect.getConfiguration().setEvaluationCounter(optionEvaluationCounter.value()); - // reuse "--incremental" and "--trace=flush" options of JastAdd + // reuse "--incremental" and "--tracing=flush" options of JastAdd boolean incrementalOptionActive = this.getConfiguration().incremental() && this.getConfiguration().traceFlush(); ragConnect.getConfiguration().setIncrementalOptionActive(incrementalOptionActive); if (isVerbose()) { diff --git a/ragconnect.base/src/main/resources/JavaHandler.mustache b/ragconnect.base/src/main/resources/JavaHandler.mustache index 90caae3..d8d907b 100644 --- a/ragconnect.base/src/main/resources/JavaHandler.mustache +++ b/ragconnect.base/src/main/resources/JavaHandler.mustache @@ -23,14 +23,13 @@ public class JavaHandler { return path; } - public RagConnectToken registerConsumer(String path, java.util.function.Consumer<byte[]> consumer) { + RagConnectToken registerConsumer(String path, java.util.function.Consumer<byte[]> consumer) { RagConnectToken token = new RagConnectToken(java.net.URI.create("internal://host/" + path), null); registerCallback(token, (s, bytes) -> consumer.accept(bytes)); return token; } - - public boolean registerCallback(RagConnectToken connectToken, java.util.function.BiConsumer<String, byte[]> callback) { + boolean registerCallback(RagConnectToken connectToken, java.util.function.BiConsumer<String, byte[]> callback) { String path = extractPath(connectToken.uri); {{logInfo}}("[JAVA_HANDLER] Registering new callback for {{log_}}.", path); @@ -46,7 +45,7 @@ public class JavaHandler { return true; } - public boolean unregisterCallback(RagConnectToken connectToken) { + boolean unregisterCallback(RagConnectToken connectToken) { String path = extractPath(connectToken.uri); java.util.function.BiConsumer<String, byte[]> callback = tokensForRemoval.get(connectToken); {{logInfo}}("[JAVA_HANDLER] Unregistering callback with uuid: on path: {{log_}}", path); @@ -54,10 +53,10 @@ public class JavaHandler { return callbackList.get(path).remove(callback); } - public void close() { + void close() { } - public boolean push(String uriString, byte[] data) { + boolean push(String uriString, byte[] data) { String path = extractPath(java.net.URI.create(uriString)); {{logDebug}}("[JAVA_HANDLER] Pushing a message for {{log_}}.", path); if (data == null) { diff --git a/ragconnect.base/src/main/resources/handler.mustache b/ragconnect.base/src/main/resources/handler.mustache index 2c4cf96..75bd14c 100644 --- a/ragconnect.base/src/main/resources/handler.mustache +++ b/ragconnect.base/src/main/resources/handler.mustache @@ -21,6 +21,12 @@ aspect RagConnectHandler { {{#javaHandler}} {{#InUse}} + public RagConnectToken {{rootNodeName}}.{{registerConsumerMethodName}}(String path, java.util.function.Consumer<byte[]> consumer) { + return {{fieldName}}.registerConsumer(path, consumer); + } + public boolean {{rootNodeName}}.{{pushMethodName}}(String uriString, byte[] data) { + return {{fieldName}}.push(uriString, data); + } {{> JavaHandler}} {{/InUse}} {{/javaHandler}} diff --git a/ragconnect.tests/build.gradle b/ragconnect.tests/build.gradle index 42c2cf6..4da4ee9 100644 --- a/ragconnect.tests/build.gradle +++ b/ragconnect.tests/build.gradle @@ -673,9 +673,6 @@ task compileJavaIncremental(type: RagConnectTest) { inputFiles = [file('src/test/01-input/java/Test.relast'), file('src/test/01-input/java/Test.connect')] rootNode = 'Root' - logReads = true - logWrites = true - logIncremental = true protocols = ['java'] extraOptions = defaultRagConnectOptionsAnd(['--experimental-jastadd-329', '--evaluationCounter']) } @@ -694,14 +691,6 @@ task compileJavaIncremental(type: RagConnectTest) { // --- Task order --- classes.dependsOn(':ragconnect.base:jar') -// TODO remove special handling of compileJavaIncremental once finished -compileJavaIncremental { - doFirst { - fileTree(dir: 'src/test/java-gen/javaInc/ast/', exclude: '.gitignore') - } -} -//compileJavaIncremental.outputs.upToDateWhen { false } -compileJavaIncremental.dependsOn(':ragconnect.base:assemble') // --- Misc --- static ArrayList<String> defaultRagConnectOptionsAnd(ArrayList<String> options = []) { diff --git a/ragconnect.tests/src/test/01-input/java/Test.connect b/ragconnect.tests/src/test/01-input/java/Test.connect index d24dde5..d516cfe 100644 --- a/ragconnect.tests/src/test/01-input/java/Test.connect +++ b/ragconnect.tests/src/test/01-input/java/Test.connect @@ -5,9 +5,9 @@ send SenderRoot.SendNTA ; AddSuffix maps A a to A {: A result = new A(); - String changedValue = a.getValue() + "post"; + String changedValue = a.getValue() + "-post"; result.setValue(changedValue); - result.setInner(new Inner("inner" + a.getInner().getInnerValue())); + result.setInner(new Inner(a.getInner().getInnerValue() + "-post")); return result; :} diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/JavaTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/JavaTest.java index 7655c07..4e807cc 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/JavaTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/JavaTest.java @@ -45,7 +45,6 @@ public class JavaTest { private JastAddList<A> lastValueMany; private A lastValueNTA; private TestChecker checker; - private JavaHandler handler; void createModel() { model = new Root(); @@ -67,16 +66,24 @@ public class JavaTest { .setCheckForTuple(TOPIC_SEND_MANY, (name, expected) -> checkAList(expected, lastValueMany, name)) .setCheckForString(TOPIC_SEND_NTA, (name, expected) -> checkA(expected, lastValueNTA, name)) .setActualString(TOPIC_RECEIVE_TOKEN, () -> receiverRoot.getSomeToken()) + .setCheckForString(TOPIC_RECEIVE_NODE_PLAIN, (name, expected) -> + checkA(expected, receiverRoot.getSomeNode(), name)) + .setCheckForString(TOPIC_RECEIVE_NODE_MAPPED, (name, expected) -> + checkA(expected, receiverRoot.getSomeNodeWithMapping(), name)) + .setCheckForTuple(TOPIC_RECEIVE_MANY, (name, expected) -> + checkAList(expected, receiverRoot.getManyNodeList(), name)) + .setCheckForString(TOPIC_RECEIVE_NTA, (name, expected) -> + checkA(expected, receiverRoot.getNTA(), name)) .put(TOPIC_RECEIVE_TOKEN, "") + .put(TOPIC_RECEIVE_MANY, tuple()) .setActualNumberOfValues(() -> 0) .disableManualWait(); // callbacks - handler = model._ragconnect_javaHandler(); - handler.registerConsumer(TOPIC_SEND_TOKEN, bytes -> lastValueToken = new String(bytes)); - handler.registerConsumer(TOPIC_SEND_NODE, bytes -> lastValueNode = ExposingASTNode.INSTANCE.bytesToA(bytes)); - handler.registerConsumer(TOPIC_SEND_MANY, bytes -> lastValueMany = ExposingASTNode.INSTANCE.bytesToList(bytes)); - handler.registerConsumer(TOPIC_SEND_NTA, bytes -> lastValueNTA = ExposingASTNode.INSTANCE.bytesToA(bytes)); + model.ragconnectJavaRegisterConsumer(TOPIC_SEND_TOKEN, bytes -> lastValueToken = new String(bytes)); + model.ragconnectJavaRegisterConsumer(TOPIC_SEND_NODE, bytes -> lastValueNode = ExposingASTNode.INSTANCE.bytesToA(bytes)); + model.ragconnectJavaRegisterConsumer(TOPIC_SEND_MANY, bytes -> lastValueMany = ExposingASTNode.INSTANCE.bytesToList(bytes)); + model.ragconnectJavaRegisterConsumer(TOPIC_SEND_NTA, bytes -> lastValueNTA = ExposingASTNode.INSTANCE.bytesToA(bytes)); // receive receiverRoot.connectSomeToken(javaUri(TOPIC_RECEIVE_TOKEN)); @@ -99,7 +106,7 @@ public class JavaTest { checker.put(TOPIC_SEND_TOKEN, "") .put(TOPIC_SEND_NODE, "1") .put(TOPIC_SEND_MANY, tuple()) - .put(TOPIC_SEND_NTA, "1") + .put(TOPIC_SEND_NTA, "1|1") ; communicateBoth(); @@ -123,7 +130,7 @@ public class JavaTest { checker.check(); senderRoot.setInput("2"); - checker.put(TOPIC_SEND_NTA, "2").check(); + checker.put(TOPIC_SEND_NTA, "2|1").check(); senderRoot.getSendNode().setValue("3"); checker.put(TOPIC_SEND_NODE, "3").check(); @@ -134,10 +141,20 @@ public class JavaTest { senderRoot.addSendManyNode(createA("5")); checker.put(TOPIC_SEND_MANY, tuple("5")).check(); - handler.push(TOPIC_RECEIVE_TOKEN, ExposingASTNode.INSTANCE.stringToBytes("7")); + model.ragconnectJavaPush(TOPIC_RECEIVE_TOKEN, ExposingASTNode.INSTANCE.stringToBytes("7")); checker.put(TOPIC_RECEIVE_TOKEN, "7").check(); - // TODO check other receive ports + model.ragconnectJavaPush(TOPIC_RECEIVE_NODE_PLAIN, ExposingASTNode.INSTANCE.aToBytes(createA("8"))); + checker.put(TOPIC_RECEIVE_NODE_PLAIN, "8").check(); + + model.ragconnectJavaPush(TOPIC_RECEIVE_NODE_MAPPED, ExposingASTNode.INSTANCE.aToBytes(createA("9"))); + checker.put(TOPIC_RECEIVE_NODE_MAPPED, "9-post|inner-post").check(); + + model.ragconnectJavaPush(TOPIC_RECEIVE_MANY, ExposingASTNode.INSTANCE.listToBytes(new JastAddList<>(createA("10"), createA("11")))); + checker.put(TOPIC_RECEIVE_MANY, tuple("10", "11")).check(); + + model.ragconnectJavaPush(TOPIC_RECEIVE_NTA, ExposingASTNode.INSTANCE.aToBytes(createA("12"))); + checker.put(TOPIC_RECEIVE_NTA, "12").check(); System.out.println(model.ragconnectEvaluationCounterSummary()); } @@ -146,8 +163,19 @@ public class JavaTest { if (expectedValue == null) { assertNull(actual, alias); } else { + final String expectedValueInA, expectedInnerValue; + if (expectedValue.contains("|")) { + String[] tokens = expectedValue.split("\\|"); + expectedValueInA = tokens[0]; + expectedInnerValue = tokens[1]; + } else { + expectedValueInA = expectedValue; + expectedInnerValue = "inner"; + } assertNotNull(actual, alias); - assertEquals(expectedValue, actual.getValue(), alias); + assertEquals(expectedValueInA, actual.getValue(), alias); + assertNotNull(actual.getInner(), alias + ".inner"); + assertEquals(expectedInnerValue, actual.getInner().getInnerValue(), alias + ".inner"); } } diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/TestUtils.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/TestUtils.java index 91bbd40..3fb3e22 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/TestUtils.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/TestUtils.java @@ -217,73 +217,112 @@ public class TestUtils { awaitMqtt().alias(name).until(actual, Predicate.isEqual(expected)); } } + static class ValuesToCompare<T> { + protected final Map<String, ActualAndExpected<T>> values = new HashMap<>(); + protected final TestChecker parent; + + ValuesToCompare(TestChecker parent) { + this.parent = parent; + } + + public TestChecker setActual(String name, Callable<T> actual) { + values.computeIfAbsent(name, ActualAndExpected::new).actual = actual; + return parent; + } + + public TestChecker setCheck(String name, BiConsumer<String, T> check) { + values.computeIfAbsent(name, ActualAndExpected::new).customCheck = check; + return parent; + } + + public TestChecker put(String name, T expected) { + values.computeIfAbsent(name, ActualAndExpected::new).expected = expected; + return parent; + } + + ActualAndExpected<T> get(String name) { + return values.get(name); + } + + void forEach(BiConsumer<? super String, ? super ActualAndExpected<T>> action) { + values.forEach(action); + } + } + static class IntegerValuesToCompare extends ValuesToCompare<Integer> { + IntegerValuesToCompare(TestChecker parent) { + super(parent); + } + + public TestChecker incNumberOfValues() { + return addToNumberOfValues(1); + } + + public TestChecker addToNumberOfValues(int increment) { + // if there is at least one call to this, we do not need to manually wait in the next check() + parent.needManualWait = false; + Integer currentExpected = values.computeIfAbsent(NUMBER_OF_VALUES, ActualAndExpected::new).expected; + return put(NUMBER_OF_VALUES, currentExpected + increment); + } + + public TestChecker setActualNumberOfValues(Callable<Integer> actual) { + setActual(NUMBER_OF_VALUES, actual); + values.get(NUMBER_OF_VALUES).expected = 0; + return parent; + } + } private final static String NUMBER_OF_VALUES = "numberOfValues"; - private final Map<String, ActualAndExpected<String>> stringValues = new HashMap<>(); - private final Map<String, ActualAndExpected<Tuple>> tupleValues = new HashMap<>(); - private final Map<String, ActualAndExpected<Integer>> intValues = new HashMap<>(); + public final ValuesToCompare<String> stringValues = new ValuesToCompare<>(this); + public final ValuesToCompare<Tuple> tupleValues = new ValuesToCompare<>(this); + public final IntegerValuesToCompare intValues = new IntegerValuesToCompare(this); private boolean needManualWait = true; private boolean useManualWait = true; public TestChecker incNumberOfValues() { - return addToNumberOfValues(1); + return intValues.incNumberOfValues(); } public TestChecker addToNumberOfValues(int increment) { - // if there is at least one call to this, we do not need to manually wait in the next check() - needManualWait = false; - Integer currentExpected = intValues.computeIfAbsent(NUMBER_OF_VALUES, ActualAndExpected::new).expected; - return put(NUMBER_OF_VALUES, currentExpected + increment); + return intValues.addToNumberOfValues(increment); } public TestChecker setActualNumberOfValues(Callable<Integer> actual) { - setActualInteger(NUMBER_OF_VALUES, actual); - intValues.get(NUMBER_OF_VALUES).expected = 0; - return this; + return intValues.setActualNumberOfValues(actual); } public TestChecker setActualString(String name, Callable<String> actual) { - stringValues.computeIfAbsent(name, ActualAndExpected::new).actual = actual; - return this; + return stringValues.setActual(name, actual); } public TestChecker setCheckForString(String name, BiConsumer<String, String> check) { - stringValues.computeIfAbsent(name, ActualAndExpected::new).customCheck = check; - return this; + return stringValues.setCheck(name, check); } public TestChecker put(String name, String expected) { - stringValues.computeIfAbsent(name, ActualAndExpected::new).expected = expected; - return this; + return stringValues.put(name, expected); } public TestChecker setActualTuple(String name, Callable<Tuple> actual) { - tupleValues.computeIfAbsent(name, ActualAndExpected::new).actual = actual; - return this; + return tupleValues.setActual(name, actual); } public TestChecker setCheckForTuple(String name, BiConsumer<String, Tuple> check) { - tupleValues.computeIfAbsent(name, ActualAndExpected::new).customCheck = check; - return this; + return tupleValues.setCheck(name, check); } public TestChecker put(String name, Tuple expected) { - tupleValues.computeIfAbsent(name, ActualAndExpected::new).expected = expected; - return this; + return tupleValues.put(name, expected); } public TestChecker setActualInteger(String name, Callable<Integer> actual) { - intValues.computeIfAbsent(name, ActualAndExpected::new).actual = actual; - return this; + return intValues.setActual(name, actual); } public TestChecker setCheckForInteger(String name, BiConsumer<String, Integer> check) { - intValues.computeIfAbsent(name, ActualAndExpected::new).customCheck = check; - return this; + return intValues.setCheck(name, check); } public TestChecker put(String name, Integer expected) { - intValues.computeIfAbsent(name, ActualAndExpected::new).expected = expected; - return this; + return intValues.put(name, expected); } public TestChecker disableManualWait() { -- GitLab From d37e1825a2df901adc68912c35fc95e5bf4358b3 Mon Sep 17 00:00:00 2001 From: rschoene <rene.schoene@tu-dresden.de> Date: Mon, 30 May 2022 17:19:06 +0200 Subject: [PATCH 7/7] Finalize tests for initial JavaHandler - try to find cause for failing RelationTest --- .gitlab-ci.yml | 2 ++ ragconnect.tests/.gitignore | 1 + .../ragconnect/tests/AbstractMqttTest.java | 6 +---- .../org/jastadd/ragconnect/tests/Errors.java | 3 +-- .../jastadd/ragconnect/tests/JavaTest.java | 4 +-- .../ragconnect/tests/MqttHandlerTest.java | 2 +- .../ragconnect/tests/RagConnectTest.java | 26 +++++++++++++++++++ .../ragconnect/tests/RegressionTests.java | 2 +- .../jastadd/ragconnect/tests/Warnings.java | 3 +-- .../tests/relation/RelationTest.java | 2 +- .../src/test/resources/log4j2.xml | 3 +++ 11 files changed, 39 insertions(+), 15 deletions(-) create mode 100644 ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/RagConnectTest.java diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 44a279a..401f721 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -42,6 +42,8 @@ test: - ./gradlew --console=plain --no-daemon allTests artifacts: when: always + paths: + - "ragconnect.tests/test.log" reports: junit: "ragconnect.tests/build/test-results/**/TEST-*.xml" expire_in: 1 week diff --git a/ragconnect.tests/.gitignore b/ragconnect.tests/.gitignore index 87b4cdd..31993ce 100644 --- a/ragconnect.tests/.gitignore +++ b/ragconnect.tests/.gitignore @@ -3,3 +3,4 @@ src/gen-res/ src/gen/ out/ *.class +test.log diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/AbstractMqttTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/AbstractMqttTest.java index c537a1d..61fc420 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/AbstractMqttTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/AbstractMqttTest.java @@ -14,14 +14,12 @@ import java.util.concurrent.TimeUnit; * @author rschoene - Initial contribution */ @Tag("mqtt") -public abstract class AbstractMqttTest { +public abstract class AbstractMqttTest extends RagConnectTest { private static boolean checkDone = false; protected static MqttHandler publisher; - protected Logger logger = LoggerFactory.getLogger(getClass()); - /** * if the initial/current value shall be sent upon connecting */ @@ -61,7 +59,6 @@ public abstract class AbstractMqttTest { public final void testCommunicateSendInitialValue() throws IOException, InterruptedException { this.writeCurrentValue = true; - logger.debug("Start testCommunicateSendInitialValue"); createModel(); setupReceiverAndConnect(); @@ -80,7 +77,6 @@ public abstract class AbstractMqttTest { public final void testCommunicateOnlyUpdatedValue() throws IOException, InterruptedException { this.writeCurrentValue = false; - logger.debug("Start testCommunicateOnlyUpdatedValue"); createModel(); setupReceiverAndConnect(); diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/Errors.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/Errors.java index d774d91..9d4c730 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/Errors.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/Errors.java @@ -22,9 +22,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue; * * @author rschoene - Initial contribution */ -public class Errors { +public class Errors extends RagConnectTest { - private static final Logger logger = LoggerFactory.getLogger(Errors.class); private static final String ERROR_DIRECTORY = "errors/"; private static final String OUTPUT_DIRECTORY = TestUtils.OUTPUT_DIRECTORY_PREFIX + ERROR_DIRECTORY; diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/JavaTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/JavaTest.java index 4e807cc..0c33e9c 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/JavaTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/JavaTest.java @@ -21,8 +21,7 @@ import static org.junit.jupiter.api.Assertions.*; * * @author rschoene - Initial contribution */ -@Tag("New") -public class JavaTest { +public class JavaTest extends RagConnectTest { private static final String TOPIC_RECEIVE_TOKEN = "receiveToken"; private static final String TOPIC_RECEIVE_NODE_PLAIN = "receiveNode/plain"; @@ -35,7 +34,6 @@ public class JavaTest { private static final String TOPIC_SEND_MANY = "sendMany"; private static final String TOPIC_SEND_NTA = "sendNTA"; - protected Logger logger = LoggerFactory.getLogger(getClass()); private Root model; private SenderRoot senderRoot; private ReceiverRoot receiverRoot; diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/MqttHandlerTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/MqttHandlerTest.java index 091990a..be61201 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/MqttHandlerTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/MqttHandlerTest.java @@ -20,7 +20,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; * @author rschoene - Initial contribution */ @Tag("mqtt") -public class MqttHandlerTest { +public class MqttHandlerTest extends RagConnectTest { @Test public void defaultBehaviour() { diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/RagConnectTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/RagConnectTest.java new file mode 100644 index 0000000..e2da157 --- /dev/null +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/RagConnectTest.java @@ -0,0 +1,26 @@ +package org.jastadd.ragconnect.tests; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.TestInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Base for all RagConnect tests. + * + * @author rschoene - Initial contribution + */ +public class RagConnectTest { + protected Logger logger = LoggerFactory.getLogger(getClass()); + + @BeforeEach + public void logStart(TestInfo testInfo) { + logger.info("Starting {}.{}", getClass().getSimpleName(), testInfo.getDisplayName()); + } + + @AfterEach + public void logEnd(TestInfo testInfo) { + logger.info("Finished {}.{}", getClass().getSimpleName(), testInfo.getDisplayName()); + } +} diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/RegressionTests.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/RegressionTests.java index 67c8217..5f74942 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/RegressionTests.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/RegressionTests.java @@ -17,7 +17,7 @@ import static org.junit.jupiter.api.Assertions.*; * * @author rschoene - Initial contribution */ -public class RegressionTests { +public class RegressionTests extends RagConnectTest { private static final String REGRESSION_TEST_OUTPUT_DIRECTORY = "regression-test/"; diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/Warnings.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/Warnings.java index b0840d6..121843c 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/Warnings.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/Warnings.java @@ -21,9 +21,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue; * * @author rschoene - Initial contribution */ -public class Warnings { +public class Warnings extends RagConnectTest { - private static final Logger logger = LoggerFactory.getLogger(Warnings.class); private static final String WARNING_DIRECTORY = "warnings/"; private static final String OUTPUT_DIRECTORY = TestUtils.OUTPUT_DIRECTORY_PREFIX + WARNING_DIRECTORY; diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/relation/RelationTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/relation/RelationTest.java index a245387..4ac0f55 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/relation/RelationTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/relation/RelationTest.java @@ -616,7 +616,7 @@ public class RelationTest extends AbstractMqttTest { biB(3).getInner().setInnerValue("inner-bi-b3"); checker.check(); - System.out.println(model.ragconnectEvaluationCounterSummary()); + logger.debug(model.ragconnectEvaluationCounterSummary()); } private void assertNullOrA(String expectedValue, A actual, String alias) { diff --git a/ragconnect.tests/src/test/resources/log4j2.xml b/ragconnect.tests/src/test/resources/log4j2.xml index 653d6c3..9a1b22e 100644 --- a/ragconnect.tests/src/test/resources/log4j2.xml +++ b/ragconnect.tests/src/test/resources/log4j2.xml @@ -4,6 +4,9 @@ <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%highlight{%d{HH:mm:ss.SSS} %-5level [%t] %logger{20} - %msg%n}" disableAnsi="false"/> </Console> + <File name="TestLogs" fileName="test.log" append="false"> + <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level [%t] %logger{20} - %msg%n"/> + </File> </Appenders> <Loggers> <Root level="debug"> -- GitLab