Skip to content
Nikolaos Pougounias edited this page Jul 29, 2014 · 3 revisions

In order to use the FSM Engine in your own project, the steps described below can be followed:

  • Identify the classes in your application whose behavior changes depending on their state and therefore would better be managed by the FSM Engine.
  • Populate the StateName enum with all the possible state names you envisage for each one of the classes selected in the previous step. Each state name is represented with an enum constant. So, for example, the state names for an Order class in an ecommerce application could be PENDING, PROCESSING, SHIPPED, CANCELLED, etc.
  • Have those classes implement the StateContext interface:
    • Add a property in your class for maintaining a reference to the current StateName.
    • Provide proper accessors and mutators (i.e. implement the StateContext#getStateName() and StateContext#setStateName() methods) for the StateName property
    • Initialise the StateName property assigning the StateName enum constant that corresponds to the initial state of your class
    • Implement the StateContext#isDone() method by providing a proper Boolean expression which will evaluate to true when your class has reached the final state, that is, when the current StateName of your class equals to the StateName constant designated as the final state for this class.
    • In case of nested states, implement the StateContext#getParent() method by providing a reference to the parent StateContext instance, otherwise return null.
  • Create a State class for each one of the StateName enum constants either by extending the DefaultState class provided along with the FSM Engine or if this doesn’t fit your needs by directly implementing the State interface. In any case, getStateName() should return the corresponding StateName enum constant.
  • Create an Event class for each one of the triggering events that you envisage for your domain’s state (or internal) transitions either by extending the DefaultEvent class provided with FSM Engine or by directly implementing the Event interface (not normally the case):
    • Override (or implement) getName() to return a suitable Event name
    • Optionally, override (or implement) getInteractionType() returning one of the available InteractionType constants (the default implementation uses InteractionType#NEUTRAL)
  • Create a Transition class corresponding to each one of the possible transitions you envisage for your domain’s States either by extending the DefaultTransition class provided with the FSM Engine or by directly implementing the Transition interface:
    • getFromState() should correspond to the State containing this Transition, otherwise an InvalidTransitionException will be thrown.
    • getToState() should correspond to the desired result of the state transition, i.e. to the State which the current State should switch to if the Transition is executed successfully.
    • Optionally, if the Transition is conditional, getGuardCondition() should be overridden to return a proper instance of the GuardCondition interface. This mean that you will need to create a GuardCondition class for each one of the applicable conditions in your Transitions, either by extending the AbstractGuardCondition class and implementing the execute(StateContext stateContext) abstract method or by directly implementing the GuardCondition interface.
    • Optionally, getActions() can be overridden to return a list of Actions to be performed once the Transition has been executed. Again, if this is the case, you will need to create an Action class for each one of the applicable Actions in your Transitions, either by extending the AbstractAction class and implementing the execute(StateContext stateContext) abstract method or by directly implementing the Action interface. If you wish the execution of Actions to be an all or nothing operation, you will also have to override the Action#rollback(StateContext stateContext) method for all of your Actions providing a proper rollback routine.
  • Once you have all of the required Events and Transitions in place, override State#getEventTransitionsMap() providing a map populated with all the valid Events for this State and their corresponding Transitions. If more than one Transitions are possible for a given Event, create a Branch class either by extending DefaultBranch and overriding the getPossibleTransitions() method or by directly implementing the Branch interface, and assign this Branch as the map value instead of a Transition.
  • As long as all of the FSM Engine definitions and wirings are complete, you can bootstrap the state machine execution by calling FiniteStateMachine#processEvent(Event event, StateContext stateContext) and passing one of your concrete Event objects along with the StateContext object as parameters. If everything is wired correctly and no exceptions are thrown along the way, normally, upon completion of the state machine execution, the state (StateName to be precise) of the StateContext instance in question should have changed to a new one (provided that this is a state transition rather than an internal transition) and any defined Actions should have been executed. Depending on your requirements, you can either use one of the provided FiniteStateMachine implementations (currently only gr.ekt.fsmegine.api.SpringFsm is available) for this reason or provide your own implementation/extension.

Clone this wiki locally