From 88a3b283f8156813f6b70cc43324d776875d1920 Mon Sep 17 00:00:00 2001
From: rschoene <rene.schoene@tu-dresden.de>
Date: Mon, 15 Jun 2020 11:48:53 +0200
Subject: [PATCH] Extracting mqtt aspect.

---
 ros2rag.base/build.gradle                     |  3 +
 .../src/main/jastadd/MustacheNodes.relast     |  2 +
 ros2rag.base/src/main/jastadd/Navigation.jrag |  2 +-
 ros2rag.base/src/main/jastadd/Ros2Rag.relast  |  1 -
 .../main/jastadd/backend/Configuration.jadd   |  1 +
 .../src/main/jastadd/backend/Generation.jadd  | 87 +++++++++----------
 .../ros2rag/compiler/AppendableWriter.java    | 37 ++++++++
 ros2rag.base/src/main/resources/mqtt.mustache | 22 +++++
 8 files changed, 107 insertions(+), 48 deletions(-)
 create mode 100644 ros2rag.base/src/main/jastadd/MustacheNodes.relast
 create mode 100644 ros2rag.base/src/main/java/org/jastadd/ros2rag/compiler/AppendableWriter.java
 create mode 100644 ros2rag.base/src/main/resources/mqtt.mustache

diff --git a/ros2rag.base/build.gradle b/ros2rag.base/build.gradle
index 9e0bde2..dec7696 100644
--- a/ros2rag.base/build.gradle
+++ b/ros2rag.base/build.gradle
@@ -19,6 +19,7 @@ buildscript {
 dependencies {
     implementation 'com.fasterxml.jackson.core:jackson-core:2.9.8'
     implementation 'com.fasterxml.jackson.core:jackson-databind:2.9.8'
+    implementation 'com.github.spullara.mustache.java:compiler:0.9.6'
 //    api 'org.jastadd:jastadd:2.3.4'
     runtime 'org.jastadd:jastadd:2.3.4'
     api group: 'net.sf.beaver', name: 'beaver-rt', version: '0.9.11'
@@ -62,6 +63,7 @@ task relast(type: JavaExec) {
             "../libs/relast.jar",
             "../relast.preprocessor/src/main/jastadd/RelAst.relast",
             "./src/main/jastadd/Ros2Rag.relast",
+            "./src/main/jastadd/MustacheNodes.relast",
             "--listClass=java.util.ArrayList",
             "--jastAddList=JastAddList",
             "--useJastAddNames",
@@ -73,6 +75,7 @@ task relast(type: JavaExec) {
     inputs.files file("../libs/relast.jar"),
             file("../relast.preprocessor/src/main/jastadd/RelAST.relast"),
             file("src/main/jastadd/Ros2Rag.relast")
+            file("src/main/jastadd/MustacheNodes.relast")
     outputs.files file("./src/gen/jastadd/Ros2Rag.ast"),
             file("src/gen/jastadd/Ros2Rag.jadd"),
             file("src/gen/jastadd/Ros2RagRefResolver.jadd"),
diff --git a/ros2rag.base/src/main/jastadd/MustacheNodes.relast b/ros2rag.base/src/main/jastadd/MustacheNodes.relast
new file mode 100644
index 0000000..3027727
--- /dev/null
+++ b/ros2rag.base/src/main/jastadd/MustacheNodes.relast
@@ -0,0 +1,2 @@
+TypeComponentMustache ;
+rel TypeComponentMustache.TypeComponent -> TypeComponent ;
diff --git a/ros2rag.base/src/main/jastadd/Navigation.jrag b/ros2rag.base/src/main/jastadd/Navigation.jrag
index f56d998..e034804 100644
--- a/ros2rag.base/src/main/jastadd/Navigation.jrag
+++ b/ros2rag.base/src/main/jastadd/Navigation.jrag
@@ -3,7 +3,7 @@ aspect Navigation {
   // --- program ---
   eq Ros2Rag.getChild().program() = getProgram();
 
-  // --- ros2rag
+  // --- ros2rag ---
   inh Ros2Rag ASTNode.ros2rag();
   eq Ros2Rag.getChild().ros2rag() = this;
 
diff --git a/ros2rag.base/src/main/jastadd/Ros2Rag.relast b/ros2rag.base/src/main/jastadd/Ros2Rag.relast
index a549970..e1a84e8 100644
--- a/ros2rag.base/src/main/jastadd/Ros2Rag.relast
+++ b/ros2rag.base/src/main/jastadd/Ros2Rag.relast
@@ -10,7 +10,6 @@ rel TokenUpdateDefinition.Token -> TokenComponent;
 ReadFromMqttDefinition : TokenUpdateDefinition;
 WriteToMqttDefinition  : TokenUpdateDefinition;
 
-// example: RobotArm._AppropriateSpeed canDependOn Joint.CurrentPosition as dependency1
 DependencyDefinition ::= <ID>;
 rel DependencyDefinition.Source <-> TokenComponent.DependencySourceDefinition*;
 rel DependencyDefinition.Target -> TokenComponent;
diff --git a/ros2rag.base/src/main/jastadd/backend/Configuration.jadd b/ros2rag.base/src/main/jastadd/backend/Configuration.jadd
index 711ba25..d4f5b43 100644
--- a/ros2rag.base/src/main/jastadd/backend/Configuration.jadd
+++ b/ros2rag.base/src/main/jastadd/backend/Configuration.jadd
@@ -1,4 +1,5 @@
 aspect Configuration {
   public static boolean ASTNode.loggingEnabledForReads = false;
   public static boolean ASTNode.loggingEnabledForWrites = false;
+  public static TypeDecl ASTNode.rootNode;
 }
diff --git a/ros2rag.base/src/main/jastadd/backend/Generation.jadd b/ros2rag.base/src/main/jastadd/backend/Generation.jadd
index e698e40..81e2dab 100644
--- a/ros2rag.base/src/main/jastadd/backend/Generation.jadd
+++ b/ros2rag.base/src/main/jastadd/backend/Generation.jadd
@@ -22,10 +22,10 @@ aspect GenerationUtils {
 }
 
 aspect AspectGeneration {
+  // naming convention attributes
   syn String TokenComponent.internalName() = getDependencySourceDefinitionList().isEmpty() ? externalName() : "_internal_" + getName();
   syn String TokenComponent.externalName() = getName();
 
-  // naming convention attributes
   syn String TokenUpdateDefinition.connectMethod() = "connect" + getToken().getName();
   syn String WriteToMqttDefinition.writeTopic() = "_topic_" + getToken().getName();
   syn String WriteToMqttDefinition.lastValue() = "_lastValue" + getToken().getName();
@@ -39,10 +39,6 @@ aspect AspectGeneration {
   syn String DependencyDefinition.internalRelationPrefix() = "_internal_" + getID();
   syn String DependencyDefinition.internalTokenName() = getSource().internalName();
 
-  inh String UpdateDefinition.mqttUpdaterAttribute();
-  inh String MappingDefinition.mqttUpdaterAttribute();
-  inh String DependencyDefinition.mqttUpdaterAttribute();
-  eq Ros2Rag.getChild().mqttUpdaterAttribute() = mqttUpdaterAttribute();
   syn String Ros2Rag.mqttUpdaterAttribute() = "_mqttUpdater";
   syn String Ros2Rag.mqttUpdaterField() = "_mqttUpdater";
 
@@ -50,54 +46,53 @@ aspect AspectGeneration {
   syn String Ros2Rag.mqttWaitUntilReadyMethod() = "MqttWaitUntilReady";
   syn String Ros2Rag.mqttCloseMethod() = "MqttCloseConnections";
 
-  public String Ros2Rag.generateAspect(String rootNodeName) {
-    StringBuilder sb = new StringBuilder();
-    TypeDecl rootNode = getProgram().resolveTypeDecl(rootNodeName);
-    generateMqttAspect(sb, rootNode);
-    generateGrammarExtension(sb);
-    return sb.toString();
-  }
+  // naming copy attributes
+  // --- mqttUpdaterAttribute ---
+  inh String UpdateDefinition.mqttUpdaterAttribute();
+  inh String MappingDefinition.mqttUpdaterAttribute();
+  inh String DependencyDefinition.mqttUpdaterAttribute();
+  eq Ros2Rag.getChild().mqttUpdaterAttribute() = mqttUpdaterAttribute();
 
-  public void Ros2Rag.generateMqttAspect(StringBuilder sb, TypeDecl rootNode) {
-    String rootNodeName = rootNode.getName();
-    sb.append("aspect MQTT {\n");
-    sb.append(ind(1)).append("private MqttUpdater ").append(rootNodeName)
-      .append(".").append(mqttUpdaterField()).append(" = new MqttUpdater();\n");
-
-    // mqttSetHost(String host)
-    sb.append(ind(1)).append("public void ").append(rootNodeName).append(".")
-      .append(mqttSetHostMethod()).append("(String host) throws java.io.IOException {\n");
-    sb.append(ind(2)).append(mqttUpdaterField()).append(".setHost(host);\n");
-    sb.append(ind(1)).append("}\n");
-
-    // mqttSetHost(String host, int port)
-    sb.append(ind(1)).append("public void ").append(rootNodeName).append(".")
-      .append(mqttSetHostMethod()).append("(String host, int port) throws java.io.IOException {\n");
-    sb.append(ind(2)).append(mqttUpdaterField()).append(".setHost(host, port);\n");
-    sb.append(ind(1)).append("}\n\n");
+  // --- mqttUpdaterField ---
+  eq Ros2Rag.getChild().mqttUpdaterField() = mqttUpdaterField();
 
-    // mqttWaitUntilReady
-    sb.append(ind(1)).append("public boolean ").append(rootNodeName).append(".")
-      .append(mqttWaitUntilReadyMethod()).append("(long time, java.util.concurrent.TimeUnit unit) {\n");
-    sb.append(ind(2)).append("return ").append(mqttUpdaterField()).append(".waitUntilReady(time, unit);\n");
-    sb.append(ind(1)).append("}\n\n");
+  // --- rootNodeName ---
+  syn String ASTNode.rootNodeName() = rootNode.getName();
 
-    // mqttClose
-    sb.append(ind(1)).append("public void ").append(rootNodeName).append(".")
-      .append(mqttCloseMethod()).append("() {\n");
-    sb.append(ind(2)).append(mqttUpdaterField()).append(".close();\n");
-    sb.append(ind(1)).append("}\n\n");
+  // mustache specific nodes
+  syn nta TypeComponentMustache TypeComponent.mustache() {
+    TypeComponentMustache result = new TypeComponentMustache();
+    result.setTypeComponent(this);
+    return result;
+  }
+  syn String TypeComponentMustache.name() = getTypeComponent().getName();
+  inh String TypeComponentMustache.mqttUpdaterAttribute();
+  inh String TypeComponentMustache.mqttUpdaterField();
 
-    // mqttUpdater
-    sb.append(ind(1)).append("inh MqttUpdater ASTNode.").append(mqttUpdaterAttribute()).append("();\n");
+  // mustache specific attributes
+  syn java.util.List<TypeComponentMustache> Ros2Rag.rootTypeChildren() {
+    java.util.List<TypeComponentMustache> result = new java.util.ArrayList<>();
     for (Component child : rootNode.getComponentList()) {
-      if (child.isTypeComponent()) {
-        sb.append(ind(1)).append("eq ").append(rootNodeName)
-          .append(".get").append(child.getName()).append("().")
-          .append(mqttUpdaterAttribute()).append("() = ").append(mqttUpdaterField()).append(";\n");
+      if (child.isTypeComponent()){
+        result.add(child.asTypeComponent().mustache());
       }
     }
-    sb.append("}\n\n");
+    return result;
+  }
+
+  public String Ros2Rag.generateAspect(String rootNodeName) {
+    StringBuilder sb = new StringBuilder();
+    rootNode = getProgram().resolveTypeDecl(rootNodeName);
+    generateMqttAspect(sb);
+    generateGrammarExtension(sb);
+    return sb.toString();
+  }
+
+  public void Ros2Rag.generateMqttAspect(StringBuilder sb) {
+    String rootNodeName = rootNode.getName();
+    com.github.mustachejava.MustacheFactory mf = new com.github.mustachejava.DefaultMustacheFactory();
+    com.github.mustachejava.Mustache m = mf.compile("mqtt.mustache");
+    m.execute(new java.io.PrintWriter(new org.jastadd.ros2rag.compiler.AppendableWriter(sb)), this);
   }
 
   public void Ros2Rag.generateGrammarExtension(StringBuilder sb) {
diff --git a/ros2rag.base/src/main/java/org/jastadd/ros2rag/compiler/AppendableWriter.java b/ros2rag.base/src/main/java/org/jastadd/ros2rag/compiler/AppendableWriter.java
new file mode 100644
index 0000000..97680b1
--- /dev/null
+++ b/ros2rag.base/src/main/java/org/jastadd/ros2rag/compiler/AppendableWriter.java
@@ -0,0 +1,37 @@
+package org.jastadd.ros2rag.compiler;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * Writer appending to a StringBuilder.
+ *
+ * @author rschoene - Initial contribution
+ */
+public class AppendableWriter extends Writer {
+  private final StringBuilder sb;
+
+  public AppendableWriter(StringBuilder sb) {
+    this.sb = sb;
+  }
+
+  @Override
+  public void write(char[] chars, int off, int len) throws IOException {
+    sb.append(chars, off, len);
+  }
+
+  @Override
+  public void write(String str) throws IOException {
+    sb.append(str);
+  }
+
+  @Override
+  public void flush() {
+
+  }
+
+  @Override
+  public void close() {
+
+  }
+}
diff --git a/ros2rag.base/src/main/resources/mqtt.mustache b/ros2rag.base/src/main/resources/mqtt.mustache
new file mode 100644
index 0000000..33e3f4e
--- /dev/null
+++ b/ros2rag.base/src/main/resources/mqtt.mustache
@@ -0,0 +1,22 @@
+aspect MQTT {
+  private MqttUpdater {{rootNodeName}}.{{mqttUpdaterField}} = new MqttUpdater();
+  public void {{rootNodeName}}.{{mqttSetHostMethod}}(String host) throws java.io.IOException {
+    {{mqttUpdaterField}}.setHost(host);
+  }
+  public void {{rootNodeName}}.{{mqttSetHostMethod}}(String host, int port) throws java.io.IOException {
+    {{mqttUpdaterField}}.setHost(host, port);
+  }
+
+  public boolean {{rootNodeName}}.{{mqttWaitUntilReadyMethod}}(long time, java.util.concurrent.TimeUnit unit) {
+    return {{mqttUpdaterField}}.waitUntilReady(time, unit);
+  }
+
+  public void {{rootNodeName}}.{{mqttCloseMethod}}() {
+    {{mqttUpdaterField}}.close();
+  }
+
+  inh MqttUpdater ASTNode.{{mqttUpdaterAttribute}}();
+  {{#rootTypeChildren}}
+  eq {{rootNodeName}}.get{{name}}().{{mqttUpdaterAttribute}}() = {{mqttUpdaterField}};
+  {{/rootTypeChildren}}
+}
-- 
GitLab