Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • feature/ros-example
  • master
2 results

Target

Select target project
  • jastadd/ragconnect-minimal
1 result
Select Git revision
  • feature/ros-example
  • master
2 results
Show changes
Commits on Source (31)
Showing
with 739 additions and 83 deletions
......@@ -8,3 +8,6 @@
/build/
/src/gen
/src/gen-res
/*.png
uml.md
/public/
variables:
GIT_SUBMODULE_STRATEGY: recursive
stages:
- build
- ragdoc_build
- ragdoc_view
- publish
before_script:
- export GRADLE_USER_HOME=`pwd`/.gradle
cache:
paths:
- .gradle/wrapper
- .gradle/caches
build:
image: openjdk:11
stage: build
script:
- ./gradlew --console=plain --no-daemon assemble
artifacts:
paths:
- "src/gen"
ragdoc_build:
image:
name: "git-st.inf.tu-dresden.de:4567/jastadd/ragdoc-builder"
entrypoint: [""]
stage: ragdoc_build
dependencies:
- build
script:
- JAVA_FILES=$(find src/ -name '*.java')
- /ragdoc-builder/start-builder.sh -excludeGenerated -d data/ $JAVA_FILES
artifacts:
paths:
- "data/"
ragdoc_view:
image:
name: "git-st.inf.tu-dresden.de:4567/jastadd/ragdoc-view:relations"
entrypoint: [""]
stage: ragdoc_view
dependencies:
- ragdoc_build
script:
- DATA_DIR=$(pwd -P)/data
- mkdir -p pages/_static/ragdoc
- OUTPUT_DIR=$(pwd -P)/pages/docs/ragdoc
- cd /ragdoc-view
- ( cd src/ && rm -rf data && ln -s $DATA_DIR )
- /ragdoc-view/build-view.sh --output-path=$OUTPUT_DIR
- ls -lah $OUTPUT_DIR
artifacts:
paths:
- "pages/docs/ragdoc"
pages:
image: python:3.10.0-bullseye
stage: publish
dependencies:
- ragdoc_view
before_script:
- pip install -r pages/requirements.txt
script:
- cd pages && mkdocs build
artifacts:
paths:
- public
buildscript {
repositories.jcenter()
dependencies {
classpath 'org.jastadd:jastaddgradle:1.13.3'
}
}
// --- Plugin definitions ---
plugins {
id 'com.github.ben-manes.versions' version '0.42.0'
id 'java'
id 'idea'
id 'org.jastadd' version "${jastadd_gradle_version}"
id 'application'
}
apply plugin: 'jastadd'
mainClassName = 'de.tudresden.inf.st.mrc.MinimalMain'
// --- Dependencies ---
repositories {
jcenter()
mavenCentral()
maven {
name "gitlab-maven"
url "https://gitlab.example.com/api/v4/groups/jastadd/-/packages/maven"
url "https://git-st.inf.tu-dresden.de/api/v4/groups/jastadd/-/packages/maven"
}
}
apply plugin: 'jastadd'
configurations {
baseRuntimeClasspath
ragconnectClasspath
ragconnect
grammar2uml
relast
}
run {
standardInput = System.in
dependencies {
grammar2uml group: 'de.tudresden.inf.st', name: 'grammar2uml', version: "${grammar2uml_version}"
relast group: 'org.jastadd', name: 'relast', version: "${relast_version}"
ragconnect group: 'de.tudresden.inf.st', name: 'ragconnect', version: "${ragconnect_version}"
implementation group: 'de.tudresden.inf.st', name: 'dumpAst', version: "${dumpAst_version}"
jastadd2 group: 'org.jastadd', name: 'jastadd2', version: "${jastadd_version}"
implementation group: 'org.fusesource.mqtt-client', name: 'mqtt-client', version: '1.16'
implementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: "${log4j_version}"
implementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: "${log4j_version}"
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: "${jackson_version}"
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: "${jackson_version}"
}
// --- Preprocessors ---
File genSrc = file("src/gen/java")
sourceSets.main.java.srcDir genSrc
idea.module.generatedSourceDirs += genSrc
dependencies {
implementation fileTree(include: ['dumpAst2uml.jar'], dir: 'libs')
implementation group: 'org.fusesource.mqtt-client', name: 'mqtt-client', version: '1.15'
implementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.11.2'
implementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.11.2'
ragconnectClasspath group: 'de.tudresden.inf.st', name: 'ragconnect.base', version: '0.2.3'
jastadd2 "org.jastadd:jastadd:2.3.4"
}
// Input files for relast
def relastFiles = ["src/gen/jastadd/MinimalModel.relast", "src/gen/jastadd/RagConnect.relast"]
// phases: ragConnect -> RelAst -> JastAdd
// phase: ragConnect
task grammar2uml(type: JavaExec) {
group = 'documentation'
main = 'de.tudresden.inf.st.jastadd.grammar2uml.compiler.Compiler'
classpath = configurations.grammar2uml
args([
'--inputGrammar2Uml=minimal.folder',
'--output=uml.png',
'src/main/jastadd/MinimalModel.relast'
])
}
// phases: RagConnect -> RelAst -> JastAdd
// phase: RagConnect
task ragConnect(type: JavaExec) {
group = 'Build'
group = 'build'
classpath = configurations.ragconnect
main = 'org.jastadd.ragconnect.compiler.Compiler'
classpath = configurations.ragconnectClasspath
args([
'--o=src/gen/jastadd',
'src/main/jastadd/MinimalModel.relast',
'src/main/jastadd/MinimalModel.connect',
'--rootNode=A'
'--List=JastAddList',
'--logReads',
'--logWrites',
'--rootNode=Root',
'--incremental=param,debug',
"--tracing=cache,flush"
])
}
// phase: RelAst
task relastToJastAdd(type: JavaExec) {
group = 'Build'
main = "-jar"
group = 'build'
classpath = configurations.relast
main = 'org.jastadd.relast.compiler.Compiler'
args(["libs/relast.jar",
args([
"--grammarName=./src/gen/jastadd/model",
"--useJastAddNames",
"--listClass=java.util.ArrayList",
"--jastAddList=JastAddList",
"--serializer=jackson",
"--resolverHelper",
"--file"]
"--file"
]
+
relastFiles)
......@@ -86,19 +100,13 @@ task relastToJastAdd(type: JavaExec) {
outputs.files file("./src/gen/jastadd/model.ast"), file("./src/gen/jastadd/model.jadd")
}
// --- JastAdd ---
// phase: JastAdd
jastadd {
configureModuleBuild()
modules {
//noinspection GroovyAssignabilityCheck
module("minimal") {
java {
basedir "src/"
include "main/**/*.java"
include "gen/**/*.java"
}
jastadd {
basedir "src/"
include "main/jastadd/**/*.ast"
......@@ -117,28 +125,38 @@ jastadd {
}
preprocessParser.doFirst {
args += ["--no-beaver-symbol"]
}
module = "minimal"
astPackage = 'de.tudresden.inf.st.mrc.ast'
genDir = 'src/gen/java'
buildInfoDir = 'src/gen-res'
// jastaddOptions = ["--lineColumnNumbers", "--visitCheck=true", "--rewrite=cnta", "--cache=all"]
// default options are: '--rewrite=cnta', '--safeLazy', '--visitCheck=false', '--cacheCycle=false'
extraJastAddOptions = ["--lineColumnNumbers", '--List=JastAddList']
extraJastAddOptions = [
'--lineColumnNumbers',
'--List=JastAddList',
'--cache=all',
"--flush=full",
"--incremental=param,debug",
"--tracing=cache,flush",
]
}
cleanGen.doFirst {
delete "src/gen/jastadd"
}
// Workflow configuration for phases
// --- Versioning and Publishing ---
mainClassName = 'de.tudresden.inf.st.mrc.MinimalMain'
// --- Task order ---
generateAst.dependsOn relastToJastAdd
relastToJastAdd.dependsOn ragConnect
// --- Misc ---
run {
standardInput = System.in
}
jackson_version = 2.13.3
log4j_version = 2.18.0
jastadd_gradle_version = 1.15.0
jastadd_version = 2.3.5-dresden-7
ragconnect_version = 1.0.0-alpha-214
relast_version = 0.4.0-143
grammar2uml_version = 0.2.4
dumpAst_version = 1.2.0
No preview for this file type
folder Sender : SenderRoot, SenderSubTree
folder Receiver : ReceiverRoot, ReceiverSubTree
folder Alfa : Alfa, Echo, Foxtrot, Golf
{% block footer %}
<p>{% if config.copyright %}
<small>{{ config.copyright }}<br></small>
{% endif %}
<hr>
Built with <a href="https://www.mkdocs.org/">MkDocs</a> using a <a href="https://github.com/snide/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
{% if page and page.meta and page.meta.git_revision_date_localized %}
<small><br><i>Last updated {{ page.meta.git_revision_date_localized }}</i></small>
{% endif %}
</p>
{% endblock %}
# Automatic Incremental Demo
This demonstration shows receiving and send of a complete subtree (of a type named `Alfa`).
The subtree has various children and relations within the subtree.
There are two separate trees ("sender" and "receiver").
The sender has a token "Input" which the subtree that is sent depends on.
That means, whenever this token is changed, a new subtree is calculated and sent out.
When running, three visualizations will be generated, one for the initial state (`00-initial-*.png`), one after setting the Input to "1" (`01-after-1-*.png`), and a last setting Input to "2" (`02-after-2-*.png`).
They show sender and receiver, respectively.
Furthermore, the console output also show sender and receiver.
# Dependency Definition Demo
This demo requires some setup in order to showcase its use case - the dependency definitions.
As all demos are based on the same code base, those changes have to be done manually.
First disable incremental evaluation by commenting out parameters for incremental evaluation (lines 76 and 143 in `build.gradle`):
```
'--incremental=param,debug',
"--incremental=param,debug",
```
Then comment in the dependency definitions in the connect specification (lines 15-17 in `src/main/jastadd/MinimalModel.connect`) to look like:
```
A.OutputOnA canDependOn A.Input as dependencyA ;
B.OutputOnB canDependOn A.Input as dependencyB ;
C.OutputOnC canDependOn A.Input as dependencyC ;
```
And finally comment in the usage of dependency definitions in the main class (lines 133-138 in `src/main/java/de/tudresden/inf/st/mrc/MinimalMain.java`) to look like:
```
// a.OutputOnA -> a.Input
normalA.addDependencyA(normalA);
// b1.OutputOnB -> a.Input
b1.addDependencyB(normalA);
// b2.OutputOnB -> a.Input
b2.addDependencyB(normalA);
```
The demonstration will show, how dependency definitions can be used in case incremental evaluation is not used.
# RagConnect Minimal Example
This repository is used to show three examples using [RagConnect](https://jastadd.pages.st.inf.tu-dresden.de/ragconnect/).
All examples can be run without prior knowledge of RagConnect or Attribute Grammars, but you are encouraged to change inputs (grammar, attributes, connect specifications), recompile and observe the resulting changes.
All three demos require a running MQTT broker on your machine (the application will abort if no connection is possible).
We recommend [mosquitto](https://mosquitto.org/) as it is easy to set up.
To visualize the complete grammar, the gradle task `grammar2uml` can be used, which produces the file `uml.png` containing the visualization.
# Simple Tree Demo
This demonstration is an interactive demo.
It requires you to publish messages by hand. This can be achieved by using e.g. [mqtt-spy](https://kamilfb.github.io/mqtt-spy/) or the command line tools from mosquitto (`mosquitto_pub`).
The demo creates a tiny AST of the form:
```
Root
|- A
|- Input:String
|- B
|- (computed) OutputOnB:String
```
The "Input" token is connected to MQTT topic `input`, i.e., whenever a new message is received on that topic, the content of the message is written into that token.
Everytime the Input token is updated, the computed property "OutputOnB" is recalculated.
Then its content is to be sent to topic `output`, but only after applying a (simple) transformation appending `"postfix"`.
site_name: RagConnect Minimal Example
repo_url: https://git-st.inf.tu-dresden.de/jastadd/ragconnect-minimal
site_dir: ../public
nav:
- "Home": index.md
- "1. Simple Tree": simple-tree.md
- "2. Dependency Definition Demo": dependency-definition.md
- "3. Automatic Incremental Demo": automatic-incremental.md
- "API documentation": ragdoc/index.html
theme:
name: readthedocs
custom_dir: custom_theme/
markdown_extensions:
- toc:
permalink:
- admonition
plugins:
- search
- git-revision-date-localized:
type: datetime
timezone: Europe/Berlin
locale: en
fallback_to_build_date: True
- macros
mkdocs==1.2.2
mkdocs-git-revision-date-localized-plugin==0.10.3
mkdocs-macros-plugin==0.6.3
Jinja2==2.11.2
MarkupSafe==1.1.1
// --- simple case ---
receive A.Input ;
send A.OutputOnA ;
send B.OutputOnB using Transformation ;
send C.OutputOnC using Transformation ;
send A.D ;
receive A.Reading ;
// mapping definitions
Transformation maps String s to String {:
return s + "postfix";
:}
// dependency definitions
A.OutputOnA canDependOn A.Input as dependencyA ;
B.OutputOnB canDependOn A.Input as dependencyB ;
// dependency definitions not needed for incremental evaluation
//A.OutputOnA canDependOn A.Input as dependencyA ;
//B.OutputOnB canDependOn A.Input as dependencyB ;
//C.OutputOnC canDependOn A.Input as dependencyC ;
// --- relational case ---
send SenderRoot.Alfa ;
receive ReceiverRoot.Alfa ;
......@@ -4,4 +4,63 @@ aspect Computation {
syn String B.getOutputOnB() = "b" + input();
inh String B.input();
eq A.getB().input() = getInput();
syn String C.getOutputOnC() = "c" + input();
inh String C.input();
eq A.getC().input() = getInput();
syn D A.getD() = new D().setID("dd" + getInput());
syn Alfa SenderRoot.getAlfa() {
Alfa result = new Alfa();
for (int i = 0; i < 4; i++) {
result.addEcho(new Echo().setID(i));
result.addFoxtrot(new Foxtrot().setID(i));
result.addGolf(new Golf().setID(i));
}
// // rel Alfa.MyBravo -> Bravo ;
// result.setMyBravo(getBravo(getInput()));
// // rel Alfa.MultiBravo* -> Bravo ;
// result.addMultiBravo(getBravo(getInput()));
// result.addMultiBravo(getBravo((getInput() + 1)));
// // rel Alfa.MidiDelta <-> Delta.MidiAlfa? ;
// result.setMidiDelta(getDelta(getInput()));
// rel Alfa.MyEcho -> Echo ;
result.setMyEcho(result.getEcho(getInput()));
// rel Alfa.MultiEcho* -> Echo ;
result.addMultiEcho(result.getEcho(getInput()));
result.addMultiEcho(result.getEcho(getInput() + 1));
// rel Foxtrot.MyAlfa? -> Alfa ;
result.getFoxtrot(getInput()).setMyAlfa(result);
// rel Alfa.MidiGolf <-> Golf.MidiAlfa? ;
result.setMidiGolf(result.getGolf(getInput()));
// // rel Alfa.MyHotel -> Hotel ;
// result.setMyHotel(getSenderSubTree().getHotel(getInput()));
// // rel Alfa.MultiHotel* -> Hotel ;
// result.addMultiHotel(getSenderSubTree().getHotel(getInput()));
// result.addMultiHotel(getSenderSubTree().getHotel((getInput() + 1)));
// rel Alfa.Myself -> Alfa ;
result.setMyself(result);
// rel Echo.MyFoxtrot -> Foxtrot ;
result.getEcho(getInput()).setMyFoxtrot(result.getFoxtrot(getInput()));
// // rel Foxtrot.MyHotel -> Hotel ;
// result.getFoxtrot(getInput()).setMyHotel(getSenderSubTree().getHotel(getInput()));
return result;
}
syn boolean ASTNode.isNameable() = false;
eq Nameable.isNameable() = true;
}
aspect NameResolution {
@Override
protected String Nameable.customID() {
return getClass().getSimpleName() + getID();
}
}
A ::= <Input:String> /<OutputOnA:String>/ B* ;
Root ::= A* SenderRoot* ReceiverRoot* ;
A ::= <Input:String> /<OutputOnA:String>/ B* C* /D/ Reading:D ;
B ::= /<OutputOnB:String>/ ;
C ::= /<OutputOnC:String>/ ;
D ::= <ID:String> ;
Nameable ::= <ID:int> ;
SenderRoot : Nameable ::= <Input:int> /Alfa/ Bravo* Charlie* Delta* SenderSubTree ;
SenderSubTree : Nameable ::= ;
ReceiverRoot : Nameable ::= Alfa Bravo* Charlie* Delta* ReceiverSubTree ;
ReceiverSubTree : Nameable ::= ;
Alfa : Nameable ::= Echo* Foxtrot* Golf* ;
Bravo : Nameable ;
Charlie : Nameable ;
Delta : Nameable ;
Echo : Nameable ;
Foxtrot : Nameable ;
Golf : Nameable ;
rel Alfa.MyBravo? -> Bravo ;
rel Alfa.MultiBravo* -> Bravo ;
// # relation into NTA not possible
//rel Charlie.MyAlfa -> Alfa ;
// # bidi relation from/into NTA probably not a good idea
rel Alfa.MidiDelta? <-> Delta.MidiAlfa? ;
rel Alfa.MyEcho -> Echo ;
rel Alfa.MultiEcho* -> Echo ;
rel Foxtrot.MyAlfa? -> Alfa ;
rel Alfa.MidiGolf <-> Golf.MidiAlfa? ;
rel Alfa.Myself -> Alfa ;
rel Echo.MyFoxtrot? -> Foxtrot ;
package de.tudresden.inf.st.mrc;
import de.tudresden.inf.st.mrc.ast.A;
import de.tudresden.inf.st.mrc.ast.B;
import de.tudresden.inf.st.jastadd.dumpAst.ast.Dumper;
import de.tudresden.inf.st.mrc.ast.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.nio.file.Paths;
import java.time.Instant;
import java.util.List;
import java.util.Scanner;
import java.util.function.Function;
import java.util.stream.Collectors;
import static java.util.concurrent.TimeUnit.SECONDS;
/**
* Minimal main.
*
* @author rschoene - Initial contribution
*/
@SuppressWarnings("CommentedOutCode")
public class MinimalMain {
public static void main(String[] args) throws IOException {
A a = new A();
// set some default value for input
a.setInput("");
B b1 = new B();
B b2 = new B();
a.addB(b1);
a.addB(b2);
// a.OutputOnA -> a.Input
a.addDependencyA(a);
// b1.OutputOnB -> a.Input
b1.addDependencyB(a);
// b2.OutputOnB -> a.Input
b2.addDependencyB(a);
a.connectInput("mqtt://localhost/topic/for/input");
a.connectOutputOnA("mqtt://localhost/a/out", true);
b1.connectOutputOnB("mqtt://localhost/b1/out", true);
b2.connectOutputOnB("mqtt://localhost/b2/out", false);
// while (true) {}
System.out.println("[Enter] to exit");
private static final Logger logger = LogManager.getLogger(MinimalMain.class);
private static final String TOPIC_FOR_INPUT = "topic/for/input";
private static final String TOPIC_URI_FOR_INPUT = "mqtt://localhost/" + TOPIC_FOR_INPUT;
private static MqttHandler publisher;
// static class MinimalReceiver implements Receiver {
// List<String> latestAttributes;
// Receiver oldReceiver;
//
// MinimalReceiver(Receiver oldReceiver) {
// this.oldReceiver = oldReceiver;
// reset();
// }
//
// void reset() {
// latestAttributes = new ArrayList<>();
// }
//
// @SuppressWarnings("rawtypes")
// @Override
// public void accept(ASTState.Trace.Event event, ASTNode node, String attribute, Object params, Object value) {
// oldReceiver.accept(event, node, attribute, params, value);
// logger.info("event: {}, node: {}, attribute: {}, params: {}, value: {},", event, node, attribute, params, value);
// latestAttributes.add(attribute);
// }
// }
// static MinimalReceiver receiver = null;
public static void main(String[] args) throws Exception {
boolean brokerReady;
try {
publisher = new MqttHandler("publisher").setHost("localhost");
brokerReady = publisher.waitUntilReady(2, SECONDS);
} catch (IOException e) {
brokerReady = false;
}
if (!brokerReady) {
logger.fatal("MQTT broker on localhost not available. Exiting!");
return;
}
publisher.publish("---", ("Start at " + Instant.now()).getBytes());
System.out.println("Choose scenario:");
System.out.println("1: Simple Tree Demo (Manually send MQTT message and observe output)");
System.out.println("2: Dependency Definition Demo (requires setup, primitive types)");
System.out.println("3: Automatic Incremental Demo (subtrees, with visualization of steps)");
Scanner scanner = new Scanner(System.in);
String input = scanner.nextLine();
switch (input) {
case "1":
mainSimpleTree();
break;
case "2":
mainIncremental();
break;
case "3":
mainRelationalTree();
break;
default:
System.err.println("Invalid input, please restart.");
}
}
private static void mainSimpleTree() throws IOException {
System.out.println("== Starting 'Simple Tree Demo' ==");
String inTopic = "mqtt://localhost/input";
String outTopic = "mqtt://localhost/output";
Root root = new Root();
root.ragconnectSetupMqttWaitUntilReady(2, SECONDS);
A treeA = new A();
root.addA(treeA);
treeA.setInput("initial");
B treeB = new B();
treeA.addB(treeB);
treeA.connectInput(inTopic);
treeB.connectOutputOnB(outTopic, true);
System.out.println("Send inputs to MQTT topic '" + inTopic + "' and observe output on '" + outTopic + "'");
System.out.println("Exit with [Enter]");
Scanner scanner = new Scanner(System.in);
scanner.nextLine();
}
private static void mainIncremental() throws Exception {
System.out.println("== Starting 'Dependency Definition Demo (requires setup, primitive types)' ==");
boolean success;
A normalA = addNewA(true);
// enableTracing(normalA);
B b1 = normalA.getB(0);
B b2 = normalA.getB(1);
Root root = new Root();
root.addA(normalA);
// dependency definitions
// // a.OutputOnA -> a.Input
// normalA.addDependencyA(normalA);
// // b1.OutputOnB -> a.Input
// b1.addDependencyB(normalA);
// // b2.OutputOnB -> a.Input
// b2.addDependencyB(normalA);
normalA.connectInput(TOPIC_URI_FOR_INPUT);
normalA.connectOutputOnA("mqtt://localhost/normalA/out", true);
b1.connectOutputOnB("mqtt://localhost/normalA/b1/out", true);
b2.connectOutputOnB("mqtt://localhost/normalA/b2/out", false);
A aWithNoDependency = addNewA(false);
// enableTracing(aWithNoDependency);
root.addA(aWithNoDependency);
aWithNoDependency.connectInput(TOPIC_URI_FOR_INPUT);
aWithNoDependency.connectOutputOnA("mqtt://localhost/aNoDep/out", true);
aWithNoDependency.getC(0).connectOutputOnC("mqtt://localhost/aNoDep/c1/out", true);
aWithNoDependency.getC(1).connectOutputOnC("mqtt://localhost/aNoDep/c2/out", false);
Dumper.read(normalA).dumpAsPNG(Paths.get("image.png"));
describedWait(1, "Publish 2");
publisher.publish(TOPIC_FOR_INPUT, "2".getBytes());
describedWait(1, "Publish 21");
publisher.publish(TOPIC_FOR_INPUT, "21".getBytes());
describedWait(1, "Publish 22 and 23");
publisher.publish(TOPIC_FOR_INPUT, "22".getBytes());
publisher.publish(TOPIC_FOR_INPUT, "23".getBytes());
describedWait(2, "Disconnect normalA");
success = normalA.disconnectInput(TOPIC_URI_FOR_INPUT);
logger.info("disconnect success: {}", success);
describedWait(2, "Publish 4");
publisher.publish(TOPIC_FOR_INPUT, "4".getBytes());
describedWait(1, "Disconnect aNoDep");
success = aWithNoDependency.disconnectInput(TOPIC_URI_FOR_INPUT);
logger.info("disconnect success: {}", success);
describedWait(1, "Publish 6");
publisher.publish(TOPIC_FOR_INPUT, "6".getBytes());
describedWait(1, "Connect aNormal again");
success = normalA.connectInput(TOPIC_URI_FOR_INPUT);
logger.info("connect success: {}", success);
describedWait(1, "Publish 8");
publisher.publish(TOPIC_FOR_INPUT, "8".getBytes());
describedWait(1, "Publish 81");
publisher.publish(TOPIC_FOR_INPUT, "81".getBytes());
describedWait(1, "Connect aNoDep again");
success = aWithNoDependency.connectInput(TOPIC_URI_FOR_INPUT);
logger.info("connect success: {}", success);
describedWait(1, "Publish 10");
publisher.publish(TOPIC_FOR_INPUT, "10".getBytes());
describedWait(1, "Publish 101");
publisher.publish(TOPIC_FOR_INPUT, "101".getBytes());
describedWait(0, "End");
}
private static void describedWait(long seconds, String description) throws InterruptedException {
SECONDS.sleep(seconds);
logger.info("--- {} ---", description);
publisher.publish("---", description.getBytes());
}
private static A addNewA(boolean useB) {
A result = new A();
result.setInput("1");
if (useB) {
B b1 = new B();
B b2 = new B();
result.addB(b1);
result.addB(b2);
} else {
C c1 = new C();
C c2 = new C();
result.addC(c1);
result.addC(c2);
}
return result;
}
private static void mainRelationalTree() throws IOException, InterruptedException {
System.out.println("== Starting 'Automatic Incremental Demo (subtrees, with visualization of steps)' ==");
System.out.println("Find the generated images in the root of this repository");
final String mqttUriString = "mqtt://localhost/alfa";
Root root1ForSender = new Root();
root1ForSender.ragconnectSetupMqttWaitUntilReady(2, SECONDS);
SenderRoot senderRoot = createSenderRoot();
root1ForSender.addSenderRoot(senderRoot);
senderRoot.connectAlfa(mqttUriString, false);
Root root2ForReceiver = new Root();
root2ForReceiver.ragconnectSetupMqttWaitUntilReady(2, SECONDS);
ReceiverRoot receiverRoot = createReceiverRoot();
root2ForReceiver.addReceiverRoot(receiverRoot);
receiverRoot.connectAlfa(mqttUriString);
Dumper.read(senderRoot).includeNonterminalAttributes("Alfa").dumpAsPNG(Paths.get("00-initial-sender.png"));
Dumper.read(receiverRoot).dumpAsPNG(Paths.get("00-initial-receiver.png"));
senderRoot.setInput(1);
describedWait(1, "after setting input to 1");
printAlfa(true, senderRoot, receiverRoot);
printAlfa(false, senderRoot, receiverRoot);
Dumper.read(senderRoot).includeNonterminalAttributes("Alfa").dumpAsPNG(Paths.get("01-after-1-sender.png"));
Dumper.read(receiverRoot).dumpAsPNG(Paths.get("01-after-1-receiver.png"));
printAlfa(true, senderRoot, receiverRoot);
printAlfa(false, senderRoot, receiverRoot);
senderRoot.setInput(2);
describedWait(1, "after setting input to 2");
printAlfa(true, senderRoot, receiverRoot);
printAlfa(false, senderRoot, receiverRoot);
Dumper.read(senderRoot).includeNonterminalAttributes("Alfa").dumpAsPNG(Paths.get("02-after-2-sender.png"));
Dumper.read(receiverRoot).dumpAsPNG(Paths.get("02-after-2-receiver.png"));
printAlfa(true, senderRoot, receiverRoot);
printAlfa(false, senderRoot, receiverRoot);
}
private static SenderRoot createSenderRoot() {
SenderRoot result = new SenderRoot();
SenderSubTree subTree = new SenderSubTree();
result.setSenderSubTree(subTree);
templateCreation(result::addBravo, result::addCharlie, result::addDelta);
return result;
}
private static ReceiverRoot createReceiverRoot() {
ReceiverRoot result = new ReceiverRoot();
ReceiverSubTree subTree = new ReceiverSubTree();
result.setReceiverSubTree(subTree);
templateCreation(result::addBravo, result::addCharlie, result::addDelta);
return result;
}
private static void templateCreation(AddBravo addBravo, AddCharlie addCharlie, AddDelta addDelta) {
for (int i = 0; i < 4; i++) {
addBravo.accept(new Bravo(i));
addCharlie.accept(new Charlie(i));
addDelta.accept(new Delta(i));
}
}
interface AddBravo { void accept(Bravo b); }
interface AddCharlie { void accept(Charlie b); }
interface AddDelta { void accept(Delta b); }
private static void printAlfa(boolean isSender, SenderRoot senderRoot, ReceiverRoot receiverRoot) {
final String name;
final String tick;
final Alfa alfa;
if (isSender) {
name = "sender";
tick = " >-";
alfa = senderRoot.getAlfa();
} else {
name = "receiver";
tick = " <-";
alfa = receiverRoot.getAlfa();
}
// also dump AST
StringBuilder sb = new StringBuilder();
printNode(alfa.getParent(), "", sb);
logger.info("\n{}", sb.toString());
logger.info("Checking Alfa\n" +
"{}: {} in {}\n" +
tick + " Myself: {}\n" +
tick + " MyEcho: {}\n" +
tick + " EchoList.MyFoxtrot: {}\n" +
tick + " MultiEchoList: {}\n" +
tick + " FoxtrotList.MyAlfa: {}\n" +
tick + " FoxtrotList.MyHotel: {}\n" +
tick + " MidiGolf: {} (MidiGolf.getMidiAlfa(): {})\n" +
tick + " GolfList (id -> alfa.id): {}\n" +
"{}", // just to make swapping of params easier
name, alfa, alfa.getParent(),
nameAndHash(alfa.getMyself()),
nameAndHash(alfa.getMyEcho()),
printOptionalList(alfa.getEchoList(), Echo::hasMyFoxtrot, Echo::getMyFoxtrot),
printNameableList(alfa.getMultiEchoList()),
printOptionalList(alfa.getFoxtrotList(), Foxtrot::hasMyAlfa, Foxtrot::getMyAlfa),
nameAndHash(alfa.getMidiGolf()), nameAndHash(alfa.getMidiGolf().getMidiAlfa()),
printOptionalList(alfa.getGolfList(), Golf::hasMidiAlfa, Golf::getMidiAlfa),
""
);
}
private static String printNameableList(List<? extends Nameable> nameableList) {
return nameableList.stream().map(MinimalMain::nameAndHash).collect(Collectors.joining(",", "[", "]"));
}
private static <T extends Nameable> String printOptionalList(Iterable<T> tIterable, Function<T, Boolean> hasChild, Function<T, Nameable> getChild) {
StringBuilder sb = new StringBuilder();
for (T t : tIterable) {
sb.append(nameAndHash(t))
.append(" -> ")
.append(hasChild.apply(t) ? nameAndHash(getChild.apply(t)) : "/")
.append(", ");
}
return sb.toString();
}
private static String nameAndHash(Nameable nameable) {
return nameable.getID() + " (@" + Integer.toHexString(nameable.hashCode()) + ")";
}
private static void printNode(ASTNode<?> node, String indent, StringBuilder sb) {
if (node.isNameable()) {
sb.append(indent)
.append("- ")
.append(node.getClass().getSimpleName())
.append(nameAndHash((Nameable) node))
.append("\n");
}
for (ASTNode<?> child : node.astChildren()) {
printNode(child, node instanceof JastAddList ? indent : indent + " |", sb);
}
}
// private static void enableTracing(ASTNode<?> node) {
// if (node.trace().getReceiver() != null && node.trace().getReceiver() instanceof MinimalReceiver) {
// System.out.println("*** receiver already set up ***");
// } else {
// System.out.println("*** activate receiver ***");
// receiver = new MinimalReceiver(node.trace().getReceiver());
// node.trace().setReceiver(receiver);
// }
// }
}
......@@ -6,7 +6,7 @@
</Console>
</Appenders>
<Loggers>
<Root level="info">
<Root level="debug">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
......