package change
This commit is contained in:
@@ -4,7 +4,7 @@ plugins {
|
|||||||
id 'io.spring.dependency-management' version '1.1.7'
|
id 'io.spring.dependency-management' version '1.1.7'
|
||||||
}
|
}
|
||||||
|
|
||||||
group = 'com.example'
|
group = 'click.kamil'
|
||||||
version = '0.0.1-SNAPSHOT'
|
version = '0.0.1-SNAPSHOT'
|
||||||
|
|
||||||
java {
|
java {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.example.statemachinedemo;
|
package click.kamil.springstatemachineexporter;
|
||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
package com.example.statemachinedemo;
|
package click.kamil.springstatemachineexporter.ast;
|
||||||
|
|
||||||
import com.example.statemachinedemo.app.AstTransitionParser;
|
import click.kamil.springstatemachineexporter.ast.app.AstTransitionParser;
|
||||||
import com.example.statemachinedemo.app.StateMachineStateConfigurationMethodFinder;
|
import click.kamil.springstatemachineexporter.ast.app.StateMachineStateConfigurationMethodFinder;
|
||||||
import com.example.statemachinedemo.app.StateMachineTransitionConfigurationMethodFinder;
|
import click.kamil.springstatemachineexporter.ast.app.StateMachineTransitionConfigurationMethodFinder;
|
||||||
import com.example.statemachinedemo.app.TransitionStateUtils;
|
import click.kamil.springstatemachineexporter.ast.app.TransitionStateUtils;
|
||||||
import com.example.statemachinedemo.app.domain.Transition;
|
import click.kamil.springstatemachineexporter.ast.app.domain.Transition;
|
||||||
import com.example.statemachinedemo.common.FileUtils;
|
import click.kamil.springstatemachineexporter.ast.common.FileUtils;
|
||||||
import com.example.statemachinedemo.in.AstFileFinder;
|
import click.kamil.springstatemachineexporter.ast.in.AstFileFinder;
|
||||||
import com.example.statemachinedemo.out.Dot;
|
import click.kamil.springstatemachineexporter.ast.out.Dot;
|
||||||
import com.example.statemachinedemo.out.PlantUml;
|
import click.kamil.springstatemachineexporter.ast.out.PlantUml;
|
||||||
import com.example.statemachinedemo.out.Scxml;
|
import click.kamil.springstatemachineexporter.ast.out.Scxml;
|
||||||
import com.example.statemachinedemo.out.StateMachineExporter;
|
import click.kamil.springstatemachineexporter.ast.out.StateMachineExporter;
|
||||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||||
import org.eclipse.jdt.core.dom.MethodDeclaration;
|
import org.eclipse.jdt.core.dom.MethodDeclaration;
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.example.statemachinedemo.app;
|
package click.kamil.springstatemachineexporter.ast.app;
|
||||||
|
|
||||||
import com.example.statemachinedemo.app.domain.Transition;
|
import click.kamil.springstatemachineexporter.ast.app.domain.Transition;
|
||||||
import org.eclipse.jdt.core.dom.*;
|
import org.eclipse.jdt.core.dom.*;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.example.statemachinedemo.app;
|
package click.kamil.springstatemachineexporter.ast.app;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.eclipse.jdt.core.dom.*;
|
import org.eclipse.jdt.core.dom.*;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.example.statemachinedemo.app;
|
package click.kamil.springstatemachineexporter.ast.app;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.eclipse.jdt.core.dom.*;
|
import org.eclipse.jdt.core.dom.*;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.example.statemachinedemo.app;
|
package click.kamil.springstatemachineexporter.ast.app;
|
||||||
|
|
||||||
import com.example.statemachinedemo.app.domain.Transition;
|
import click.kamil.springstatemachineexporter.ast.app.domain.Transition;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.example.statemachinedemo.app.domain;
|
package click.kamil.springstatemachineexporter.ast.app.domain;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.example.statemachinedemo.common;
|
package click.kamil.springstatemachineexporter.ast.common;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.example.statemachinedemo.in;
|
package click.kamil.springstatemachineexporter.ast.in;
|
||||||
|
|
||||||
import org.eclipse.jdt.core.dom.*;
|
import org.eclipse.jdt.core.dom.*;
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.example.statemachinedemo.out;
|
package click.kamil.springstatemachineexporter.ast.out;
|
||||||
|
|
||||||
import com.example.statemachinedemo.app.domain.Transition;
|
import click.kamil.springstatemachineexporter.ast.app.domain.Transition;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.example.statemachinedemo.out;
|
package click.kamil.springstatemachineexporter.ast.out;
|
||||||
|
|
||||||
import com.example.statemachinedemo.app.domain.Transition;
|
import click.kamil.springstatemachineexporter.ast.app.domain.Transition;
|
||||||
import io.micrometer.common.util.StringUtils;
|
import io.micrometer.common.util.StringUtils;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -8,6 +8,20 @@ import java.util.stream.Collectors;
|
|||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
public class PlantUml implements StateMachineExporter {
|
public class PlantUml implements StateMachineExporter {
|
||||||
|
// Color palette for choices
|
||||||
|
private final List<String> choiceColors = List.of("FF6347", "4682B4", "32CD32", "FFD700", "6A5ACD", "FF69B4");
|
||||||
|
private String getColor(Transition t, String source, Map<String, String> choiceStateColorMap) {
|
||||||
|
return switch (t.getType()) {
|
||||||
|
case "withChoice" -> choiceStateColorMap.getOrDefault(source, "000000");
|
||||||
|
case "withExternal" -> "1E90FF";
|
||||||
|
case "withInternal" -> "32CD32";
|
||||||
|
case "withLocal" -> "FFA500";
|
||||||
|
case "withJunction" -> "FF69B4";
|
||||||
|
case "withJoin" -> "8A2BE2";
|
||||||
|
case "withFork" -> "20B2AA";
|
||||||
|
default -> "000000";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String export(List<Transition> transitions,
|
public String export(List<Transition> transitions,
|
||||||
@@ -44,9 +58,6 @@ public class PlantUml implements StateMachineExporter {
|
|||||||
}
|
}
|
||||||
sb.append("\n");
|
sb.append("\n");
|
||||||
|
|
||||||
// Color palette for choices
|
|
||||||
List<String> choiceColors = List.of("FF6347", "4682B4", "32CD32", "FFD700", "6A5ACD", "FF69B4");
|
|
||||||
|
|
||||||
// Assign color to each choice state
|
// Assign color to each choice state
|
||||||
Map<String, String> choiceStateColorMap = new HashMap<>();
|
Map<String, String> choiceStateColorMap = new HashMap<>();
|
||||||
int colorIndex = 0;
|
int colorIndex = 0;
|
||||||
@@ -168,17 +179,4 @@ public class PlantUml implements StateMachineExporter {
|
|||||||
|
|
||||||
return String.join(" ", parts);
|
return String.join(" ", parts);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getColor(Transition t, String source, Map<String, String> choiceStateColorMap) {
|
|
||||||
return switch (t.getType()) {
|
|
||||||
case "withChoice" -> choiceStateColorMap.getOrDefault(source, "000000");
|
|
||||||
case "withExternal" -> "1E90FF";
|
|
||||||
case "withInternal" -> "32CD32";
|
|
||||||
case "withLocal" -> "FFA500";
|
|
||||||
case "withJunction" -> "FF69B4";
|
|
||||||
case "withJoin" -> "8A2BE2";
|
|
||||||
case "withFork" -> "20B2AA";
|
|
||||||
default -> "000000";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.example.statemachinedemo.out;
|
package click.kamil.springstatemachineexporter.ast.out;
|
||||||
|
|
||||||
import com.example.statemachinedemo.app.domain.Transition;
|
import click.kamil.springstatemachineexporter.ast.app.domain.Transition;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.example.statemachinedemo.out;
|
package click.kamil.springstatemachineexporter.ast.out;
|
||||||
|
|
||||||
import com.example.statemachinedemo.app.domain.Transition;
|
import click.kamil.springstatemachineexporter.ast.app.domain.Transition;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -0,0 +1,180 @@
|
|||||||
|
package click.kamil.springstatemachineexporter.springbased;
|
||||||
|
|
||||||
|
import click.kamil.springstatemachineexporter.statemachine.OrderEvents;
|
||||||
|
import click.kamil.springstatemachineexporter.statemachine.OrderStates;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.boot.ApplicationArguments;
|
||||||
|
import org.springframework.boot.ApplicationRunner;
|
||||||
|
import org.springframework.statemachine.StateMachine;
|
||||||
|
import org.springframework.statemachine.config.StateMachineFactory;
|
||||||
|
import org.springframework.statemachine.state.PseudoStateKind;
|
||||||
|
import org.springframework.statemachine.state.State;
|
||||||
|
import org.springframework.statemachine.transition.Transition;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.w3c.dom.Element;
|
||||||
|
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
import javax.xml.transform.Transformer;
|
||||||
|
import javax.xml.transform.TransformerFactory;
|
||||||
|
import javax.xml.transform.dom.DOMSource;
|
||||||
|
import javax.xml.transform.stream.StreamResult;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
|
||||||
|
public class SpringExporter {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
class Runner implements ApplicationRunner {
|
||||||
|
|
||||||
|
private final DotExporter dotExporter;
|
||||||
|
private final PlantUmlExporter plantUmlExporter;
|
||||||
|
private final ScxmlExporter scxmlExporter;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(ApplicationArguments args) throws Exception {
|
||||||
|
dotExporter.export("stateMachine.dot");
|
||||||
|
plantUmlExporter.export("stateMachine.uml.dot");
|
||||||
|
scxmlExporter.export("stateMachine.scxml.xml");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class BaseExporter {
|
||||||
|
@Qualifier("simpleEnumStateMachineFactory")
|
||||||
|
protected final StateMachineFactory<OrderStates, OrderEvents> factory;
|
||||||
|
|
||||||
|
protected BaseExporter(StateMachineFactory<OrderStates, OrderEvents> factory) {
|
||||||
|
this.factory = factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract void export(String name) throws Exception;
|
||||||
|
|
||||||
|
protected StateMachine<OrderStates, OrderEvents> createStateMachine() {
|
||||||
|
return factory.getStateMachine("order");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
|
class DotExporter extends BaseExporter {
|
||||||
|
|
||||||
|
public DotExporter(@Qualifier("simpleEnumStateMachineFactory") StateMachineFactory<OrderStates, OrderEvents> factory) {
|
||||||
|
super(factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void export(String filename) throws Exception {
|
||||||
|
try (PrintWriter writer = new PrintWriter(filename)) {
|
||||||
|
StateMachine<OrderStates, OrderEvents> machine = createStateMachine();
|
||||||
|
writer.println("digraph stateMachine {");
|
||||||
|
|
||||||
|
for (State<OrderStates, OrderEvents> state : machine.getStates()) {
|
||||||
|
writer.printf(" %s;%n", state.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Transition<OrderStates, OrderEvents> transition : machine.getTransitions()) {
|
||||||
|
if (transition.getSource() != null && transition.getTarget() != null) {
|
||||||
|
writer.printf(" %s -> %s [label=\"%s\"];%n",
|
||||||
|
transition.getSource().getId(),
|
||||||
|
transition.getTarget().getId(),
|
||||||
|
transition.getTrigger() != null ? transition.getTrigger().getEvent() : "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.println("}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
|
class PlantUmlExporter extends BaseExporter {
|
||||||
|
|
||||||
|
public PlantUmlExporter(@Qualifier("simpleEnumStateMachineFactory") StateMachineFactory<OrderStates, OrderEvents> factory) {
|
||||||
|
super(factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void export(String filename) throws Exception {
|
||||||
|
try (PrintWriter writer = new PrintWriter(filename)) {
|
||||||
|
StateMachine<OrderStates, OrderEvents> machine = createStateMachine();
|
||||||
|
writer.println("@startuml");
|
||||||
|
writer.println("[*] --> " + machine.getInitialState().getId());
|
||||||
|
|
||||||
|
for (Transition<OrderStates, OrderEvents> transition : machine.getTransitions()) {
|
||||||
|
if (transition.getSource() != null && transition.getTarget() != null) {
|
||||||
|
String source = transition.getSource().getId().toString();
|
||||||
|
String target = transition.getTarget().getId().toString();
|
||||||
|
String label = "";
|
||||||
|
|
||||||
|
if (transition.getTrigger() != null && transition.getTrigger().getEvent() != null) {
|
||||||
|
label += transition.getTrigger().getEvent().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transition.getGuard() != null) {
|
||||||
|
if (!label.isEmpty()) label += " ";
|
||||||
|
label += "[guard]";
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.printf("%s --> %s%s%n", source, target, !label.isEmpty() ? " : " + label : "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (State<OrderStates, OrderEvents> state : machine.getStates()) {
|
||||||
|
if (state.getPseudoState() != null && state.getPseudoState().getKind() == PseudoStateKind.END) {
|
||||||
|
writer.printf("%s --> [*]%n", state.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.println("@enduml");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
|
class ScxmlExporter extends BaseExporter {
|
||||||
|
|
||||||
|
public ScxmlExporter(@Qualifier("simpleEnumStateMachineFactory") StateMachineFactory<OrderStates, OrderEvents> factory) {
|
||||||
|
super(factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void export(String filename) throws Exception {
|
||||||
|
StateMachine<OrderStates, OrderEvents> machine = createStateMachine();
|
||||||
|
|
||||||
|
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
|
||||||
|
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
|
||||||
|
Document doc = dBuilder.newDocument();
|
||||||
|
|
||||||
|
Element scxml = doc.createElement("scxml");
|
||||||
|
scxml.setAttribute("version", "1.0");
|
||||||
|
doc.appendChild(scxml);
|
||||||
|
|
||||||
|
Element statesElement = doc.createElement("states");
|
||||||
|
scxml.appendChild(statesElement);
|
||||||
|
|
||||||
|
for (State<OrderStates, OrderEvents> state : machine.getStates()) {
|
||||||
|
Element stateEl = doc.createElement("state");
|
||||||
|
stateEl.setAttribute("id", state.getId().toString());
|
||||||
|
statesElement.appendChild(stateEl);
|
||||||
|
}
|
||||||
|
|
||||||
|
Element transitionsElement = doc.createElement("transitions");
|
||||||
|
scxml.appendChild(transitionsElement);
|
||||||
|
|
||||||
|
for (Transition<OrderStates, OrderEvents> transition : machine.getTransitions()) {
|
||||||
|
Element t = doc.createElement("transition");
|
||||||
|
t.setAttribute("from", transition.getSource().getId().toString());
|
||||||
|
t.setAttribute("to", transition.getTarget().getId().toString());
|
||||||
|
t.setAttribute("event", String.valueOf(transition.getTrigger()));
|
||||||
|
transitionsElement.appendChild(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
Transformer transformer = TransformerFactory.newInstance().newTransformer();
|
||||||
|
transformer.transform(new DOMSource(doc), new StreamResult(new File(filename)));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.example.statemachinedemo.z.statemachine;
|
package click.kamil.springstatemachineexporter.statemachine;
|
||||||
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.statemachine.action.Action;
|
import org.springframework.statemachine.action.Action;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.example.statemachinedemo.z.statemachine;
|
package click.kamil.springstatemachineexporter.statemachine;
|
||||||
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.statemachine.action.Action;
|
import org.springframework.statemachine.action.Action;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.example.statemachinedemo.z.statemachine;
|
package click.kamil.springstatemachineexporter.statemachine;
|
||||||
|
|
||||||
public enum OrderEvents {
|
public enum OrderEvents {
|
||||||
FULFILL, PAY, CANCEL,
|
FULFILL, PAY, CANCEL,
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.example.statemachinedemo.z.statemachine;
|
package click.kamil.springstatemachineexporter.statemachine;
|
||||||
|
|
||||||
public enum OrderStates {
|
public enum OrderStates {
|
||||||
SUBMITTED, PAID, FULFILLED, CANCELED
|
SUBMITTED, PAID, FULFILLED, CANCELED
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.example.statemachinedemo.z.statemachine;
|
package click.kamil.springstatemachineexporter.statemachine;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
@@ -1,224 +0,0 @@
|
|||||||
package com.example.statemachinedemo.z.notgoodspringbased;
|
|
||||||
|
|
||||||
import com.example.statemachinedemo.z.statemachine.OrderEvents;
|
|
||||||
import com.example.statemachinedemo.z.statemachine.OrderStates;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
|
||||||
import org.springframework.boot.ApplicationArguments;
|
|
||||||
import org.springframework.boot.ApplicationRunner;
|
|
||||||
import org.springframework.statemachine.StateMachine;
|
|
||||||
import org.springframework.statemachine.config.StateMachineFactory;
|
|
||||||
import org.springframework.statemachine.state.PseudoStateKind;
|
|
||||||
import org.springframework.statemachine.state.State;
|
|
||||||
import org.springframework.statemachine.transition.Transition;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.w3c.dom.Document;
|
|
||||||
import org.w3c.dom.Element;
|
|
||||||
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
|
||||||
import javax.xml.transform.Transformer;
|
|
||||||
import javax.xml.transform.TransformerFactory;
|
|
||||||
import javax.xml.transform.dom.DOMSource;
|
|
||||||
import javax.xml.transform.stream.StreamResult;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
public class SpringExporter {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Component
|
|
||||||
@Slf4j
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
class Runner implements ApplicationRunner {
|
|
||||||
// private final StateMachineFactory<OrderStates, OrderEvents> simpleEnumStateMachineConfiguration;
|
|
||||||
// @Override
|
|
||||||
// public void run(ApplicationArguments args) throws Exception {
|
|
||||||
// StateMachine<OrderStates, OrderEvents> stateMachine = factory.getStateMachine("order");
|
|
||||||
// stateMachine.start();
|
|
||||||
// log.info("Current state is {}", stateMachine.getState().getId());
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
private final Config1 c;
|
|
||||||
private final Config2 c2;
|
|
||||||
private final Config3 c3;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run(ApplicationArguments args) throws Exception {
|
|
||||||
c.a();
|
|
||||||
c2.a();
|
|
||||||
c3.exportToSCXML();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class StateMachineDotExporter {
|
|
||||||
public static <S, E> void export(StateMachine<S, E> stateMachine, PrintWriter writer) {
|
|
||||||
writer.println("digraph stateMachine {");
|
|
||||||
|
|
||||||
for (State<S, E> state : stateMachine.getStates()) {
|
|
||||||
writer.printf(" %s;%n", state.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Transition<S, E> transition : stateMachine.getTransitions()) {
|
|
||||||
if (transition.getSource() != null && transition.getTarget() != null) {
|
|
||||||
writer.printf(" %s -> %s [label=\"%s\"];%n",
|
|
||||||
transition.getSource().getId(),
|
|
||||||
transition.getTarget().getId(),
|
|
||||||
transition.getTrigger() != null ? transition.getTrigger().getEvent() : "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.println("}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class StateMachinePlantUMLExporter {
|
|
||||||
|
|
||||||
public static <S, E> void export(StateMachine<S, E> stateMachine, PrintWriter writer) {
|
|
||||||
writer.println("@startuml");
|
|
||||||
|
|
||||||
// Initial state
|
|
||||||
writer.println("[*] --> " + stateMachine.getInitialState().getId());
|
|
||||||
|
|
||||||
for (Transition<S, E> transition : stateMachine.getTransitions()) {
|
|
||||||
if (transition.getSource() != null && transition.getTarget() != null) {
|
|
||||||
String source = transition.getSource().getId().toString();
|
|
||||||
String target = transition.getTarget().getId().toString();
|
|
||||||
|
|
||||||
String label = "";
|
|
||||||
|
|
||||||
if (transition.getTrigger() != null && transition.getTrigger().getEvent() != null) {
|
|
||||||
label += transition.getTrigger().getEvent().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (transition.getGuard() != null) {
|
|
||||||
// If event is empty but there’s a guard, still label it meaningfully
|
|
||||||
if (!label.isEmpty()) {
|
|
||||||
label += " ";
|
|
||||||
}
|
|
||||||
label += "[guard]";
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there's no label at all, don't include ":"
|
|
||||||
if (!label.isEmpty()) {
|
|
||||||
writer.printf("%s --> %s : %s%n", source, target, label);
|
|
||||||
} else {
|
|
||||||
writer.printf("%s --> %s%n", source, target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// End states
|
|
||||||
for (State<S, E> state : stateMachine.getStates()) {
|
|
||||||
if (state.getPseudoState() != null &&
|
|
||||||
state.getPseudoState().getKind() == PseudoStateKind.END) {
|
|
||||||
writer.printf("%s --> [*]%n", state.getId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.println("@enduml");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
class Config1 {
|
|
||||||
@Qualifier("simpleEnumStateMachineFactory")
|
|
||||||
private final StateMachineFactory<OrderStates, OrderEvents> simpleEnumStateMachineConfiguration;
|
|
||||||
public void a() throws FileNotFoundException {
|
|
||||||
StateMachine<OrderStates, OrderEvents> stateMachine = simpleEnumStateMachineConfiguration.getStateMachine("order");
|
|
||||||
|
|
||||||
StateMachineDotExporter exporter = new StateMachineDotExporter();
|
|
||||||
try (PrintWriter out = new PrintWriter("statemachine.dot")) {
|
|
||||||
StateMachineDotExporter.export(stateMachine, out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
class Config2 {
|
|
||||||
@Qualifier("simpleEnumStateMachineFactory")
|
|
||||||
private final StateMachineFactory<OrderStates, OrderEvents> simpleEnumStateMachineConfiguration;
|
|
||||||
public void a() throws FileNotFoundException {
|
|
||||||
StateMachine<OrderStates, OrderEvents> stateMachine = simpleEnumStateMachineConfiguration.getStateMachine("order");
|
|
||||||
|
|
||||||
try (PrintWriter out = new PrintWriter("statemachine.uml.dot")) {
|
|
||||||
StateMachinePlantUMLExporter.export(stateMachine, out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@Component
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
class Config3 {
|
|
||||||
@Qualifier("simpleEnumStateMachineFactory")
|
|
||||||
private final StateMachineFactory<OrderStates, OrderEvents> simpleEnumStateMachineConfiguration;
|
|
||||||
public void exportToSCXML() throws Exception {
|
|
||||||
StateMachine<OrderStates, OrderEvents> stateMachine = simpleEnumStateMachineConfiguration.getStateMachine("order");
|
|
||||||
|
|
||||||
SCXMLExporter exporter = new SCXMLExporter();
|
|
||||||
File file = new File("statemachine.scxml.xml");
|
|
||||||
exporter.exportToSCXML(stateMachine);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Component
|
|
||||||
class SCXMLExporter {
|
|
||||||
|
|
||||||
// This method assumes you already have a state machine
|
|
||||||
public <S, E> void exportToSCXML(StateMachine<S, E> stateMachine) throws Exception {
|
|
||||||
// Create a document to represent the SCXML structure
|
|
||||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
|
||||||
DocumentBuilder builder = factory.newDocumentBuilder();
|
|
||||||
Document doc = builder.newDocument();
|
|
||||||
|
|
||||||
// Root SCXML element
|
|
||||||
Element scxmlElement = doc.createElement("scxml");
|
|
||||||
scxmlElement.setAttribute("version", "1.0");
|
|
||||||
doc.appendChild(scxmlElement);
|
|
||||||
|
|
||||||
// Define the states
|
|
||||||
Element statesElement = doc.createElement("states");
|
|
||||||
scxmlElement.appendChild(statesElement);
|
|
||||||
|
|
||||||
// Iterate over the states of the state machine
|
|
||||||
Collection<State<S, E>> states = stateMachine.getStates();
|
|
||||||
for (State<S, E> state : states) {
|
|
||||||
Element stateElement = doc.createElement("state");
|
|
||||||
stateElement.setAttribute("id", state.getId().toString());
|
|
||||||
statesElement.appendChild(stateElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Define the transitions
|
|
||||||
Element transitionsElement = doc.createElement("transitions");
|
|
||||||
scxmlElement.appendChild(transitionsElement);
|
|
||||||
|
|
||||||
Collection<org.springframework.statemachine.transition.Transition<S, E>> transitions = stateMachine.getTransitions();
|
|
||||||
for (Transition<S, E> transition : transitions) {
|
|
||||||
Element transitionElement = doc.createElement("transition");
|
|
||||||
transitionElement.setAttribute("from", transition.getSource().getId().toString());
|
|
||||||
transitionElement.setAttribute("to", transition.getTarget().getId().toString());
|
|
||||||
transitionElement.setAttribute("event", String.valueOf(transition.getTrigger()));
|
|
||||||
transitionsElement.appendChild(transitionElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write to file
|
|
||||||
File file = new File("stateMachine.scxml");
|
|
||||||
saveDocumentToFile(doc, file);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void saveDocumentToFile(Document doc, File file) throws Exception {
|
|
||||||
// Serialize the document to a file (you can use your preferred XML writer)
|
|
||||||
Transformer transformer = TransformerFactory.newInstance().newTransformer();
|
|
||||||
StreamResult result = new StreamResult(file);
|
|
||||||
DOMSource source = new DOMSource(doc);
|
|
||||||
transformer.transform(source, result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package click.kamil.springstatemachineexporter;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.boot.CommandLineRunner;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||||
|
|
||||||
|
@SpringBootTest
|
||||||
|
class StatemachinedemoApplicationTests {
|
||||||
|
|
||||||
|
@MockitoBean
|
||||||
|
CommandLineRunner commandLineRunner;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void contextLoads() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
package com.example.statemachinedemo;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
|
||||||
|
|
||||||
@SpringBootTest
|
|
||||||
class StatemachinedemoApplicationTests {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void contextLoads() {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user