extended analysis

This commit is contained in:
2026-06-14 16:32:51 +02:00
parent 2251a587d9
commit ab474c0766
125 changed files with 4180 additions and 317 deletions

View File

@@ -0,0 +1,55 @@
package click.kamil.examples.statemachine.extended.config;
import click.kamil.examples.statemachine.extended.constants.MyEvents;
import org.springframework.context.annotation.Configuration;
import org.springframework.statemachine.config.EnableStateMachine;
import org.springframework.statemachine.config.StateMachineConfigurerAdapter;
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
import org.springframework.beans.factory.annotation.Value;
@Configuration
@EnableStateMachine(name = "extendedStateMachine")
public class ExtendedStateMachineConfig extends StateMachineConfigurerAdapter<String, String> {
@Value("${app.states.initial:START}")
private String initialState;
@Override
public void configure(StateMachineStateConfigurer<String, String> states) throws Exception {
states
.withStates()
.initial(initialState)
.state("PROCESSING")
.state("COMPLETED")
.state("CANCELLED");
}
@Override
public void configure(StateMachineTransitionConfigurer<String, String> transitions) throws Exception {
transitions
.withExternal()
.source("START").target("PROCESSING")
.event(MyEvents.SUBMIT)
.and()
.withExternal()
.source("PROCESSING").target("COMPLETED")
.event("FINISH")
.and()
.withExternal()
.source("PROCESSING").target("CANCELLED")
.event(MyEvents.CANCEL)
.and()
.withExternal()
.source("START").target("PROCESSING")
.event("REACTIVE_EVENT")
.and()
.withExternal()
.source("START").target("START")
.event("AUDIT_EVENT")
.and()
.withExternal()
.source("START").target("PROCESSING")
.event("EXTERNAL_TRIGGER");
}
}

View File

@@ -0,0 +1,6 @@
package click.kamil.examples.statemachine.extended.constants;
public class MyEvents {
public static final String SUBMIT = "SUBMIT_EVENT";
public static final String CANCEL = "CANCEL_EVENT";
}

View File

@@ -0,0 +1,11 @@
package click.kamil.examples.statemachine.extended.service;
import org.springframework.stereotype.Service;
@Service
public class ExternalNotificationService {
public void sendExternalNotification(String message) {
// Simulated third-party call that triggers a state change in an external system
System.out.println("Notifying external system: " + message);
}
}

View File

@@ -0,0 +1,31 @@
package click.kamil.examples.statemachine.extended.service;
import click.kamil.examples.statemachine.extended.constants.MyEvents;
import lombok.RequiredArgsConstructor;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.persist.StateMachinePersister;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class OrderService {
private final StateMachine<String, String> stateMachine;
private final StateMachinePersister<String, String, String> persister;
private final ExternalNotificationService notificationService;
public void processSubmit() {
// Business logic here...
notificationService.sendExternalNotification("Submit processed");
stateMachine.sendEvent(MyEvents.SUBMIT);
}
public void processCancel() {
// More business logic...
stateMachine.sendEvent(MyEvents.CANCEL);
}
public void resumeOrder(String orderId) throws Exception {
persister.restore(stateMachine, orderId);
}
}

View File

@@ -0,0 +1,22 @@
package click.kamil.examples.statemachine.extended.service;
import lombok.RequiredArgsConstructor;
import org.springframework.statemachine.StateMachine;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
@Service
@RequiredArgsConstructor
public class ReactiveOrderService {
private final StateMachine<String, String> stateMachine;
public Mono<Void> processReactive(String orderId) {
return Mono.just(orderId)
.doOnNext(id -> {
// Hidden trigger inside a lambda!
stateMachine.sendEvent("REACTIVE_EVENT");
})
.then();
}
}

View File

@@ -0,0 +1,19 @@
package click.kamil.examples.statemachine.extended.web;
import lombok.RequiredArgsConstructor;
import org.springframework.statemachine.StateMachine;
import org.springframework.web.servlet.HandlerInterceptor;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@RequiredArgsConstructor
public class AuditInterceptor implements HandlerInterceptor {
private final StateMachine<String, String> stateMachine;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
stateMachine.sendEvent("AUDIT_EVENT");
return true;
}
}

View File

@@ -0,0 +1,46 @@
package click.kamil.examples.statemachine.extended.web;
import click.kamil.examples.statemachine.extended.constants.MyEvents;
import click.kamil.examples.statemachine.extended.service.OrderService;
import click.kamil.examples.statemachine.extended.service.ReactiveOrderService;
import lombok.RequiredArgsConstructor;
import org.springframework.statemachine.StateMachine;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/api/orders")
@RequiredArgsConstructor
public class OrderController {
private final StateMachine<String, String> stateMachine;
private final OrderService orderService;
private final ReactiveOrderService reactiveOrderService;
@PostMapping("/submit")
public void submitOrder() {
orderService.processSubmit();
}
@PostMapping("/cancel")
public void cancelOrder() {
orderService.processCancel();
}
@PostMapping("/finish")
public void finishOrder() {
stateMachine.sendEvent("FINISH");
}
@PostMapping("/resume")
public void resumeOrder(String orderId) throws Exception {
orderService.resumeOrder(orderId);
}
@PostMapping("/reactive")
public Mono<Void> reactiveOrder(String orderId) {
return reactiveOrderService.processReactive(orderId);
}
}

View File

@@ -0,0 +1 @@
app.states.initial=PROD_INITIAL

View File

@@ -0,0 +1 @@
app.states.initial=INIT_STATE

View File

@@ -0,0 +1,6 @@
[
{
"methodFqn": "ExternalNotificationService.sendExternalNotification",
"event": "EXTERNAL_TRIGGER"
}
]