Skip to content

Latest commit

 

History

History
230 lines (169 loc) · 5.72 KB

StatefulJ_FSM.adoc

File metadata and controls

230 lines (169 loc) · 5.72 KB

StatefulJ FSM

The StatefulJ FSM is a lightweight Finite State Machine with support for Deterministic and Non-Determinstic Transitions. Stateful FSM is self-contained with minimal dependencies (just SLF4J for a logging facade).

Installation

Install StatefulJ FSM from Maven Central into your app by adding the following to your pom.xml:

<dependency>
    <groupId>org.statefulj</groupId>
    <artifactId>statefulj-fsm</artifactId>
    <version>2.1</version>
</dependency>

Or if you are feeling adventurous, you can download and build the latest from source.

Coding

To use StatefulJ FSM, you build State Models. A State Model is a set of States and Transitions which is associated with a Class. This Class is referred to as the Stateful Entity.

To create a State Model, you will need to:

  • Define your Stateful Entity

  • Define your Events

  • Define your States

  • Define your Actions

  • Define your Transitions

  • Define your Persister

  • Construct the FSM

  • Using the FSM

Define your Stateful Entity

A Stateful Entity is a class that contains a State field which is managed by StatefulJ FSM. The type of the State Field is dependent on the Persister being used. The State field is defined by a @State annotation.

// Stateful Entity
//
public class Foo {

    @State
    String state;   // Memory Persister requires a String

    boolean bar;

    public String getState() {
        return state;
    }

    // Note: there is no setter for the state field
    //       as the value is set by StatefulJ

    public void setBar(boolean bar) {
        this.bar = bar;
    }

    public boolean isBar() {
        return bar;
    }

}

Define your Events

Events in StatefulJ are Strings.

// Events
//
String eventA = "Event A";
String eventB = "Event B";

Define your States

A State defines the state value for an Entity and holds the mapping of all Transitions for that State.

// States
//
State<Foo> stateA = new StateImpl<Foo>("State A");
State<Foo> stateB = new StateImpl<Foo>("State B");
State<Foo> stateC = new StateImpl<Foo>("State C", true); // End State

Define your Actions

An Action is a Command object.

// Hello <what> Action
//
public class HelloAction<T> implements Action<T> {

    String what;

    public HelloAction(String what) {
        this.what = what;
    }

    public void execute(T stateful,
                        String event,
                        Object ... args) throws RetryException {
        System.out.println("Hello " + what);
    }
}
// Actions
//
Action<Foo> actionA = new HelloAction("World");
Action<Foo> actionB = new HelloAction("Folks");

Define your Transitions

A Transition is a reaction to an Event directed at a Stateful Entity. The Transition can involve a possible change in State and a possible Action.

Transitions are referred as being either Deterministic or Non-Deterministic:

  • A Deterministic Transition means that for a given State and Event, there is only a single Transition.

  • A Non-Deterministic Transition means that for a given State and Event there is more than one Transition. Transitions are added to a State and are mapped by an Event.

Deterministic Transitions

/* Deterministic Transitions */

// stateA(eventA) -> stateB/actionA
//
stateA.addTransition(eventA, stateB, actionA);

// stateB(eventB) -> stateC/actionB
//
stateB.addTransition(eventB, stateC, actionB);

Non-Deterministic Transitions

/* Non-Deterministic Transitions */

//                   +--> stateB/NOOP  -- loop back on itself
//  stateB(eventA) --|
//                   +--> stateC/NOOP
//
stateB.addTransition(eventA, new Transition<Foo>() {

    public StateActionPair<Foo> getStateActionPair(Foo stateful) {
        State<Foo> next = null;
        if (stateful.isBar()) {
            next = stateB;
        } else {
            next = stateC;
        }

        // Move to the next state without taking any action
        //
        return new StateActionPairImpl<Foo>(next, null);
    }
});

Define your Persister

A Persister is a Class Responsible for persisting the State value for a Stateful Entity. A Persister implements the Persister interface and must ensure that updates are atomic, isolated and thread-safe. The Stateful FSM library comes with an in-memory Persister which maintains the State only on the in-memory Stateful Entity. If you need to persist to a database, you will need to use one of the Database Persisters or integrate the StatefulJ Framework.

// In-Memory Persister
//
List<State<Foo>> states = new LinkedList<State<Foo>>();
states.add(stateA);
states.add(stateB);
states.add(stateC);

MemoryPersisterImpl<Foo> persister =
    new MemoryPersisterImpl<Foo>(
        states,   // Set of States
        stateA);  // Start State

Construct the FSM

The final step is construct the FSM.

// FSM
//
FSM<Foo> fsm = new FSM<Foo>("Foo FSM", persister);

Using the FSM

Now that you have everything set up, you can drive your FSM by calling the onEvent method, passing in the Stateful Entity and the Event

// Instantiate the Stateful Entity
//
Foo foo = new Foo();

// Drive the FSM with a series of events: eventA, eventA, eventA
//
fsm.onEvent(foo, eventA);  // stateA(EventA) -> stateB/actionA

foo.setBar(true);

fsm.onEvent(foo, eventA);  // stateB(EventA) -> stateB/NOOP

foo.setBar(false);

fsm.onEvent(foo, eventA);  // stateB(EventA) -> stateC/NOOP