A simple statemachine for Spring Boot projects. This project presents a simple statemachine framework and a sample usage of the framework for a project like an online order processing.
In this approach we write the requirements as a set of state transitions. In this demo the order state transitions are considered.
| Initial State | Pre-event | Processor | Post-event | Final State |
|---|---|---|---|---|
| DEFAULT -> | submit -> | orderProcessor() -> | orderCreated -> | PMTPENDING |
| PMTPENDING -> | pay -> | paymentProcessor() -> | paymentError -> | PMTPENDING |
| PMTPENDING -> | pay -> | paymentProcessor() -> | paymentSuccess -> | COMPLETED |
By writing the requirements as a set of state transitions we get the following benefits:
Enables building robust applications since the application can only be in one of the three known states specified in the requirements.
Simplifies writing unit tests since writing three tests for the three processors ensures 100% code coverage.
Enables adding new processes faster due to the modular nature of the framework.
-
To use this framework first create a state transitions table like above.
-
Then Configure the transitions in the enums - OrderState and OrderEvent
-
Identify a primary key for the process. For the order process it would be orderId, for a time sheet application it would be userId-week-ending-date etc. (In this demo we store the state in a HashMap. Also, for this quick demo we do not store the state history.)
-
Implement the StateTransitionsManager. See the OrderStateTransitionsManager class for an example.
-
Implement the Processor class. See the OrderProcessor and the PaymentProcessor classes for examples.
-
Create a controller class. See the OrderController for an example.
Run the command ".\gradlew clean build" at the project root
Unit tests can be run using the ".\gradlew test" command at the project root.
Run the command ".\gradlew bootRun" at the prject root.
For the order sample considered in this project, the following APIs are called to test the order process:
- User request to create an order. This API is implemented as GET so it can be tested quickly in the browser.
http://localhost:8080/order
<< creates an order and returns an orderId (as a UUID). Selected product ids are not included in this demo example >>
- User makes a wrong payment. This API is also implemented as GET so it can be tested quickly in the browser.
http://localhost:8080/order/cart?payment=0&orderId=UUID
<< where UUID is the orderId returned by the API call in Step #1. Returns paymentError status. Payment value less than 1.00 is considered for the error transition >>
- User makes a payment. This API is also implemented as GET so it can be tested quickly in the browser.
http://localhost:8080/order/cart?payment=123&orderId=UUID
<< where UUID is the orderId returned by the API call in Step #1 above. Returns Completed status >>
<< for quick testing in a browser all of the above APIs are implemented as GET APIs >> When the above APIs are called the console log displays the state transitions that reflect the above table. (Note: payment=0 is used to mock payment error in this example)
Spring has a more comprehensive statemachine Framework - Spring Statemachine