From d6449a8de1f4f6336c5009c58d6483d519c7beef Mon Sep 17 00:00:00 2001 From: Kamil Patryk Kozakowski Date: Tue, 15 Jul 2025 03:52:13 +0200 Subject: [PATCH] choice for plantuml as rectangles --- .../ast/out/PlantUml.java | 23 +++-- .../KamilEnumStateMachineConfiguration.java | 94 +++++++++++++++++++ 2 files changed, 111 insertions(+), 6 deletions(-) create mode 100644 src/main/java/click/kamil/springstatemachineexporter/statemachine/KamilEnumStateMachineConfiguration.java diff --git a/src/main/java/click/kamil/springstatemachineexporter/ast/out/PlantUml.java b/src/main/java/click/kamil/springstatemachineexporter/ast/out/PlantUml.java index dfb7a14..032c414 100644 --- a/src/main/java/click/kamil/springstatemachineexporter/ast/out/PlantUml.java +++ b/src/main/java/click/kamil/springstatemachineexporter/ast/out/PlantUml.java @@ -29,6 +29,7 @@ public class PlantUml implements StateMachineExporter { Set startStates, Set endStates, boolean useLambdaGuards) { + boolean includeChoiceStates = false; StringBuilder sb = new StringBuilder(); sb.append("@startuml\n"); sb.append("skinparam state {\n"); @@ -53,9 +54,14 @@ public class PlantUml implements StateMachineExporter { // 3. Declare choice pseudostates & connect from original state for (String state : statesWithChoice) { - String choiceState = state + "_choice"; - sb.append("state ").append(choiceState).append(" <>\n"); - sb.append(state).append(" --> ").append(choiceState).append("\n"); + String choiceState = state; + if (includeChoiceStates) { + choiceState = state + "_choice"; + sb.append("state ").append(choiceState).append(" <>\n"); + sb.append(state).append(" --> ").append(choiceState).append("\n"); + } else { + sb.append("state ").append(choiceState).append(" <>\n"); + } } sb.append("\n"); @@ -91,9 +97,14 @@ public class PlantUml implements StateMachineExporter { for (String rawTarget : targets) { String target = simplify(rawTarget); - String transitionSource = "withChoice".equals(t.getType()) && statesWithChoice.contains(source) - ? source + "_choice" - : source; + String transitionSource; + if (includeChoiceStates) { + transitionSource = "withChoice".equals(t.getType()) && statesWithChoice.contains(source) + ? source + "_choice" + : source; + } else { + transitionSource = source; + } String label = buildLabel(t, useLambdaGuards); String color = getColor(t, source, choiceStateColorMap); diff --git a/src/main/java/click/kamil/springstatemachineexporter/statemachine/KamilEnumStateMachineConfiguration.java b/src/main/java/click/kamil/springstatemachineexporter/statemachine/KamilEnumStateMachineConfiguration.java new file mode 100644 index 0000000..395a97a --- /dev/null +++ b/src/main/java/click/kamil/springstatemachineexporter/statemachine/KamilEnumStateMachineConfiguration.java @@ -0,0 +1,94 @@ +package click.kamil.springstatemachineexporter.statemachine; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Configuration; +import org.springframework.statemachine.StateContext; +import org.springframework.statemachine.action.Action; +import org.springframework.statemachine.config.EnableStateMachineFactory; +import org.springframework.statemachine.config.StateMachineConfigurerAdapter; +import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer; +import org.springframework.statemachine.config.builders.StateMachineStateConfigurer; +import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer; +import org.springframework.statemachine.guard.Guard; +import org.springframework.statemachine.listener.StateMachineListenerAdapter; +import org.springframework.statemachine.state.State; + +@Configuration +@EnableStateMachineFactory(name = "simpleEnumStateMachineFactory") +@Slf4j +class KamilEnumStateMachineConfiguration extends StateMachineConfigurerAdapter { + @Override + public void configure(StateMachineTransitionConfigurer transitions) throws Exception { + Guard guard1 = null; + Action action2 = null; + transitions + .withExternal().source(OrderStates.SUBMITTED).target(OrderStates.PAID).event(OrderEvents.PAY) + .and() + .withExternal().source(OrderStates.PAID).target(OrderStates.FULFILLED).event(OrderEvents.FULFILL) + .and() + .withExternal().source(OrderStates.SUBMITTED).target(OrderStates.CANCELED).event(OrderEvents.CANCEL).guard(new Guard() { + @Override + public boolean evaluate(StateContext context) { + return false; + } + }) + .and() + .withExternal().source(OrderStates.PAID).target(OrderStates.CANCELED).event(OrderEvents.CANCEL) + + + .and() + .withExternal().source(OrderStates.SUBMITTED).event(OrderEvents.ABCD) + // it needs to have target specified to get added to .transitions collections + .and() + .withExternal().source(OrderStates.SUBMITTED).target(OrderStates.PAID1).event(OrderEvents.ABCD) +// + .and() + .withChoice().source(OrderStates.PAID1) + .first(OrderStates.PAID2, new Guard() { + @Override + public boolean evaluate(StateContext context) { + return true; + } + }) + .then(OrderStates.PAID3, guard1) + .then(OrderStates.HAPPEN, new Guard() { + @Override + public boolean evaluate(StateContext context) { + return false; + } + }) + .last(OrderStates.CANCELED) + .and().withExternal().source(OrderStates.PAID2).target(OrderStates.CANCELED) + .and().withExternal().source(OrderStates.PAID3).target(OrderStates.CANCELED) +// .and().withLocal().source(OrderStates.SUBMITTED).target(OrderStates.CANCELED) + .and().withExternal().source(OrderStates.PAID2).event(OrderEvents.ABCD).action(new Action() { + @Override + public void execute(StateContext context) { + ; + } + }).action(action2); + } + + @Override + public void configure(StateMachineStateConfigurer states) throws Exception { + states.withStates() + .initial(OrderStates.SUBMITTED) + .state(OrderStates.PAID) + .state(OrderStates.PAID2) + .state(OrderStates.PAID3) + .end(OrderStates.FULFILLED) + .end(OrderStates.CANCELED); + } + @Override + public void configure(StateMachineConfigurationConfigurer config) throws Exception { + StateMachineListenerAdapter listenerAdapter = new StateMachineListenerAdapter<>() { + @Override + public void stateChanged(State from, State to) { + log.info("state changed from {} to {}", from, to); + } + }; + config.withConfiguration() + .autoStartup(false) + .listener(listenerAdapter); + } +} \ No newline at end of file