Akka Java FSM as an example

Please note: I am a Java developer who does not have knowledge of Scala (unfortunately). I would like to ask that any code examples provided in the answer will use the Akka Java API.

I am trying to use the Akka FSM API to simulate the next super-simple automaton. In fact, my car is much more complicated, but the answer to this question will allow me to extrapolate my actual FSM.

enter image description here

And so I have 2 states: Off and On . You can go Off -> On by turning on the machine by calling SomeObject#powerOn(<someArguments>) . You can go from On -> Off by turning off the machine by calling SomeObject#powerOff(<someArguments>) .

I wonder what actors and supporting classes I will need to implement this FSM. I believe that an actor representing FSM should extend AbstractFSM . But which classes are 2 states? What code provides and implements state transitions powerOn(...) and powerOff(...) ? A working Java example or even a simple Java pseudo code would be long for me here.

+8
java actor akka fsm
source share
2 answers

I think we can do a little better than copypasta from FSM docs ( http://doc.akka.io/docs/akka/snapshot/java/lambda-fsm.html ). First, study your use case a little.

You have two triggers (or events or signals) - powerOn and powerOff. You would like to send these signals to the Actor and change his state, of which two significant states are turned on and off.

Now, strictly speaking, FSM needs another component: the action you want to take to transition.

 FSM: State (S) x Event (E) -> Action (A), State (S') Read: "When in state S, if signal E is received, produce action A and advance to state S'" 

You DO NOT NEED any action, but the actor cannot be directly examined or changed. All mutation and confirmation occur through asynchronous messaging.

In your example, which does not give any action to go to the transition, you basically have a state machine that does not work. Actions occur, state transitions without a side effect, and this state is invisible, so the working machine is identical to a broken one. And since all this happens asynchronously, you don’t even know when the broken thing ended.

So let me expand your contract a bit and include the following definitions in the FSM definitions:

  When in Off, if powerOn is received, advance state to On and respond to the caller with the new state When in On, if powerOff is received, advance state to Off and respond to the caller with the new state 

Now we could create an FSM that can actually be verified.

Define a couple of classes for your two signals. (AbstractFSM DSL expects a class match):

 public static class PowerOn {} public static class PowerOff {} 

Define a pair of enumerations for your two states:

  enum LightswitchState { on, off } 

Define the AbstractFSM actor ( http://doc.akka.io/japi/akka/2.3.8/akka/actor/AbstractFSM.html ). The AbstractFSM extension allows us to define an actor using a chain of FSM definitions similar to the above, rather than defining the behavior of the message directly in the onReceive () method. It provides a nice little DSL for these definitions and (somewhat bizarrely) expects the definitions to be installed in a static initializer.

A quick detour: AbstractFSM has two generic files that are used to provide compile-time type checking.

S is the base of the state types we want to use, and D is the database of data types. If you are creating an FSM that will hold and modify data (maybe a power meter for your lighting switch?), You should create a separate class to store this data, and not try to add new members to your AbstractFSM subclass. Since we have no data, let's define a dummy class so you can see how it goes:

 public static class NoDataItsJustALightswitch {} 

So, from this point of view, we can build a class of our actor.

 public class Lightswitch extends AbstractFSM<LightswitchState, NoDataItsJustALightswitch> { { //static initializer startWith(off, new NoDataItsJustALightswitch()); //okay, we're saying that when a new Lightswitch is born, it'll be in the off state and have a new NoDataItsJustALightswitch() object as data //our first FSM definition when(off, //when in off, matchEvent(PowerOn.class, //if we receive a PowerOn message, NoDataItsJustALightswitch.class, //and have data of this type, (powerOn, noData) -> //we'll handle it using this function: goTo(on) //go to the on state, .replying(on); //and reply to the sender that we went to the on state ) ); //our second FSM definition when(on, matchEvent(PowerOff.class, NoDataItsJustALightswitch.class, (powerOn, noData) -> { goTo(off) .replying(off); //here you could use multiline functions, //and use the contents of the event (powerOn) or data (noData) to make decisions, alter content of the state, etc. } ) ); initialize(); //boilerplate } } 

I'm sure you are wondering: how can I use this ?! So give you a test harness using the direct JUnit and Akka Testkit for java:

 public class LightswitchTest { @Test public void testLightswitch() { ActorSystem system = ActorSystem.create("lightswitchtest");//should make this static if you're going to test a lot of things, actor systems are a bit expensive new JavaTestKit(system) {{ //there that static initializer again ActorRef lightswitch = system.actorOf(Props.create(Lightswitch.class)); //here is our lightswitch. It an actor ref, a reference to an actor that will be created on //our behalf of type Lightswitch. We can't, as mentioned earlier, actually touch the instance //of Lightswitch, but we can send messages to it via this reference. lightswitch.tell( //using the reference to our actor, tell it new PowerOn(), //to "Power On," using our message type getRef()); //and giving it an actor to call back (in this case, the JavaTestKit itself) //because it is asynchronous, the tell will return immediately. Somewhere off in the distance, on another thread, our lightbulb is receiving its message expectMsgEquals(LightswitchState.on); //we block until the lightbulb sends us back a message with its current state ("on.") //If our actor is broken, this call will timeout and fail. lightswitch.tell(new PowerOff(), getRef()); expectMsgEquals(LightswitchState.off); system.stop(lightswitch); //switch works, kill the instance, leave the system up for further use }}; } } 

And here you are: the FSM indicator light. Honestly, the example, this trivial one, does not really show the power of FSM, since the dataless example can be executed as a set of “become / unsafe” actions in half of the LoC without generics or lambda. Much more readable IMO.

PS consider learning Scala, if only you can read the code of other nations! The first half of Atomic Scala is available free online.

PPS, if all you really need is a compiled state machine, I support Pulleys , a state machine mechanism based on pure Java statecharts. This has been going on for many years (a lot of XML and old templates, without DI integration), but if you really want to separate the state machine implementation from the inputs and outputs, there might be some inspiration.

+17
source share

I know about the actors in Scala.
This Java startup code can help you:

Yes, extend SimpleFSM from AbstractFSM .
The enum state in AbstractFSM .
Your <someArguments> may be part of the Data in your AbstractFSM
Your powerOn and powerOff are actor messages / events. And state switching occurs in Part transitions

 // states enum State { Off, On } enum Uninitialized implements Data { Uninitialized } public class SimpleFSM extends AbstractFSM<State, Data> { { // fsm body startWith(Off, Uninitialized); // transitions when(Off, matchEvent(... .class ..., (... Variable Names ...) -> goTo(On).using(...) ); // powerOn(<someArguments>) when(On, matchEvent(... .class ..., (... Variable Names ...) -> goTo(Off).using(...) ); // powerOff(<someArguments>) initialize(); } } 

Real working project see

Scala and Java 8 with Lambda pattern for Akka AbstractFSM

+2
source share

All Articles