Skip to content

digitalpetri/strict-machine

Repository files navigation

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:

About

A declarative DSL for building asynchronously evaluated Finite State Machines on the JVM

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published