State and Flow Overrides¶
At times a state may need to be extended to add, alter, or remove functionality. To accommodate state and flow extensions there are multiple techniques that should be used based on the type of extension desired.
Extension Techniques¶
There are multiple extension techniques that can be used based on the specific needs.
- Flow Routing for changing the YAML flow configuration.
- Action Handler for handling an action from the State Machine.
- Event Handler for handling asynchronous
AppEvent.
Flow Routing¶
Flow Routing changes can be done by creating flow-ext.yml resource files that adjust the desired flow and state
actions. This type of alteration is typically used when needing to add a state to a flow or to change the state that
will be used when routing for a specific action.
Reasons why flows might need to be extended:
- Adding new flows.
- Adding new state to existing flow.
- Changing the state a particular flow will route to from an action.
Example¶
With this example we will change the MyHelpfulFlow and change the SomeAction so that it will route to a new state.
Given this flow in helpful-flow.yml:
MyHelpfulFlow:
- MyState:
SomeAction: MyOtherState
- MyOtherState:
AllDone: CompleteState
Extension flow in helpful-flow-ext.yml:
MyHelpfulFlow:
- MyState:
SomeAction: MyNewState
- MyNewState:
AllDone: CompleteState
Read more about defining flows here.
Best Practices¶
- Reroute existing actions to new states or new flows
- Add new actions from new buttons that route to new states or new flows
- Do all new business logic in the new states. Return from flows using no ReturnAction (which just calls the @OnArrive method) or route to a new state or subflow by using ReturnActionMapping
- If the state that is transitioning to a custom flow does not have a generic return method, then one should be added to base. Should not be extending just to a return method.
Anti-patterns¶
- Subclassing existing states for enhancement.
Action Handler¶
All Action Handlers should be implemented via a State Bean. Action Handlers are ideally used when a particular action is intended to make a call to a microservice to persist data or to save data to the State Context so that it can be used later in the flow or from a Screen Builder.
To use the State Bean Action Handler, the state must have a Screen Builder that will return a non-empty screen.
@State(name = "MyState")
public class OnSomeAction {
@ActionHandler
public void onSomeAction(Action action) {
...
}
}
Best Practices¶
- Name the action handler class in the pattern
On{Action Name} - Use State Context properties to access and store data for the flow in
@In,@InOut, or@Out.
Anti-Patterns¶
- Interacting with
IStateManagershould be avoided when possible. - Avoid adding multiple action handler methods to an action handler state bean as this can make maintaining the code harder.
Event Handler¶
All Event Handlers should be implemented via a State Bean. Application Events can be fired from Action Handlers, Event Handlers, Microservice Endpoints, or anywhere else within the application. When these events are fired they are given the Device ID and App ID that they are intending to process the event. Events can then be processed by the device that was intended to handle the event through a State Bean.
Events Handlers can listen for events that were also not emitted directly for the device but also in scenarios where the device is linked with another device, an example being a POS terminal and a Customer Display.
Event Handler Sources¶
Event Handlers can listen to multiple sources to combine functionality. This is extremely useful when trying to keep two different devices in sync based on the actions of another device.
SELF¶
Event Handlers that are listening for SELF sources will get events intended for itself for the current state defined
for the event handlers.
PARENT¶
Event Handlers that are listening for PARENT sources will get events intended for the parent device for the current
state defined for the event handler. The example is if a POS were to emit an event the Customer Display could handle
those events by setting the sources to PARENT.
PAIRED¶
Event Handlers that are listening for PAIRED sources will get events intended for the child device for the current
state defined for the event handler. The example is if the Customer Display were to emit an event the POS could handle
those events by setting the sources to PAIRED.
ALL¶
Event Handlers that are listening for ALL sources will get all events.
Example¶
Here is a simple example to handle events for from the current device and its paired device.
@State(name = "MyState")
public class OnMyEvent {
@OnEvent(sources = {SELF, PAIRED})
public void onMyEvent(MyEvent event) {
...
}
}
Best Practices¶
- Name the action handler class in the pattern
On{Event Type}Handler - Use State Context properties to access and store data for the flow in
@In,@InOut, or@Out.
Anti-Patterns¶
- Interacting with
IStateManagershould be avoided when possible. - Avoid adding multiple action handler methods to an action handler state bean as this can make maintaining the code harder.