State Bean¶
State Beans are components that can be created to handle interaction with a state via the StateContext.
Creating a State Bean¶
State Beans are spring components defined by adding @State to a class that also implements one of
the Supported State Bean types. State beans can also be defined for multiple states
using @States with multiple @State annotations.
The following class (OnSomeAction) is an example of what a State Bean looks like that will be evaluated
when StateContext has the current state of MyState.
@State(name = "MyState")
class OnSomeAction {
...
}
@States({
@State(name = "MyState"),
@State(name = "MyOtherState")
})
class OnSharedAction {
...
}
Lifecycle¶
State Beans are created
as prototype
beans and are generated each time they are needed by the StateMachine during the action loop. This means that any
members on the class MUST be annotated with the Scoped Context
annotations of @In, @InOut, or @Out in order to make data available to other state beans or to persist it past the
invocation of the state bean.
Supported State Bean¶
Action Handler¶
Action Handler State Beans are a type State Bean that conforms to the Responding to Actions of flow control.
@State(name = "MyState")
class OnSomeAction {
@ActionHandler
public void onSomeAction(Action action) {
...
}
}
Event Handler¶
Event Handler State Beans are a type of State Bean that are invoked when AppEvent are published via EventPublisher.
@State(name = "MyState")
class OnSomeEventHandler {
@OnEvent(sources = SELF)
public void onSomeEvent(SomeEvent event) {
...
}
}
Screen Builder¶
Screen Builder State Beans are a type of State Bean that are invoked from the ShowScreenAfterActionLoop which is only
invoked when the StateManager is not busy and the current device has no more current actions in the action loop queue.
Screen Builder State Beans must implement IBuildScreen and return a non-empty Optional in order for the given screen
builder to have been used. Screen Builders can also have extra filters that other State Beans do not support which is
the @ActionScreenBuilder annotation which acts as a filter for the state bean and a priority order for that specific
screen builder to be evaluated sooner.
Note: Screen Builders with @ActionScreenBuilder where the value attribute contains an action that was completed
in the action loop will be prioritized above other state beans, this includes State beans with a
higher Order of Precedence unless both beans have the @ActionScreenBuilder annotation in which
case both will be ordered above other State Beans and then ordered by the standard order of precedence amongst
the @ActionScreenBuilder beans.
StateContext Resolution¶
State Beans support multiple layers of filtering to allow for state beans to be applicable in the most appropriate case
given the business need. By specifying the properties for the @State annotation a State Bean will be restricted to
only be evaluated when the StateContext meets the annotations properties. For a State Bean to be considered a match
all of the @State properties must match the StateContext OR be left blank.
Note: This does mean that State Beans can be defined globally and evaluated for every state.
State¶
A State Bean will be considered a match for a StateContext when the class of the state object matches the name
attribute of the @State annotation.
With the following example the StateContext#state member is an instance of MyState only OnSomeAction would be
resolved as a candidate for an appropriate State Bean to then be further evaluated for matching of an Action Handler,
Event Handler, or Screen Builder.
class StateContext {
private Object state; // = MyState
}
@State(name = "MyState")
class OnSomeAction {
}
@State(name = "OtherState")
class OnSomethingElse {
}
Flow¶
A State Bean will be considered a match for a StateContext when the flowConfig has a name that matches the flow
attribute of the @State annotation.
With the following example the StateContext has a flowConfig with a name of MyFancyFlow only OnFlowAction
would be resolved as a candidate for an appropriate State Bean to then be further evaluated for matching of an Action
Handler, Event Handler, or Screen Builder.
class FlowConfig {
String name; // = "MyFancyFlow"
}
class StateContext {
FlowConfig flowConfig;
}
@State(flow = "MyFancyFlow")
class OnFlowAction {
...
}
@State(flow = "MyOtherFlow")
class OnOtherFlowAction {
....
}
App ID¶
A State Bean will be considered a match for a StateContext when the appId matches the appId attribute of
the @State annotation. The StateContext will be populated with the appId of the device from its initial
connection.
With the following example the StateContext has an appId of customerdisplay only CustomerDisplayOnSomeAction
would be resolved as a candidate for an appropriate State Bean to then be further evaluated for matching of an Action
Handler, Event Handler, or Screen Builder.
class StateContext {
String appId; // = "customerdisplay"
}
@State(appId = "pos")
class POSOnSomeAction {
...
}
@State(appId = "customerdisplay")
class CustomerDisplayOnSomeAction {
....
}
Order of Precedence¶
In almost every case a state will have more than one State Bean defined. When multiple state beans are defined they will
be ordered based on the specificity of the @State annotation itself then optionally based on the needs of the State
Bean type further ordering followed finally be springs PriorityOrdered, Ordered, and finally the Order annotation.
When determining the order the State Beans will be evaluated based on the name, flow, and appId attributes of
the @State annotation with the most precedence given to a value with a non-default value then ordered by state, flow,
then appId.
Order Evaluation¶
- State, Flow, and AppId all non-default values
- State and Flow defined non-default values
- State and AppId defined non-default values
- State defined non-default value
- Flow and AppId defined non-default values
- Flow defined non-default value
- AppId defined non-default value
- All default values
Order Example¶
@State(name = "MyState", flow = "MyFlow", appId = "my-app")
class OnSomething1 {
// Example of State Bean Definition meeting criteria 1.
}
@State(name = "MyState", flow = "MyFlow")
class OnSomething2 {
// Example of State Bean Definition meeting criteria 2.
}
@State(name = "MyState", appId = "my-app")
class OnSomething3 {
// Example of State Bean Definition meeting criteria 3.
}
@State(name = "MyState")
class OnSomething4 {
// Example of State Bean Definition meeting criteria 4.
}
@State(flow = "MyFlow", appId = "my-app")
class OnSomething5 {
// Example of State Bean Definition meeting criteria 5.
}
@State(flow = "MyFlow")
class OnSomething6 {
// Example of State Bean Definition meeting criteria 6.
}
@State(appId = "my-app")
class OnSomething7 {
// Example of State Bean Definition meeting criteria 7.
}
@State
class OnSomething8 {
// Example of State Bean Definition meeting criteria 8.
}
Conditional Base Implementations¶
All base implementation beans should be annotated with @ConditionalOnMissingActionHandler
or @ConditionalOnMissingScreenBuilder which will evaluate if any other state bean for the given bean type (Action
Handler or Screen Builder) is defined that meets the exact State Bean definition as the bean with the conditional
annotation.
ConditionalOnMissingActionHandler¶
Given base has a State Bean defined for MyState to handle an action of SomeAction if an implementer needs to extend
the state and adjust what happens for SomeAction just by creating a new State Bean of OnSomeAction with the same
definition as the base it will be the chosen implementation.
So with the following action, BaseOnSomeAction will not appear in the Spring ApplicationContext but OnSomeAction
will be present.
@State(name = "MyState")
@ConditionalOnMissingActionHandler
class BaseOnSomeAction {
@ActionHandler
public void onSomeAction(Action action) {
...
}
}
@State(name = "MyState")
class OnSomeAction {
@ActionHandler
public void onSomeAction(Action action) {
...
}
}
ConditionalOnMissingScreenBuilder¶
Screen Builder can be present as both a default screen matching a @State annotation or for a specific action after the
action loop. The screen builder condition will prevent a screen builder from being match when the state configuration is
an exact match just like the Action Handler condition but it will also check if the screen builder is annotated
with @ActionScreenBuilder as an extra condition since that is considered to be a unique state bean.
Given the following example, BaseBuildMyStateScreen would not be added to the Spring ApplicationContext and instead
would add BuildMyStateScreen. However, BaseBuildMyStateMyActionScreen would still be added to
the ApplicationContext since it was also annotated with ActionScreenBuilder and the action name was not defined in
an override screen builder.
@State(name = "MyState")
@ConditionalOnMissingScreenBuilder
class BaseBuildMyStateScreen implements IBuildScreen<MyStateUIMessage> {
...
}
@ActionScreenBuilder("MyAction")
@State(name = "MyState")
@ConditionalOnMissingScreenBuilder
class BaseBuildMyStateMyActionScreen implements IBuildScreen<MyActionMyStateUIMessage> {
...
}
@State(name = "MyState")
class BuildMyStateScreen implements IBuildScreen<MyStateUIMessage> {
...
}