public interface FSM<S,D> extends Actor, Listeners, ActorLogging
object A { trait State case class One extends State case class Two extends State case class Data(i : Int) } class A extends Actor with FSM[A.State, A.Data] { import A._ startWith(One, Data(42)) when(One) { case Event(SomeMsg, Data(x)) => ... case Ev(SomeMsg) => ... // convenience when data not needed } when(Two, stateTimeout = 5 seconds) { ... } initialize() }
Within the partial function the following values are returned for effecting state transitions:
- stay
for staying in the same state
- stay using Data(...)
for staying in the same state, but with
different data
- stay forMax 5.millis
for staying with a state timeout; can be
combined with using
- goto(...)
for changing into a different state; also supports
using
and forMax
- stop
for terminating this FSM actor
Each of the above also supports the method replying(AnyRef)
for
sending a reply before changing state.
While changing state, custom handlers may be invoked which are registered
using onTransition
. This is meant to enable concentrating
different concerns in different places; you may choose to use
when
for describing the properties of a state, including of
course initiating transitions, but you can describe the transitions using
onTransition
to avoid having to duplicate that code among
multiple paths which lead to a transition:
onTransition { case Active -> _ => cancelTimer("activeTimer") }
Multiple such blocks are supported and all of them will be called, not only the first matching one.
Another feature is that other actors may subscribe for transition events by
sending a SubscribeTransitionCallback
message to this actor.
Stopping a listener without unregistering will not remove the listener from the
subscription list; use UnsubscribeTransitionCallback
before stopping
the listener.
State timeouts set an upper bound to the time which may pass before another message is received in the current state. If no external message is available, then upon expiry of the timeout a StateTimeout message is sent. Note that this message will only be received in the state for which the timeout was set and that any message received will cancel the timeout (possibly to be started again by the next transition).
Another feature is the ability to install and cancel single-shot as well as repeated timers which arrange for the sending of a user-specified message:
setTimer("tock", TockMsg, 1 second, true) // repeating setTimer("lifetime", TerminateMsg, 1 hour, false) // single-shot cancelTimer("tock") isTimerActive("tock")
Modifier and Type | Interface and Description |
---|---|
static class |
FSM.$minus$greater$
This extractor is just convenience for matching a (S, S) pair, including a
reminder what the new state is.
|
static class |
FSM.CurrentState<S>
Message type which is sent directly to the subscribed actor in
FSM.SubscribeTransitionCallBack before sending any
FSM.Transition messages. |
static class |
FSM.CurrentState$ |
static class |
FSM.Event<D>
All messages sent to the
FSM will be wrapped inside an
Event , which allows pattern matching to extract both state and data. |
static class |
FSM.Event$ |
static class |
FSM.Failure
Signifies that the
FSM is shutting itself down because of
an error, e.g. |
static class |
FSM.Failure$ |
static class |
FSM.LogEntry<S,D>
Log Entry of the
LoggingFSM , can be obtained by calling getLog . |
static class |
FSM.LogEntry$ |
static class |
FSM.Normal$
Default reason if calling
stop() . |
static class |
FSM.NullFunction$
A partial function value which does not match anything and can be used to
“reset”
whenUnhandled and onTermination handlers. |
static interface |
FSM.Reason
Reason why this
FSM is shutting down. |
static class |
FSM.Shutdown$
Reason given when someone was calling
system.stop(fsm) from outside;
also applies to Stop supervision directive. |
static class |
FSM.SilentState<S,D>
INTERNAL API
Using a subclass for binary compatibility reasons
|
static class |
FSM.State<S,D>
This captures all of the managed state of the
FSM : the state
name, the state data, possibly custom timeout, stop reason and replies
accumulated while processing the last message. |
static class |
FSM.State$ |
static class |
FSM.StateTimeout$
This case object is received in case of a state timeout.
|
static class |
FSM.StopEvent<S,D>
Case class representing the state of the
FSM within the
onTermination block. |
static class |
FSM.StopEvent$ |
static class |
FSM.SubscribeTransitionCallBack
Send this to an
FSM to request first the FSM.CurrentState
and then a series of FSM.Transition updates. |
static class |
FSM.SubscribeTransitionCallBack$ |
static class |
FSM.TimeoutMarker
INTERNAL API
|
static class |
FSM.TimeoutMarker$ |
static class |
FSM.Timer
INTERNAL API
|
static class |
FSM.Timer$ |
static class |
FSM.TransformHelper |
static class |
FSM.Transition<S>
Message type which is used to communicate transitions between states to
all subscribed listeners (use
FSM.SubscribeTransitionCallBack ). |
static class |
FSM.Transition$ |
static class |
FSM.UnsubscribeTransitionCallBack
Unsubscribe from
FSM.Transition notifications which was
effected by sending the corresponding FSM.SubscribeTransitionCallBack . |
static class |
FSM.UnsubscribeTransitionCallBack$ |
Actor.emptyBehavior$, Actor.ignoringBehavior$
Modifier and Type | Method and Description |
---|---|
void |
applyState(FSM.State<S,D> nextState) |
void |
cancelTimer(java.lang.String name) |
boolean |
debugEvent() |
FSM.Event$ |
Event() |
void |
handleTransition(S prev,
S next) |
void |
initialize() |
boolean |
isStateTimerActive() |
boolean |
isTimerActive(java.lang.String name) |
void |
logTermination(FSM.Reason reason)
By default
FSM.Failure is logged at error level and other reason
types are not logged. |
void |
makeTransition(FSM.State<S,D> nextState) |
D |
nextStateData() |
void |
onTermination(scala.PartialFunction<FSM.StopEvent<S,D>,scala.runtime.BoxedUnit> terminationHandler) |
void |
onTransition(scala.PartialFunction<scala.Tuple2<S,S>,scala.runtime.BoxedUnit> transitionHandler) |
void |
postStop()
User overridable callback.
|
void |
processEvent(FSM.Event<D> event,
java.lang.Object source) |
void |
processMsg(java.lang.Object value,
java.lang.Object source) |
scala.PartialFunction<java.lang.Object,scala.runtime.BoxedUnit> |
receive()
This defines the initial actor behavior, it must return a partial function
with the actor logic.
|
void |
register(S name,
scala.PartialFunction<FSM.Event<D>,FSM.State<S,D>> function,
scala.Option<scala.concurrent.duration.FiniteDuration> timeout) |
void |
setStateTimeout(S state,
scala.Option<scala.concurrent.duration.FiniteDuration> timeout) |
void |
setTimer(java.lang.String name,
java.lang.Object msg,
scala.concurrent.duration.FiniteDuration timeout,
boolean repeat) |
void |
startWith(S stateName,
D stateData,
scala.Option<scala.concurrent.duration.FiniteDuration> timeout)
Set initial state.
|
D |
stateData() |
S |
stateName() |
FSM.StateTimeout$ |
StateTimeout()
This case object is received in case of a state timeout.
|
FSM.State<S,D> |
stay()
Produce "empty" transition descriptor.
|
FSM.State<S,D> |
stop()
Produce change descriptor to stop this FSM actor with reason "Normal".
|
FSM.State<S,D> |
stop(FSM.Reason reason)
Produce change descriptor to stop this FSM actor including specified reason.
|
FSM.State<S,D> |
stop(FSM.Reason reason,
D stateData)
Produce change descriptor to stop this FSM actor including specified reason.
|
FSM.StopEvent$ |
StopEvent() |
void |
terminate(FSM.State<S,D> nextState) |
scala.PartialFunction<scala.Tuple2<S,S>,scala.runtime.BoxedUnit> |
total2pf(scala.Function2<S,S,scala.runtime.BoxedUnit> transitionHandler) |
FSM.TransformHelper |
transform(scala.PartialFunction<FSM.Event<D>,FSM.State<S,D>> func) |
void |
when(S stateName,
scala.concurrent.duration.FiniteDuration stateTimeout,
scala.PartialFunction<FSM.Event<D>,FSM.State<S,D>> stateFunction)
Insert a new StateFunction at the end of the processing chain for the
given state.
|
void |
whenUnhandled(scala.PartialFunction<FSM.Event<D>,FSM.State<S,D>> stateFunction) |
aroundPostRestart, aroundPostStop, aroundPreRestart, aroundPreStart, aroundReceive, context, postRestart, preRestart, preStart, self, sender, supervisorStrategy, unhandled
gossip, listenerManagement, listeners
log
FSM.Event$ Event()
FSM.StopEvent$ StopEvent()
FSM.StateTimeout$ StateTimeout()
void when(S stateName, scala.concurrent.duration.FiniteDuration stateTimeout, scala.PartialFunction<FSM.Event<D>,FSM.State<S,D>> stateFunction)
stateName
- designator for the statestateTimeout
- default state timeout for this statestateFunction
- partial function describing response to inputvoid startWith(S stateName, D stateData, scala.Option<scala.concurrent.duration.FiniteDuration> timeout)
initialize()
method.
If different state is needed after a restart this method, followed by initialize()
, can
be used in the actor life cycle hooks Actor.preStart()
and Actor.postRestart(java.lang.Throwable)
.
stateName
- initial state designatorstateData
- initial state datatimeout
- state timeout for the initial state, overriding the default timeout for that stateFSM.State<S,D> stay()
No transition event will be triggered by stay()
.
If you want to trigger an event like S -> S
for onTransition
to handle use goto
instead.
FSM.State<S,D> stop()
FSM.State<S,D> stop(FSM.Reason reason)
reason
- (undocumented)FSM.State<S,D> stop(FSM.Reason reason, D stateData)
reason
- (undocumented)stateData
- (undocumented)void setTimer(java.lang.String name, java.lang.Object msg, scala.concurrent.duration.FiniteDuration timeout, boolean repeat)
void cancelTimer(java.lang.String name)
boolean isTimerActive(java.lang.String name)
void setStateTimeout(S state, scala.Option<scala.concurrent.duration.FiniteDuration> timeout)
boolean isStateTimerActive()
void onTransition(scala.PartialFunction<scala.Tuple2<S,S>,scala.runtime.BoxedUnit> transitionHandler)
scala.PartialFunction<scala.Tuple2<S,S>,scala.runtime.BoxedUnit> total2pf(scala.Function2<S,S,scala.runtime.BoxedUnit> transitionHandler)
void onTermination(scala.PartialFunction<FSM.StopEvent<S,D>,scala.runtime.BoxedUnit> terminationHandler)
void initialize()
S stateName()
D stateData()
D nextStateData()
boolean debugEvent()
void register(S name, scala.PartialFunction<FSM.Event<D>,FSM.State<S,D>> function, scala.Option<scala.concurrent.duration.FiniteDuration> timeout)
scala.PartialFunction<java.lang.Object,scala.runtime.BoxedUnit> receive()
Actor
void processMsg(java.lang.Object value, java.lang.Object source)
void postStop()
Actor
void logTermination(FSM.Reason reason)
FSM.Failure
is logged at error level and other reason
types are not logged. It is possible to override this behavior.reason
- (undocumented)