Finite State Machine on Scala

Yes, another one Finite State Machine (FSM) on Scala!

The best way studying a new language – to write simple real task. I chose FSM.

State Model

Collection of Transition defines state model.

Each transition defines:

  • source state
  • destination state
  • input (type and parameters)
  • collection of conditions – TransitionCondition
  • type of aggregation (all, one, etc.)
  • priority

Each TransitionCondition defines:

  • parameter name
  • compare type (“<“, “=”, “>”, etc.)
  • expected value

Parameter may be:

  • Text
  • Double
  • Integer
  • Date

Sources on Scala are here

About ysden123

We are not only for work... All my time free from work I spend on photography. Most photos are from our travels. I like make photos in still life style as well.
This entry was posted in Programming, Scala and tagged , , , , , , , , . Bookmark the permalink.

5 Responses to Finite State Machine on Scala

  1. Nats says:

    Hi, thank you so much for the post on FSM. I have gone through the source code and have question regarding the execution.

    1) I have 3 states (TUNE,TRICK,NON-TUNED)
    2) I have trigger events (ex: PLAY, PAUSE, FORWARD, REPLAY)
    3) Based on the trigger events I want to either change the state or stay in the same state.

    Can you please let me know how I can execute this based on your code.

  2. ysden123 says:

    Hi Nats,
    thank you for question.
    In your question is missing relations between trigger events and states.
    I wrote a simple example with suggestions:
    Initial state is “start”.
    Event “tune” changes state from “start” to “tune”.
    Event “trick” changes state from “tune” to “trick”.
    Dummy conditions (“nothing”) are used.

    Following is code:
    object Test1 extends App {
    test1()

    def test1(): Unit = {
    println(“==>test1”)
    // Build state machine config
    var currentState: State = State(“start”)
    // Define inputs
    val tune = Input(“tune”, Map(“nothing” -> TextParameter(“nothing”)))
    val trick = Input(“trick”, Map(“nothing” -> TextParameter(“nothing”)))

    // Define conditions
    val tuneConditions = List(TransitionCondition(paramName = “nothing”,
    compareType = CompareType.Equal, expectedValue = TextParameter(“nothing”)))
    val trickConditions = List(TransitionCondition(paramName = “nothing”,
    compareType = CompareType.Equal, expectedValue = TextParameter(“nothing”)))

    // Define transitions
    val transitions = Vector(
    Transition(input = tune,
    priority = 0,
    sourceState = State(“start”),
    destinationState = State(“tune”),
    conditions = tuneConditions,
    aggregationType = ConditionAggregationType.One
    ),
    Transition(input = trick,
    priority = 0,
    sourceState = State(“tune”),
    destinationState = State(“trick”),
    conditions = trickConditions,
    aggregationType = ConditionAggregationType.One
    )
    )

    // Make tune
    Automaton.nextState(currentState, tune, transitions) match {
    case Some(x) =>
    currentState = x
    println(s”Current state is $x”)
    case x =>
    println(“No new state was found”)
    }

    // Make trick
    Automaton.nextState(currentState, trick, transitions) match {
    case Some(x) =>
    currentState = x
    println(s”Current state is $x”)
    case x =>
    println(“No new state was found”)
    }
    println(“<==test1")
    }

    }

    Hope this will help you.

  3. Nats says:

    Thank you so much for your reply. Is it possible to use custom class for input events AND outputs. I will get inputs sorted based on timestamp and based on the incoming event change the states and print the output.

    States:

    object MachineState extends Enumeration {
    type State = Value
    val TUNED, TRICK, NON-TUNED = Value
    }
    Input:
    case class InputEvent(eventType:String,startTime:Timestmap,inputId:String)

    Note: I have the list of valid eventTypes as ENUM.

    Output:
    case class Output(startEventType:String,endEventType:String,startTime:Timestamp,endTime:Timestamp)

    Let’s say at the start, machine is always in NON-TUNED state.

    if current State = “NON-TUNED” and InputEvent.eventType = PLAY or RE-PLAY or TUNE and
    go to TUNED state and Output(InputEvent.eventType,,InputEvent.starTime,) and hold this output some where so I can update the endEvent, endTime when the next valid event comes in.

    if current State = “TUNED” and InputEvent.eventType = PLAY and
    stay in TUNED state but emit the output

    if current State = “TUNED” and InputEvent.eventType = FAST FORWARD or PAUSE and
    go to TRICK state and

    if current State = “TUNED” and InputEvent.eventType = POWEROFF and
    go to NON-TUNED state and

    if current State = “TRICK” InputEvent.eventType = PLAY or RE-PLAY or TUNE and
    go to TUNED state and

    if current State = “TRICK” InputEvent.eventType = POWEROFF and
    go to NON-TUNED state and

    Example:
    Inputs: Batch1
    PLAY|20180118001420|ID1
    PAUSE|20180118001425|ID2
    PLAY|20180118001430|ID3
    POWEROFF|20180118001435|ID4
    PLAY|20180118001440|ID5

    Expected Output:
    PLAY|PAUSE|20180118001420|20180118001425
    PLAY|POWEROFF|20180118001430|20180118001435

    At end of batch1 machine will be TUNED state with the below ouput stored since the last event was PLAY event.
    PLAY|NULL|20180118001440|NULL

    Inputs: Batch2
    PLAY|20180118001445|ID6
    PAUSE|20180118001450|ID7

    Expected Output:
    PLAY|PLAY|20180118001440|20180118001445
    PLAY|PAUSE|20180118001445|20180118001450
    PAUSE|NULL|20180118001450|NULL

    At end of batch2 machine will be TRICK state since the last event was PAUSE event.

    Thanks in advance for your help.. I am trying to incorporate this state machine logic in spark streaming.

  4. ysden123 says:

    Hi Nats,
    feel free to fork this project. You may use it as start code and to change code for your requirements.
    It was my POC project during studying Scala. Unfortunately I don’t plan to upgrade code.

  5. Nats says:

    Thank you…

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.