State refactor

This commit is contained in:
momania 2010-07-20 09:53:57 +02:00
parent f7d5315d24
commit 9687bf829e
2 changed files with 29 additions and 14 deletions

View file

@ -5,17 +5,17 @@ import se.scalablesolutions.akka.actor.{ActorRef, Scheduler, Actor}
trait Fsm[S] { self: Actor =>
type State = scala.PartialFunction[Event, NextState]
type StateFunction = scala.PartialFunction[Event, State]
@volatile var currentState: NextState = initialState
@volatile var currentState: State = initialState
@volatile var timeoutActor: Option[ActorRef] = None
def initialState: NextState
def initialState: State
def handleEvent: State = {
def handleEvent: StateFunction = {
case event@Event(value,stateData) =>
log.warning("No state for event with value %s - keeping current state %s", value, stateData)
NextState(currentState.state, stateData, currentState.timeout)
State(NextState, currentState.stateFunction, stateData, currentState.timeout)
}
@ -24,15 +24,30 @@ trait Fsm[S] { self: Actor =>
timeoutActor = timeoutActor flatMap { ref => Scheduler.unschedule(ref); None }
val event = Event(value, currentState.stateData)
currentState = (currentState.state orElse handleEvent).apply(event)
currentState = (currentState.stateFunction orElse handleEvent).apply(event)
currentState.timeout.foreach{timeout =>
timeoutActor = Some(Scheduler.scheduleOnce(this.self, StateTimeout, timeout, TimeUnit.MILLISECONDS))
}
currentState match {
case State(Reply, _, _, _, reply) => reply.foreach(this.self.reply)
}
}
}
case class NextState(state: State, stateData: S, timeout: Option[Int] = None)
case class State(stateEvent: StateEvent,
stateFunction: StateFunction,
stateData: S,
timeout: Option[Int] = None,
reply: Option[Any] =None)
case class Event(event: Any, stateData: S)
sealed trait StateEvent
object NextState extends StateEvent
object Reply extends StateEvent
object StateTimeout
}

View file

@ -17,29 +17,29 @@ object FsmActorSpec {
unlockedLatch: StandardLatch,
lockedLatch: StandardLatch) extends Actor with Fsm[CodeState] {
def initialState = NextState(locked, CodeState("", "33221"))
def initialState = State(NextState, locked, CodeState("", "33221"))
def locked: State = {
def locked: StateFunction = {
case Event(digit: Char, CodeState(soFar, code)) => {
soFar + digit match {
case incomplete if incomplete.length < code.length =>
NextState(locked, CodeState(incomplete, code))
State(NextState, locked, CodeState(incomplete, code))
case codeTry if (codeTry == code) => {
doUnlock
new NextState(open, CodeState("", code), Some(timeout))
new State(NextState, open, CodeState("", code), Some(timeout))
}
case wrong => {
log.error("Wrong code %s", wrong)
NextState(locked, CodeState("", code))
State(NextState, locked, CodeState("", code))
}
}
}
}
def open: State = {
def open: StateFunction = {
case Event(StateTimeout, stateData) => {
doLock
NextState(locked, stateData)
State(NextState, locked, stateData)
}
}