-
Notifications
You must be signed in to change notification settings - Fork 3
Domain Model
The FSM Engine consists of a set of core interfaces and classes all of which are found under the gr.ekt.fsmengine.api.* package and described below:
#####gr.ekt.fsmengine.api.StateContext Maintains a reference to the current state. It should be implemented by one or more client classes that can have different internal states and whose behavior changes depending on those states.
#####gr.ekt.fsmengine.api.State
Represents the different states of the state machine. Each possible state of a class implementing the StateContext interface should correspond to a concrete implementation of this interface.
#####gr.ekt.fsmengine.api.StateName A Java enum acting as a bridge between StateContext and States. Within the classes that implement the StateContext interface, internal states are represented via a StateName enum rather than a State object. This is due to the fact that typically StateContext implementations will need to be persisted in a database and therefore representing States with a regular object would introduce unnecessary complexities (since the relationship between StateContexts and States would need to be mapped at the database level as well) as opposed to Java enums which can be easily persisted in a database as plain text.
#####gr.ekt.fsmengine.api.Event Represents an external or internal event such as a button click or a date expiration that can change the State of an object, thus leading to a state Transition in the system. Usually, there is only one Transition corresponding to a given Event but it is also possible to accommodate more than one Transitions for an Event via Branches and GuardConditions (see below). An Event can also be characterised by an InteractionType. gr.ekt.fsmengine.api.InteractionType is a Java enum with three constants, namely POSITIVE, NEGATIVE and NEUTRAL. It is not coupled to any particular purpose, but the most common use case is for styling form controls in the front end, such as for coloring buttons that fire certain Events for example.
#####gr.ekt.fsmengine.api.Transition Defines the transition from one state to another as a response of the state machine to an occurrence of a specific Event. A Transition can be guarded by a GuardCondition which determines whether the execution of the Transition should proceed or not. In addition, a Transition can be associated with one or more Actions to be performed once the Transition has been executed.
#####gr.ekt.fsmengine.api.GuardCondition A GuardCondition is actually a Boolean expression that affects the behavior of the state machine by enabling Transitions only when it evaluates to true and disabling them when it evaluates to false. A GuardCondition can be associated with many Transitions but each Transition can have only one GuardCondition.
#####gr.ekt.fsmengine.api.Action Defines an activity that is to be performed when executing a certain Transition. An Action can be associated with more than one Transitions and a Transition can have more than one Actions. Also note that an Action can well trigger an Event having as a result another Transition.
#####gr.ekt.fsmengine.api.Branch Acts as a container of Transitions. It is used in cases where there is no one-to-one mapping between an Event and a Transition but instead there are more than one possible Transitions for a given Event. In principle, the Transitions contained in a Branch are mutually exclusive, meaning that only one Transition will be executed each time and this will be determined once the GuardConditions of all Transitions have been evaluated. Note however, that currently this behavior is not strictly enforced by the Engine and therefore care should be taken to avoid unexpected results.
#####gr.ekt.fsmengine.api.StateChanger Its sole purpose is to define a common interface for Transitions and Branches so that they can be used interchangeably (i.e. both Transition and Branch interfaces extend this interface).
#####gr.ekt.fsmengine.api.FiniteStateMachine An abstraction encapsulating the internal details of the state machine, presenting a single interface to the outside world. Implementation classes should be used as the main point where the lifecycle management of a StateContext takes place, whenever a triggering Event occurs.
The figure below depicts the main relationships between the aforementioned classes:

Where required, either default implementation classes of the core interfaces (DefaultState, DefaultEvent, DefaultTransition, DefaultBranch, DefaultFsm, SpringFsm) or base abstract classes (AbstractAction, AbstractGuardCondition) are provided, that are necessary for implementing the basic logic of the state machine. Normally they should be used as is, but nevertheless if needed they are “open for extension and closed for modification” (thus following the open/closed principle). In addition, some utility implementation classes are provided under the gr.ekt.fsmengine.impl.* package which might come in handy e.g. for testing purposes:
#####gr.ekt.fsmengine.impl.AlwaysTrueCondition A GuardCondition implementation (actually an AbstractGuardCondition extension) that always evaluates to true.
#####gr.ekt.fsmengine.impl.AlwaysFalseCondition A GuardCondition implementation (actually an AbstractGuardCondition extension) that always evaluates to false.
#####gr.ekt.fsmengine.impl.NullAction An Action implementation (actually an AbstractAction extension) that does nothing other than logging a dummy debug statement.