Files
spring-state-machine-renderer/src/TODO.md
2025-07-15 00:15:25 +02:00

5.0 KiB

  1. extract state machines from this as well
  2. extract from all possible formats (ask chatgpt)

import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.config.builders.StateMachineBuilder;

import java.util.EnumSet;

public class DynamicStateMachineExample {

    public enum States {
        DRAFT, REVIEW, APPROVED
    }

    public enum Events {
        SUBMIT, APPROVE
    }

    public static StateMachine<States, Events> buildStateMachine() throws Exception {
        StateMachineBuilder.Builder<States, Events> builder = StateMachineBuilder.builder();

        builder.configureStates()
            .withStates()
                .initial(States.DRAFT)
                .states(EnumSet.allOf(States.class));

        builder.configureTransitions()
            .withExternal()
                .source(States.DRAFT).target(States.REVIEW).event(Events.SUBMIT)
            .and()
            .withExternal()
                .source(States.REVIEW).target(States.APPROVED).event(Events.APPROVE);

        return builder.build();
    }

    public static void main(String[] args) throws Exception {
        StateMachine<States, Events> sm = buildStateMachine();

        sm.start();
        System.out.println("Current State: " + sm.getState().getId());

        sm.sendEvent(Events.SUBMIT);
        System.out.println("After SUBMIT: " + sm.getState().getId());

        sm.sendEvent(Events.APPROVE);
        System.out.println("After APPROVE: " + sm.getState().getId());
    }
}

  1. define how java function can be implemented 1.2. for this analyse bytecode manipulation such as project lombok

  2. get a diagram

  3. get a diagram with slicing, for example, slice by setValue on an ENUM field -> identify saga

  4. make a list of all messages on message queues, how they're remapped and then who receives them

NOTE


import com.github.javaparser.StaticJavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.expr.MethodCallExpr;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;

import java.io.File;
import java.io.FileInputStream;
import java.util.*;

public class MethodCallGraphGenerator {

    static class MethodNode {
        String className;
        String methodName;

        public MethodNode(String className, String methodName) {
            this.className = className;
            this.methodName = methodName;
        }

        @Override
        public String toString() {
            return className + "." + methodName;
        }

        @Override
        public int hashCode() {
            return Objects.hash(className, methodName);
        }

        @Override
        public boolean equals(Object obj) {
            if (obj instanceof MethodNode other) {
                return this.className.equals(other.className) && this.methodName.equals(other.methodName);
            }
            return false;
        }
    }

    static Map<MethodNode, Set<MethodNode>> callGraph = new HashMap<>();

    public static void main(String[] args) throws Exception {
        File sourceDir = new File("src");  // Change to your Java source directory
        parseDirectory(sourceDir);

        generateDotFile("callgraph.dot");
        System.out.println("Call graph generated to callgraph.dot");
    }

    private static void parseDirectory(File dir) throws Exception {
        for (File file : Objects.requireNonNull(dir.listFiles())) {
            if (file.isDirectory()) {
                parseDirectory(file);
            } else if (file.getName().endsWith(".java")) {
                parseFile(file);
            }
        }
    }

    private static void parseFile(File file) throws Exception {
        CompilationUnit cu = StaticJavaParser.parse(new FileInputStream(file));
        cu.findAll(MethodDeclaration.class).forEach(method -> {
            String className = cu.getPrimaryTypeName().orElse("Unknown");
            MethodNode caller = new MethodNode(className, method.getNameAsString());

            callGraph.putIfAbsent(caller, new HashSet<>());

            method.accept(new VoidVisitorAdapter<Void>() {
                @Override
                public void visit(MethodCallExpr call, Void arg) {
                    super.visit(call, arg);
                    String calleeName = call.getNameAsString();
                    MethodNode callee = new MethodNode("Unknown", calleeName);  // Could be refined with better context
                    callGraph.get(caller).add(callee);
                }
            }, null);
        });
    }

    private static void generateDotFile(String filename) throws Exception {
        StringBuilder sb = new StringBuilder();
        sb.append("digraph G {\n");
        for (var caller : callGraph.keySet()) {
            for (var callee : callGraph.get(caller)) {
                sb.append("  \"").append(caller).append("\" -> \"").append(callee).append("\";\n");
            }
        }
        sb.append("}");
        java.nio.file.Files.writeString(new File(filename).toPath(), sb.toString());
    }
}