Scala with FSM

Jul - 15 2016 | By

FSM stands for Finite State Machine.

Lets break this down,

State : State is a description of the status of a system that is waiting to execute a transition. A transition is a set of actions to be executed when a condition is fulfilled or when an event is received.

Its the best way to describe it.

 

lets have a look at a sample i wrote

 

package test
import akka.actor.{Props, ActorSystem, FSM}
import akka.persistence.fsm.PersistentFSM.FSMState
import akka.testkit.{ImplicitSender, TestKit}
import org.scalatest.{Matchers, FlatSpecLike, BeforeAndAfterAll}


//States
sealed trait CarState extends FSMState
case class Driving() extends CarState {override def identifier: String = "Driving"}
case class Parked() extends CarState {override def identifier: String = "Parked"}
case class Crashed() extends CarState {override def identifier: String = "Crashed"}
case class BeingRepaired() extends CarState {override def identifier: String = "BeingRepaired"}


//Data
sealed trait CarEntity {
  var carType: String
  var carModel: String
  var yearOfManufactor: String
}
case object UnInitialized extends CarEntity {
  var carType = ""
  var carModel = ""
  var yearOfManufactor = ""
}
case object VWGolf extends CarEntity {
  override var carType: String = "VW"
  override var carModel: String = "GOLF"
  override var yearOfManufactor: String = "2016"
}


class Car(carDetails : CarEntity) extends FSM[CarState, CarEntity]
{
  startWith(Parked(), carDetails)

  //When we are Parked, we can only go Driving or BeingRepaired
when(Parked()){
    case Event(event: Driving,_) => //"_" is the Data part of the event
      goto(event)
    case Event(event: BeingRepaired,_) =>
      goto(event)
  }

  when(Driving()){
    case Event(event: Parked,_) =>
      goto(event)
    case Event(event: Crashed,_) =>
      println("We just crashed!!!")
      goto(event)
  }
  when(Crashed()){
    case Event(event: BeingRepaired,_) =>
      goto(event)
  }

 //for capturing all state transactions  onTransition { case (fromState, toState) => { if (fromState != toState) { val oldData = stateData val newData = nextStateData println(s"$fromState -> $toState") } } }
  whenUnhandled {
    case Event(event, state) =>
      println(s"We cannot go from $stateName, to state $event (data = $stateData)")
      stay
  }
initialize()
}


class CarTestSpec extends TestKit(ActorSystem("CarTestSpec"))
  with ImplicitSender
  with FlatSpecLike
  with Matchers
  with BeforeAndAfterAll
{
  behavior of "CarTestSpec"
  it should "should validate correct FSM transaction" in {

    val vwGolf = system.actorOf(Props(new Car(VWGolf)))
    vwGolf ! Driving()
    vwGolf ! Parked()
    vwGolf ! Crashed()
    vwGolf ! Driving()
    vwGolf ! Crashed()
    expectNoMsg()
  }

  override def afterAll {
    TestKit.shutdownActorSystem(system)
  }

}

 

The following test prints out

Parked() -> Driving()
Driving() -> Parked()
We cannot go from Parked(), to state Crashed() (data = VWGolf)
Parked() -> Driving()
We just crashed!!!
Driving() -> Crashed()

 

 

Of course we could very easily attached data to each state transition like  “total mile travel” or something like that, and update the car object in this class at each transition.

Comments are closed. Please see front page on how to contact me