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
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.
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.
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.
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.
Thank you…