Skip to content

Latest commit

 

History

History
155 lines (118 loc) · 4.28 KB

README.md

File metadata and controls

155 lines (118 loc) · 4.28 KB

Strict Machine

Maven Central

Strict Machine is a declarative DSL for building asynchronously evaluated Finite State Machines.

Release builds are available from Maven Central and SNAPSHOT builds are available from the Sonatype OSS Snapshot Repository.

Gradle

dependencies {
    compile("com.digitalpetri.fsm:strict-machine:0.7")
}

Maven

<dependencies>
    <dependency>
      <groupId>com.digitalpetri.fsm</groupId>
      <artifactId>strict-machine</artifactId>
      <version>0.7</version>
    </dependency>
</dependencies>

What does it look like?

Given this simple ATM example:

atmfsm.png

Define the State and Event types:

enum State {
    Idle,
    Loading,
    OutOfService,
    InService,
    Disconnected
}

enum Event {
    Connected,
    ConnectionClosed,
    ConnectionLost,
    ConnectionRestored,
    LoadFail,
    LoadSuccess,
    Shutdown,
    Startup
}

Define the transitions:

FsmBuilder<State, Event> fb = new FsmBuilder<>();

/* Idle */
fb.when(State.Idle)
  .on(Event.Connected)
  .transitionTo(State.Loading);

/* Loading */
fb.when(State.Loading)
  .on(Event.LoadSuccess)
  .transitionTo(State.InService);

fb.when(State.Loading)
  .on(Event.LoadFail)
  .transitionTo(State.OutOfService);

fb.when(State.Loading)
  .on(Event.ConnectionClosed)
  .transitionTo(State.Disconnected);

/* OutOfService */
fb.when(State.OutOfService)
  .on(Event.Startup)
  .transitionTo(State.InService);

fb.when(State.OutOfService)
  .on(Event.ConnectionLost)
  .transitionTo(State.Disconnected);

/* InService */
fb.when(State.InService)
  .on(Event.ConnectionLost)
  .transitionTo(State.Disconnected);

fb.when(State.InService)
  .on(Event.Shutdown)
  .transitionTo(State.OutOfService);

/* Disconnected */
fb.when(State.Disconnected)
  .on(Event.ConnectionRestored)
  .transitionTo(State.InService);

Fsm<State, Event> fsm = fb.build(State.Idle);

Fire events to be evaluated asynchronously:

fsm.fireEvent(Event.Connected);

or block waiting for the state that resulted from evaluating the event:

State state = fsm.fireEventBlocking(Event.Connected); 

Transition Guards

Guard conditions that prevent a transition from occurring unless they're met can be defined using guardedBy:

fb.when(State.Idle)
    .on(Event.Connected)
    .transitionTo(State.Loading)
    .guardedBy(ctx -> ...guard condition here...);

Where the guard provided to guardedBy is a Predicate that receives the FsmContext.

Transition Actions

Of course, in order for your state machine to actually do something, you need to define actions that execute when events are evaluated and transitions occur.

This is accomplished using the onTransitionTo, onTransitionFrom, and onInternalTransition methods on FsmBuilder.

For example, logging a message on the transition from Idle to Loading might be defined in either of two ways:

// define the action in the context of a transition away from Idle
fb.onTransitionFrom(State.Idle)
    .to(State.Loading)
    .via(Event.Connected)
    .execute(ctx -> System.out.println("S(Idle) x E(Connected) = S'(Loading)"));
        
// define the action in the context of a transition to Loading
fb.onTransitionTo(State.Loading)
    .from(State.Idle)
    .via(Event.Connected)
    .execute(ctx -> System.out.println("S(Idle) x E(Connected) = S'(Loading)"));

More Examples

See the full AtmFsm defined in the test suite.

Advanced examples from production code: