Select Git revision
MinimalMain.java

René Schöne authored
- add switch to launch the three demos - switch to mkdocs for pages - add documentation for all three demos
MinimalMain.java 12.84 KiB
package de.tudresden.inf.st.mrc;
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 {
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);
// }
// }
}