Skip to content
Snippets Groups Projects
Select Git revision
  • 44b89700ecc3ed305106d50994956313a80cfbb1
  • master default protected
  • feature/ros-example
3 results

MinimalMain.java

Blame
  • rschoene's avatar
    René Schöne authored
    - add switch to launch the three demos
    - switch to mkdocs for pages
    - add documentation for all three demos
    44b89700
    History
    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);
    //    }
    //  }
    }