179 lines
4.6 KiB
Java
179 lines
4.6 KiB
Java
/**
|
|
* Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
|
|
*/
|
|
|
|
package docs.actorlambda.fsm;
|
|
|
|
import akka.actor.*;
|
|
import akka.testkit.JavaTestKit;
|
|
import org.hamcrest.CoreMatchers;
|
|
import org.junit.AfterClass;
|
|
import org.junit.BeforeClass;
|
|
import org.junit.Test;
|
|
import scala.concurrent.duration.Duration;
|
|
|
|
import static org.junit.Assert.*;
|
|
|
|
import static docs.actorlambda.fsm.FSMDocTest.StateType.*;
|
|
import static docs.actorlambda.fsm.FSMDocTest.Messages.*;
|
|
import static java.util.concurrent.TimeUnit.*;
|
|
|
|
public class FSMDocTest {
|
|
static ActorSystem system;
|
|
|
|
@BeforeClass
|
|
public static void setup() {
|
|
system = ActorSystem.create("FSMDocTest");
|
|
}
|
|
|
|
@AfterClass
|
|
public static void tearDown() {
|
|
JavaTestKit.shutdownActorSystem(system);
|
|
system = null;
|
|
}
|
|
|
|
public static enum StateType {
|
|
SomeState,
|
|
Processing,
|
|
Idle,
|
|
Active,
|
|
Error
|
|
}
|
|
|
|
public static enum Messages {
|
|
WillDo,
|
|
Tick
|
|
}
|
|
|
|
public static enum Data {
|
|
Foo,
|
|
Bar
|
|
};
|
|
|
|
public static interface X {};
|
|
|
|
public static class DummyFSM extends AbstractFSM<StateType, Integer> {
|
|
Integer newData = 42;
|
|
//#alt-transition-syntax
|
|
public void handler(StateType from, StateType to) {
|
|
// handle transition here
|
|
}
|
|
|
|
//#alt-transition-syntax
|
|
{
|
|
//#modifier-syntax
|
|
when(SomeState, matchAnyEvent((msg, data) -> {
|
|
return goTo(Processing).using(newData).
|
|
forMax(Duration.create(5, SECONDS)).replying(WillDo);
|
|
}));
|
|
//#modifier-syntax
|
|
|
|
//#NullFunction
|
|
when(SomeState, AbstractFSM.NullFunction());
|
|
//#NullFunction
|
|
|
|
//#transition-syntax
|
|
onTransition(
|
|
matchState(Active, Idle, () -> setTimer("timeout",
|
|
Tick, Duration.create(1, SECONDS), true)).
|
|
state(Active, null, () -> cancelTimer("timeout")).
|
|
state(null, Idle, (f, t) -> log().info("entering Idle from " + f)));
|
|
//#transition-syntax
|
|
|
|
//#alt-transition-syntax
|
|
onTransition(this::handler);
|
|
//#alt-transition-syntax
|
|
|
|
//#stop-syntax
|
|
when(Error, matchEventEquals("stop", (event, data) -> {
|
|
// do cleanup ...
|
|
return stop();
|
|
}));
|
|
//#stop-syntax
|
|
|
|
//#termination-syntax
|
|
onTermination(
|
|
matchStop(Normal(),
|
|
(state, data) -> {/* Do something here */}).
|
|
stop(Shutdown(),
|
|
(state, data) -> {/* Do something here */}).
|
|
stop(Failure.class,
|
|
(reason, state, data) -> {/* Do something here */}));
|
|
//#termination-syntax
|
|
|
|
//#unhandled-syntax
|
|
whenUnhandled(
|
|
matchEvent(X.class, (x, data) -> {
|
|
log().info("Received unhandled event: " + x);
|
|
return stay();
|
|
}).
|
|
anyEvent((event, data) -> {
|
|
log().warning("Received unknown event: " + event);
|
|
return goTo(Error);
|
|
}));
|
|
}
|
|
//#unhandled-syntax
|
|
}
|
|
|
|
static
|
|
//#logging-fsm
|
|
public class MyFSM extends AbstractLoggingFSM<StateType, Data> {
|
|
//#body-elided
|
|
//#logging-fsm
|
|
ActorRef target = null;
|
|
//#logging-fsm
|
|
@Override
|
|
public int logDepth() { return 12; }
|
|
{
|
|
onTermination(
|
|
matchStop(Failure.class, (reason, state, data) -> {
|
|
String lastEvents = getLog().mkString("\n\t");
|
|
log().warning("Failure in state " + state + " with data " + data + "\n" +
|
|
"Events leading up to this point:\n\t" + lastEvents);
|
|
//#logging-fsm
|
|
target.tell(reason.cause(), self());
|
|
target.tell(state, self());
|
|
target.tell(data, self());
|
|
target.tell(lastEvents, self());
|
|
//#logging-fsm
|
|
})
|
|
);
|
|
//...
|
|
//#logging-fsm
|
|
startWith(SomeState, Data.Foo);
|
|
when(SomeState, matchEvent(ActorRef.class, Data.class, (ref, data) -> {
|
|
target = ref;
|
|
target.tell("going active", self());
|
|
return goTo(Active);
|
|
}));
|
|
when(Active, matchEventEquals("stop", (event, data) -> {
|
|
target.tell("stopping", self());
|
|
return stop(new Failure("This is not the error you're looking for"));
|
|
}));
|
|
initialize();
|
|
//#logging-fsm
|
|
}
|
|
//#body-elided
|
|
}
|
|
//#logging-fsm
|
|
|
|
@Test
|
|
public void testLoggingFSM()
|
|
{
|
|
new JavaTestKit(system) {{
|
|
final ActorRef logger =
|
|
system.actorOf(Props.create(MyFSM.class));
|
|
final ActorRef probe = getRef();
|
|
|
|
logger.tell(probe, probe);
|
|
expectMsgEquals("going active");
|
|
logger.tell("stop", probe);
|
|
expectMsgEquals("stopping");
|
|
expectMsgEquals("This is not the error you're looking for");
|
|
expectMsgEquals(Active);
|
|
expectMsgEquals(Data.Foo);
|
|
String msg = expectMsgClass(String.class);
|
|
assertTrue(msg.startsWith("LogEntry(SomeState,Foo,Actor[akka://FSMDocTest/system/"));
|
|
}};
|
|
}
|
|
}
|