!act,doc #3831 Adding more Java with Lambda documentation and support
* The Java with Lambda support documentation for AbstractActor and AbstractFSM are now on par with Scala * Many small fixes and additions of missing things * Added an AbstractActorContext that has convenience functions for getChild and getChildren
This commit is contained in:
parent
8396e923cf
commit
0dcb6d6654
34 changed files with 2494 additions and 211 deletions
17
akka-samples/akka-docs-java-lambda/build.sbt
Normal file
17
akka-samples/akka-docs-java-lambda/build.sbt
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
name := "akka-docs-java-lambda"
|
||||
|
||||
version := "2.3-SNAPSHOT"
|
||||
|
||||
scalaVersion := "2.10.3"
|
||||
|
||||
compileOrder := CompileOrder.ScalaThenJava
|
||||
|
||||
javacOptions ++= Seq("-source", "1.8", "-target", "1.8", "-Xlint")
|
||||
|
||||
testOptions += Tests.Argument(TestFrameworks.JUnit, "-v", "-a")
|
||||
|
||||
libraryDependencies ++= Seq(
|
||||
"com.typesafe.akka" %% "akka-actor" % "2.3-SNAPSHOT",
|
||||
"com.typesafe.akka" %% "akka-testkit" % "2.3-SNAPSHOT" % "test",
|
||||
"junit" % "junit" % "4.11" % "test",
|
||||
"com.novocode" % "junit-interface" % "0.10" % "test")
|
||||
53
akka-samples/akka-docs-java-lambda/pom.xml
Normal file
53
akka-samples/akka-docs-java-lambda/pom.xml
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
|
||||
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<groupId>sample</groupId>
|
||||
<artifactId>akka-docs-java-lambda</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>2.3-SNAPSHOT</version>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.typesafe.akka</groupId>
|
||||
<artifactId>akka-actor_2.10</artifactId>
|
||||
<version>2.3-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.typesafe.akka</groupId>
|
||||
<artifactId>akka-testkit_2.10</artifactId>
|
||||
<version>2.3-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.1</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
<fork>true</fork>
|
||||
<compilerArgs>
|
||||
<arg>-Xlint</arg>
|
||||
</compilerArgs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
|
@ -0,0 +1 @@
|
|||
sbt.version=0.13.1
|
||||
|
|
@ -0,0 +1,561 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package docs.actor;
|
||||
|
||||
import akka.actor.*;
|
||||
import akka.event.LoggingAdapter;
|
||||
import akka.event.Logging;
|
||||
import akka.japi.pf.ReceiveBuilder;
|
||||
import scala.PartialFunction;
|
||||
import scala.runtime.BoxedUnit;
|
||||
import static docs.actor.Messages.Swap.Swap;
|
||||
import static docs.actor.Messages.*;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import akka.testkit.JavaTestKit;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
//#import-props
|
||||
import akka.actor.Props;
|
||||
//#import-props
|
||||
//#import-actorRef
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.ActorSystem;
|
||||
//#import-actorRef
|
||||
//#import-identify
|
||||
import akka.actor.ActorIdentity;
|
||||
import akka.actor.ActorSelection;
|
||||
import akka.actor.Identify;
|
||||
//#import-identify
|
||||
//#import-graceFulStop
|
||||
import akka.pattern.AskTimeoutException;
|
||||
import scala.concurrent.Await;
|
||||
import scala.concurrent.duration.Duration;
|
||||
import scala.concurrent.Future;
|
||||
import static akka.pattern.Patterns.gracefulStop;
|
||||
//#import-graceFulStop
|
||||
|
||||
public class ActorDocTest {
|
||||
|
||||
static ActorSystem system = null;
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
system = ActorSystem.create("ActorDocTest");
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() {
|
||||
system.shutdown();
|
||||
system.awaitTermination(Duration.create("5 seconds"));
|
||||
}
|
||||
|
||||
static
|
||||
//#context-actorOf
|
||||
public class FirstActor extends AbstractActor {
|
||||
final ActorRef child = context().actorOf(Props.create(MyActor.class), "myChild");
|
||||
//#plus-some-behavior
|
||||
@Override
|
||||
public PartialFunction<Object, BoxedUnit> receive() {
|
||||
return ReceiveBuilder.
|
||||
matchAny(x -> {
|
||||
sender().tell(x, self());
|
||||
}).build();
|
||||
}
|
||||
//#plus-some-behavior
|
||||
}
|
||||
//#context-actorOf
|
||||
|
||||
static public abstract class ReceiveActor extends AbstractActor {
|
||||
@Override
|
||||
//#receive
|
||||
public abstract PartialFunction<Object, BoxedUnit> receive();
|
||||
//#receive
|
||||
}
|
||||
|
||||
static public class ActorWithArgs extends AbstractActor {
|
||||
private final String args;
|
||||
|
||||
ActorWithArgs(String args) {
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PartialFunction<Object, BoxedUnit> receive() {
|
||||
return ReceiveBuilder.
|
||||
matchAny(x -> { }).build();
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
//#props-factory
|
||||
public class DemoActor extends AbstractActor {
|
||||
/**
|
||||
* Create Props for an actor of this type.
|
||||
* @param magicNumber The magic number to be passed to this actor’s constructor.
|
||||
* @return a Props for creating this actor, which can then be further configured
|
||||
* (e.g. calling `.withDispatcher()` on it)
|
||||
*/
|
||||
static Props props(Integer magicNumber) {
|
||||
// You need to specify the actual type of the returned actor
|
||||
// since Java 8 lambdas have some runtime type information erased
|
||||
return Props.create(DemoActor.class, () -> new DemoActor(magicNumber));
|
||||
}
|
||||
|
||||
private final Integer magicNumber;
|
||||
|
||||
DemoActor(Integer magicNumber) {
|
||||
this.magicNumber = magicNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PartialFunction<Object, BoxedUnit> receive() {
|
||||
return ReceiveBuilder.
|
||||
match(Integer.class, i -> {
|
||||
sender().tell(i + magicNumber, self());
|
||||
}).build();
|
||||
}
|
||||
}
|
||||
|
||||
//#props-factory
|
||||
static
|
||||
//#props-factory
|
||||
public class SomeOtherActor extends AbstractActor {
|
||||
// Props(new DemoActor(42)) would not be safe
|
||||
ActorRef demoActor = context().actorOf(DemoActor.props(42), "demo");
|
||||
// ...
|
||||
//#props-factory
|
||||
@Override
|
||||
public PartialFunction<Object, BoxedUnit> receive() {
|
||||
return emptyBehavior();
|
||||
}
|
||||
//#props-factory
|
||||
}
|
||||
//#props-factory
|
||||
|
||||
public static class Hook extends AbstractActor {
|
||||
ActorRef target = null;
|
||||
//#preStart
|
||||
@Override
|
||||
public void preStart() {
|
||||
target = context().actorOf(Props.create(MyActor.class, "target"));
|
||||
}
|
||||
//#preStart
|
||||
public PartialFunction<Object, BoxedUnit> receive() {
|
||||
return emptyBehavior();
|
||||
}
|
||||
//#postStop
|
||||
@Override
|
||||
public void postStop() {
|
||||
//#clean-up-some-resources
|
||||
final String message = "stopped";
|
||||
//#tell
|
||||
// don’t forget to think about who is the sender (2nd argument)
|
||||
target.tell(message, self());
|
||||
//#tell
|
||||
final Object result = "";
|
||||
//#forward
|
||||
target.forward(result, context());
|
||||
//#forward
|
||||
target = null;
|
||||
//#clean-up-some-resources
|
||||
}
|
||||
//#postStop
|
||||
|
||||
// compilation test only
|
||||
public void compileSelections() {
|
||||
//#selection-local
|
||||
// will look up this absolute path
|
||||
context().actorSelection("/user/serviceA/actor");
|
||||
// will look up sibling beneath same supervisor
|
||||
context().actorSelection("../joe");
|
||||
//#selection-local
|
||||
|
||||
//#selection-wildcard
|
||||
// will look all children to serviceB with names starting with worker
|
||||
context().actorSelection("/user/serviceB/worker*");
|
||||
// will look up all siblings beneath same supervisor
|
||||
context().actorSelection("../*");
|
||||
//#selection-wildcard
|
||||
|
||||
//#selection-remote
|
||||
context().actorSelection("akka.tcp://app@otherhost:1234/user/serviceB");
|
||||
//#selection-remote
|
||||
}
|
||||
}
|
||||
|
||||
public static class ReplyException extends AbstractActor {
|
||||
@Override
|
||||
public PartialFunction<Object, BoxedUnit> receive() {
|
||||
return ReceiveBuilder.
|
||||
matchAny(x -> {
|
||||
//#reply-exception
|
||||
try {
|
||||
String result = operation();
|
||||
sender().tell(result, self());
|
||||
} catch (Exception e) {
|
||||
sender().tell(new akka.actor.Status.Failure(e), self());
|
||||
throw e;
|
||||
}
|
||||
//#reply-exception
|
||||
}).build();
|
||||
}
|
||||
|
||||
private String operation() {
|
||||
return "Hi";
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
//#gracefulStop-actor
|
||||
public class Manager extends AbstractActor {
|
||||
private static enum Shutdown {
|
||||
Shutdown
|
||||
}
|
||||
public static final Shutdown SHUTDOWN = Shutdown.Shutdown;
|
||||
|
||||
private ActorRef worker =
|
||||
context().watch(context().actorOf(Props.create(Cruncher.class), "worker"));
|
||||
|
||||
@Override
|
||||
public PartialFunction<Object, BoxedUnit> receive() {
|
||||
return ReceiveBuilder.
|
||||
matchEquals("job", s -> {
|
||||
worker.tell("crunch", self());
|
||||
}).
|
||||
matchEquals(SHUTDOWN, x -> {
|
||||
worker.tell(PoisonPill.getInstance(), self());
|
||||
context().become(shuttingDown);
|
||||
}).build();
|
||||
}
|
||||
|
||||
public PartialFunction<Object, BoxedUnit> shuttingDown =
|
||||
ReceiveBuilder.
|
||||
matchEquals("job", s -> {
|
||||
sender().tell("service unavailable, shutting down", self());
|
||||
}).
|
||||
match(Terminated.class, t -> t.actor().equals(worker), t -> {
|
||||
context().stop(self());
|
||||
}).build();
|
||||
}
|
||||
//#gracefulStop-actor
|
||||
|
||||
@Test
|
||||
public void usePatternsGracefulStop() throws Exception {
|
||||
ActorRef actorRef = system.actorOf(Props.create(Manager.class));
|
||||
//#gracefulStop
|
||||
try {
|
||||
Future<Boolean> stopped =
|
||||
gracefulStop(actorRef, Duration.create(5, TimeUnit.SECONDS), Manager.SHUTDOWN);
|
||||
Await.result(stopped, Duration.create(6, TimeUnit.SECONDS));
|
||||
// the actor has been stopped
|
||||
} catch (AskTimeoutException e) {
|
||||
// the actor wasn't stopped within 5 seconds
|
||||
}
|
||||
//#gracefulStop
|
||||
}
|
||||
|
||||
|
||||
public static class Cruncher extends AbstractActor {
|
||||
@Override
|
||||
public PartialFunction<Object, BoxedUnit> receive() {
|
||||
return ReceiveBuilder.
|
||||
matchEquals("crunch", s -> { }).build();
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
//#swapper
|
||||
public class Swapper extends AbstractActor {
|
||||
final LoggingAdapter log = Logging.getLogger(context().system(), this);
|
||||
|
||||
@Override
|
||||
public PartialFunction<Object, BoxedUnit> receive() {
|
||||
return ReceiveBuilder.
|
||||
matchEquals(Swap, s -> {
|
||||
log.info("Hi");
|
||||
context().become(ReceiveBuilder.
|
||||
matchEquals(Swap, x -> {
|
||||
log.info("Ho");
|
||||
context().unbecome(); // resets the latest 'become' (just for fun)
|
||||
}).build(), false); // push on top instead of replace
|
||||
}).build();
|
||||
}
|
||||
}
|
||||
|
||||
//#swapper
|
||||
static
|
||||
//#swapper
|
||||
public class SwapperApp {
|
||||
public static void main(String[] args) {
|
||||
ActorSystem system = ActorSystem.create("SwapperSystem");
|
||||
ActorRef swapper = system.actorOf(Props.create(Swapper.class), "swapper");
|
||||
swapper.tell(Swap, ActorRef.noSender()); // logs Hi
|
||||
swapper.tell(Swap, ActorRef.noSender()); // logs Ho
|
||||
swapper.tell(Swap, ActorRef.noSender()); // logs Hi
|
||||
swapper.tell(Swap, ActorRef.noSender()); // logs Ho
|
||||
swapper.tell(Swap, ActorRef.noSender()); // logs Hi
|
||||
swapper.tell(Swap, ActorRef.noSender()); // logs Ho
|
||||
system.shutdown();
|
||||
}
|
||||
}
|
||||
//#swapper
|
||||
|
||||
|
||||
@Test
|
||||
public void creatingActorWithSystemActorOf() {
|
||||
//#system-actorOf
|
||||
// ActorSystem is a heavy object: create only one per application
|
||||
final ActorSystem system = ActorSystem.create("MySystem");
|
||||
final ActorRef myActor = system.actorOf(Props.create(MyActor.class), "myactor");
|
||||
//#system-actorOf
|
||||
try {
|
||||
new JavaTestKit(system) {
|
||||
{
|
||||
myActor.tell("hello", getRef());
|
||||
expectMsgEquals("hello");
|
||||
}
|
||||
};
|
||||
} finally {
|
||||
JavaTestKit.shutdownActorSystem(system);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void creatingPropsConfig() {
|
||||
//#creating-props
|
||||
Props props1 = Props.create(MyActor.class);
|
||||
Props props2 = Props.create(ActorWithArgs.class,
|
||||
() -> new ActorWithArgs("arg")); // careful, see below
|
||||
Props props3 = Props.create(ActorWithArgs.class, "arg");
|
||||
//#creating-props
|
||||
|
||||
//#creating-props-deprecated
|
||||
// NOT RECOMMENDED within another actor:
|
||||
// encourages to close over enclosing class
|
||||
Props props7 = Props.create(ActorWithArgs.class,
|
||||
() -> new ActorWithArgs("arg"));
|
||||
//#creating-props-deprecated
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void creatingPropsIllegal() {
|
||||
//#creating-props-illegal
|
||||
// This will throw an IllegalArgumentException since some runtime
|
||||
// type information of the lambda is erased.
|
||||
// Use Props.create(actorClass, Creator) instead.
|
||||
Props props = Props.create(() -> new ActorWithArgs("arg"));
|
||||
//#creating-props-illegal
|
||||
}
|
||||
|
||||
static
|
||||
//#receive-timeout
|
||||
public class ReceiveTimeoutActor extends AbstractActor {
|
||||
public ReceiveTimeoutActor() {
|
||||
// To set an initial delay
|
||||
context().setReceiveTimeout(Duration.create("10 seconds"));
|
||||
}
|
||||
//#receive-timeout
|
||||
ActorRef target = context().system().deadLetters();
|
||||
//#receive-timeout
|
||||
|
||||
@Override
|
||||
public PartialFunction<Object, BoxedUnit> receive() {
|
||||
return ReceiveBuilder.
|
||||
matchEquals("Hello", s -> {
|
||||
// To set in a response to a message
|
||||
context().setReceiveTimeout(Duration.create("1 second"));
|
||||
//#receive-timeout
|
||||
target = sender();
|
||||
target.tell("Hello world", self());
|
||||
//#receive-timeout
|
||||
}).
|
||||
match(ReceiveTimeout.class, r -> {
|
||||
// To turn it off
|
||||
context().setReceiveTimeout(Duration.Undefined());
|
||||
//#receive-timeout
|
||||
target.tell("timeout", self());
|
||||
//#receive-timeout
|
||||
}).build();
|
||||
}
|
||||
}
|
||||
//#receive-timeout
|
||||
|
||||
@Test
|
||||
public void using_receiveTimeout() {
|
||||
final ActorRef myActor = system.actorOf(Props.create(ReceiveTimeoutActor.class));
|
||||
new JavaTestKit(system) {
|
||||
{
|
||||
myActor.tell("Hello", getRef());
|
||||
expectMsgEquals("Hello world");
|
||||
expectMsgEquals("timeout");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static
|
||||
//#hot-swap-actor
|
||||
public class HotSwapActor extends AbstractActor {
|
||||
private PartialFunction<Object, BoxedUnit> angry;
|
||||
private PartialFunction<Object, BoxedUnit> happy;
|
||||
|
||||
{
|
||||
angry =
|
||||
ReceiveBuilder.
|
||||
matchEquals("foo", s -> {
|
||||
sender().tell("I am already angry?", self());
|
||||
}).
|
||||
matchEquals("bar", s -> {
|
||||
context().become(happy);
|
||||
}).build();
|
||||
|
||||
happy = ReceiveBuilder.
|
||||
matchEquals("bar", s -> {
|
||||
sender().tell("I am already happy :-)", self());
|
||||
}).
|
||||
matchEquals("foo", s -> {
|
||||
context().become(angry);
|
||||
}).build();
|
||||
}
|
||||
|
||||
public PartialFunction<Object, BoxedUnit> receive() {
|
||||
return ReceiveBuilder.
|
||||
matchEquals("foo", s -> {
|
||||
context().become(angry);
|
||||
}).
|
||||
matchEquals("bar", s -> {
|
||||
context().become(happy);
|
||||
}).build();
|
||||
}
|
||||
}
|
||||
//#hot-swap-actor
|
||||
|
||||
@Test
|
||||
public void using_hot_swap() {
|
||||
final ActorRef actor = system.actorOf(Props.create(HotSwapActor.class), "hot");
|
||||
new JavaTestKit(system) {
|
||||
{
|
||||
actor.tell("foo", getRef());
|
||||
actor.tell("foo", getRef());
|
||||
expectMsgEquals("I am already angry?");
|
||||
actor.tell("bar", getRef());
|
||||
actor.tell("bar", getRef());
|
||||
expectMsgEquals("I am already happy :-)");
|
||||
actor.tell("foo", getRef());
|
||||
actor.tell("foo", getRef());
|
||||
expectMsgEquals("I am already angry?");
|
||||
expectNoMsg(Duration.create(1, TimeUnit.SECONDS));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
//#stash
|
||||
public class ActorWithProtocol extends AbstractActorWithStash {
|
||||
public PartialFunction<Object, BoxedUnit> receive() {
|
||||
return ReceiveBuilder.
|
||||
matchEquals("open", s -> {
|
||||
context().become(ReceiveBuilder.
|
||||
matchEquals("write", ws -> { /* do writing */ }).
|
||||
matchEquals("close", cs -> {
|
||||
unstashAll();
|
||||
context().unbecome();
|
||||
}).
|
||||
matchAny(msg -> stash()).build(), false);
|
||||
}).
|
||||
matchAny(msg -> stash()).build();
|
||||
}
|
||||
}
|
||||
//#stash
|
||||
|
||||
@Test
|
||||
public void using_Stash() {
|
||||
final ActorRef actor = system.actorOf(Props.create(ActorWithProtocol.class), "stash");
|
||||
}
|
||||
|
||||
static
|
||||
//#watch
|
||||
public class WatchActor extends AbstractActor {
|
||||
private final ActorRef child = context().actorOf(Props.empty(), "target");
|
||||
{
|
||||
context().watch(child); // <-- this is the only call needed for registration
|
||||
}
|
||||
private ActorRef lastSender = system.deadLetters();
|
||||
|
||||
public PartialFunction<Object, BoxedUnit> receive() {
|
||||
return ReceiveBuilder.
|
||||
matchEquals("kill", s -> {
|
||||
context().stop(child);
|
||||
lastSender = sender();
|
||||
}).
|
||||
match(Terminated.class, t -> t.actor().equals(child), t -> {
|
||||
lastSender.tell("finished", self());
|
||||
}).build();
|
||||
}
|
||||
}
|
||||
//#watch
|
||||
|
||||
@Test
|
||||
public void using_watch() {
|
||||
ActorRef actor = system.actorOf(Props.create(WatchActor.class));
|
||||
|
||||
new JavaTestKit(system) {
|
||||
{
|
||||
actor.tell("kill", getRef());
|
||||
expectMsgEquals("finished");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static
|
||||
//#identify
|
||||
public class Follower extends AbstractActor {
|
||||
final Integer identifyId = 1;
|
||||
|
||||
{
|
||||
ActorSelection selection = context().actorSelection("/user/another");
|
||||
selection.tell(new Identify(identifyId), self());
|
||||
}
|
||||
|
||||
public PartialFunction<Object, BoxedUnit> receive() {
|
||||
return ReceiveBuilder.
|
||||
match(ActorIdentity.class, id -> id.getRef() != null, id -> {
|
||||
ActorRef ref = id.getRef();
|
||||
context().watch(ref);
|
||||
context().become(active(ref));
|
||||
}).
|
||||
match(ActorIdentity.class, id -> id.getRef() == null, id -> {
|
||||
context().stop(self());
|
||||
}).build();
|
||||
}
|
||||
|
||||
final PartialFunction<Object, BoxedUnit> active(final ActorRef another) {
|
||||
return ReceiveBuilder.
|
||||
match(Terminated.class, t -> t.actor().equals(another), t -> {
|
||||
context().stop(self());
|
||||
}).build();
|
||||
}
|
||||
}
|
||||
//#identify
|
||||
|
||||
@Test
|
||||
public void using_Identify() {
|
||||
ActorRef a = system.actorOf(Props.empty());
|
||||
ActorRef b = system.actorOf(Props.create(Follower.class));
|
||||
|
||||
new JavaTestKit(system) {
|
||||
{
|
||||
watch(b);
|
||||
system.stop(a);
|
||||
assertEquals(expectMsgClass(Duration.create(2, TimeUnit.SECONDS), Terminated.class).actor(), b);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package docs.actor;
|
||||
|
||||
import akka.actor.*;
|
||||
import akka.japi.pf.ReceiveBuilder;
|
||||
import akka.testkit.JavaTestKit;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import scala.PartialFunction;
|
||||
import scala.concurrent.duration.Duration;
|
||||
import scala.runtime.BoxedUnit;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class InitializationDocTest {
|
||||
|
||||
static ActorSystem system = null;
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
system = ActorSystem.create("InitializationDocTest");
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() {
|
||||
system.shutdown();
|
||||
system.awaitTermination(Duration.create("5 seconds"));
|
||||
}
|
||||
|
||||
public static class MessageInitExample extends AbstractActor {
|
||||
//#messageInit
|
||||
private String initializeMe = null;
|
||||
|
||||
@Override
|
||||
public PartialFunction<Object, BoxedUnit> receive() {
|
||||
return ReceiveBuilder.
|
||||
matchEquals("init", m1 -> {
|
||||
initializeMe = "Up and running";
|
||||
context().become(ReceiveBuilder.
|
||||
matchEquals("U OK?", m2 -> {
|
||||
sender().tell(initializeMe, self());
|
||||
}).build());
|
||||
}).build();
|
||||
}
|
||||
//#messageInit
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIt() {
|
||||
|
||||
new JavaTestKit(system) {{
|
||||
ActorRef testactor = system.actorOf(Props.create(MessageInitExample.class), "testactor");
|
||||
String msg = "U OK?";
|
||||
|
||||
testactor.tell(msg, getRef());
|
||||
expectNoMsg(Duration.create(1, TimeUnit.SECONDS));
|
||||
|
||||
testactor.tell("init", getRef());
|
||||
testactor.tell(msg, getRef());
|
||||
expectMsgEquals("Up and running");
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,149 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package docs.actor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class Messages {
|
||||
static
|
||||
//#immutable-message
|
||||
public class ImmutableMessage {
|
||||
private final int sequenceNumber;
|
||||
private final List<String> values;
|
||||
|
||||
public ImmutableMessage(int sequenceNumber, List<String> values) {
|
||||
this.sequenceNumber = sequenceNumber;
|
||||
this.values = Collections.unmodifiableList(new ArrayList<String>(values));
|
||||
}
|
||||
|
||||
public int getSequenceNumber() {
|
||||
return sequenceNumber;
|
||||
}
|
||||
|
||||
public List<String> getValues() {
|
||||
return values;
|
||||
}
|
||||
}
|
||||
//#immutable-message
|
||||
|
||||
public static class DoIt {
|
||||
private final ImmutableMessage msg;
|
||||
|
||||
DoIt(ImmutableMessage msg) {
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public ImmutableMessage getMsg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
DoIt doIt = (DoIt) o;
|
||||
|
||||
if (!msg.equals(doIt.msg)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return msg.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DoIt{" +
|
||||
"msg=" + msg +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
public static class Message {
|
||||
final String str;
|
||||
|
||||
Message(String str) {
|
||||
this.str = str;
|
||||
}
|
||||
|
||||
public String getStr() {
|
||||
return str;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Message message = (Message) o;
|
||||
|
||||
if (!str.equals(message.str)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return str.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Message{" +
|
||||
"str='" + str + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
public static enum Swap {
|
||||
Swap
|
||||
}
|
||||
|
||||
public static class Result {
|
||||
final String x;
|
||||
final String s;
|
||||
|
||||
public Result(String x, String s) {
|
||||
this.x = x;
|
||||
this.s = s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((s == null) ? 0 : s.hashCode());
|
||||
result = prime * result + ((x == null) ? 0 : x.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Result other = (Result) obj;
|
||||
if (s == null) {
|
||||
if (other.s != null)
|
||||
return false;
|
||||
} else if (!s.equals(other.s))
|
||||
return false;
|
||||
if (x == null) {
|
||||
if (other.x != null)
|
||||
return false;
|
||||
} else if (!x.equals(other.x))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package docs.actor;
|
||||
|
||||
//#imports
|
||||
import akka.actor.AbstractActor;
|
||||
import akka.event.Logging;
|
||||
import akka.event.LoggingAdapter;
|
||||
import akka.japi.pf.ReceiveBuilder;
|
||||
import scala.PartialFunction;
|
||||
import scala.runtime.BoxedUnit;
|
||||
|
||||
//#imports
|
||||
|
||||
//#my-actor
|
||||
public class MyActor extends AbstractActor {
|
||||
private final LoggingAdapter log = Logging.getLogger(context().system(), this);
|
||||
|
||||
@Override
|
||||
public PartialFunction<Object, BoxedUnit> receive() {
|
||||
return ReceiveBuilder.
|
||||
match(String.class, s -> {
|
||||
log.info("Received String message: {}", s);
|
||||
//#my-actor
|
||||
//#reply
|
||||
sender().tell(s, self());
|
||||
//#reply
|
||||
//#my-actor
|
||||
}).
|
||||
matchAny(o -> log.info("received unknown message")).build();
|
||||
}
|
||||
}
|
||||
//#my-actor
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package docs.actor;
|
||||
|
||||
//#sample-actor
|
||||
import akka.actor.AbstractActor;
|
||||
import akka.japi.pf.ReceiveBuilder;
|
||||
import scala.PartialFunction;
|
||||
import scala.runtime.BoxedUnit;
|
||||
|
||||
public class SampleActor extends AbstractActor {
|
||||
|
||||
private PartialFunction<Object, BoxedUnit> guarded = ReceiveBuilder.
|
||||
match(String.class, s -> s.contains("guard"), s -> {
|
||||
sender().tell("contains(guard): " + s, self());
|
||||
context().unbecome();
|
||||
}).build();
|
||||
|
||||
@Override
|
||||
public PartialFunction<Object, BoxedUnit> receive() {
|
||||
return ReceiveBuilder.
|
||||
match(Double.class, d -> {
|
||||
sender().tell(d.isNaN() ? 0 : d, self());
|
||||
}).
|
||||
match(Integer.class, i -> {
|
||||
sender().tell(i * 10, self());
|
||||
}).
|
||||
match(String.class, s -> s.startsWith("guard"), s -> {
|
||||
sender().tell("startsWith(guard): " + s.toUpperCase(), self());
|
||||
context().become(guarded, false);
|
||||
}).build();
|
||||
}
|
||||
}
|
||||
//#sample-actor
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package docs.actor;
|
||||
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.actor.Props;
|
||||
import akka.testkit.JavaTestKit;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class SampleActorTest {
|
||||
|
||||
static ActorSystem system;
|
||||
|
||||
@BeforeClass
|
||||
public static void setup() {
|
||||
system = ActorSystem.create("SampleActorTest");
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDown() {
|
||||
JavaTestKit.shutdownActorSystem(system);
|
||||
system = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSampleActor()
|
||||
{
|
||||
new JavaTestKit(system) {{
|
||||
final ActorRef subject = system.actorOf(Props.create(SampleActor.class), "sample-actor");
|
||||
final ActorRef probeRef = getRef();
|
||||
|
||||
subject.tell(47.11, probeRef);
|
||||
subject.tell("and no guard in the beginning", probeRef);
|
||||
subject.tell("guard is a good thing", probeRef);
|
||||
subject.tell(47.11, probeRef);
|
||||
subject.tell(4711, probeRef);
|
||||
subject.tell("and no guard in the beginning", probeRef);
|
||||
subject.tell(4711, probeRef);
|
||||
subject.tell("and an unmatched message", probeRef);
|
||||
|
||||
expectMsgEquals(47.11);
|
||||
assertTrue(expectMsgClass(String.class).startsWith("startsWith(guard):"));
|
||||
assertTrue(expectMsgClass(String.class).startsWith("contains(guard):"));
|
||||
expectMsgEquals(47110);
|
||||
expectNoMsg();
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package docs.actor.fsm;
|
||||
|
||||
//#simple-imports
|
||||
import akka.actor.AbstractFSM;
|
||||
import akka.actor.ActorRef;
|
||||
import akka.japi.pf.UnitMatch;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import scala.concurrent.duration.Duration;
|
||||
//#simple-imports
|
||||
|
||||
import static docs.actor.fsm.Buncher.Data;
|
||||
import static docs.actor.fsm.Buncher.State.*;
|
||||
import static docs.actor.fsm.Buncher.State;
|
||||
import static docs.actor.fsm.Buncher.Uninitialized.*;
|
||||
import static docs.actor.fsm.Events.*;
|
||||
|
||||
//#simple-fsm
|
||||
public class Buncher extends AbstractFSM<State, Data> {
|
||||
{
|
||||
//#fsm-body
|
||||
startWith(Idle, Uninitialized);
|
||||
|
||||
//#when-syntax
|
||||
when(Idle,
|
||||
matchEvent(SetTarget.class, Uninitialized.class,
|
||||
(setTarget, uninitialized) ->
|
||||
stay().using(new Todo(setTarget.getRef(), new LinkedList<>()))));
|
||||
//#when-syntax
|
||||
|
||||
//#transition-elided
|
||||
onTransition(
|
||||
matchState(Active, Idle, () -> {
|
||||
// reuse this matcher
|
||||
final UnitMatch<Data> m = UnitMatch.create(
|
||||
matchData(Todo.class,
|
||||
todo -> todo.getTarget().tell(new Batch(todo.getQueue()), self())));
|
||||
m.match(stateData());
|
||||
}).
|
||||
state(Idle, Active, () -> {/* Do something here */}));
|
||||
//#transition-elided
|
||||
|
||||
when(Active, Duration.create(1, "second"),
|
||||
matchEvent(Arrays.asList(Flush.class, StateTimeout()), Todo.class,
|
||||
todo -> goTo(Idle).using(todo.copy(new LinkedList<>()))));
|
||||
|
||||
//#unhandled-elided
|
||||
whenUnhandled(
|
||||
matchEvent(Queue.class, Todo.class,
|
||||
(queue, todo) -> goTo(Active).using(todo.addElement(queue.getObj()))).
|
||||
anyEvent((event, state) -> {
|
||||
log().warning("received unhandled request {} in state {}/{}",
|
||||
event, stateName(), state);
|
||||
return stay();
|
||||
}));
|
||||
//#unhandled-elided
|
||||
|
||||
initialize();
|
||||
//#fsm-body
|
||||
}
|
||||
//#simple-fsm
|
||||
|
||||
static
|
||||
//#simple-state
|
||||
// states
|
||||
enum State {
|
||||
Idle, Active
|
||||
}
|
||||
|
||||
//#simple-state
|
||||
static
|
||||
//#simple-state
|
||||
// state data
|
||||
interface Data {
|
||||
}
|
||||
|
||||
//#simple-state
|
||||
static
|
||||
//#simple-state
|
||||
enum Uninitialized implements Data {
|
||||
Uninitialized
|
||||
}
|
||||
|
||||
//#simple-state
|
||||
static
|
||||
//#simple-state
|
||||
final class Todo implements Data {
|
||||
private final ActorRef target;
|
||||
private final List<Object> queue;
|
||||
|
||||
public Todo(ActorRef target, List<Object> queue) {
|
||||
this.target = target;
|
||||
this.queue = queue;
|
||||
}
|
||||
|
||||
public ActorRef getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
public List<Object> getQueue() {
|
||||
return queue;
|
||||
}
|
||||
//#boilerplate
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Todo{" +
|
||||
"target=" + target +
|
||||
", queue=" + queue +
|
||||
'}';
|
||||
}
|
||||
|
||||
public Todo addElement(Object element) {
|
||||
List<Object> nQueue = new LinkedList<>(queue);
|
||||
nQueue.add(element);
|
||||
return new Todo(this.target, nQueue);
|
||||
}
|
||||
|
||||
public Todo copy(List<Object> queue) {
|
||||
return new Todo(this.target, queue);
|
||||
}
|
||||
|
||||
public Todo copy(ActorRef target) {
|
||||
return new Todo(target, this.queue);
|
||||
}
|
||||
//#boilerplate
|
||||
}
|
||||
//#simple-state
|
||||
//#simple-fsm
|
||||
}
|
||||
//#simple-fsm
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package docs.actor.fsm;
|
||||
|
||||
import akka.actor.ActorRef;
|
||||
import akka.actor.ActorSystem;
|
||||
import akka.actor.Props;
|
||||
import akka.testkit.JavaTestKit;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import docs.actor.fsm.*;
|
||||
import static docs.actor.fsm.Events.Batch;
|
||||
import static docs.actor.fsm.Events.Queue;
|
||||
import static docs.actor.fsm.Events.SetTarget;
|
||||
import static docs.actor.fsm.Events.Flush.Flush;
|
||||
|
||||
//#test-code
|
||||
public class BuncherTest {
|
||||
|
||||
static ActorSystem system;
|
||||
|
||||
@BeforeClass
|
||||
public static void setup() {
|
||||
system = ActorSystem.create("BuncherTest");
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDown() {
|
||||
JavaTestKit.shutdownActorSystem(system);
|
||||
system = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuncherActorBatchesCorrectly()
|
||||
{
|
||||
new JavaTestKit(system) {{
|
||||
final ActorRef buncher =
|
||||
system.actorOf(Props.create(Buncher.class));
|
||||
final ActorRef probe = getRef();
|
||||
|
||||
buncher.tell(new SetTarget(probe), probe);
|
||||
buncher.tell(new Queue(42), probe);
|
||||
buncher.tell(new Queue(43), probe);
|
||||
LinkedList<Object> list1 = new LinkedList<>();
|
||||
list1.add(42);
|
||||
list1.add(43);
|
||||
expectMsgEquals(new Batch(list1));
|
||||
buncher.tell(new Queue(44), probe);
|
||||
buncher.tell(Flush, probe);
|
||||
buncher.tell(new Queue(45), probe);
|
||||
LinkedList<Object> list2 = new LinkedList<>();
|
||||
list2.add(44);
|
||||
expectMsgEquals(new Batch(list2));
|
||||
LinkedList<Object> list3 = new LinkedList<>();
|
||||
list3.add(45);
|
||||
expectMsgEquals(new Batch(list3));
|
||||
system.stop(buncher);
|
||||
}};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuncherActorDoesntBatchUninitialized()
|
||||
{
|
||||
new JavaTestKit(system) {{
|
||||
final ActorRef buncher =
|
||||
system.actorOf(Props.create(Buncher.class));
|
||||
final ActorRef probe = getRef();
|
||||
|
||||
buncher.tell(new Queue(42), probe);
|
||||
expectNoMsg();
|
||||
system.stop(buncher);
|
||||
}};
|
||||
}
|
||||
}
|
||||
//#test-code
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package docs.actor.fsm;
|
||||
|
||||
import akka.actor.ActorRef;
|
||||
import java.util.List;
|
||||
|
||||
public class Events {
|
||||
|
||||
static
|
||||
//#simple-events
|
||||
public final class SetTarget {
|
||||
private final ActorRef ref;
|
||||
|
||||
public SetTarget(ActorRef ref) {
|
||||
this.ref = ref;
|
||||
}
|
||||
|
||||
public ActorRef getRef() {
|
||||
return ref;
|
||||
}
|
||||
//#boilerplate
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SetTarget{" +
|
||||
"ref=" + ref +
|
||||
'}';
|
||||
}
|
||||
//#boilerplate
|
||||
}
|
||||
|
||||
//#simple-events
|
||||
static
|
||||
//#simple-events
|
||||
public final class Queue {
|
||||
private final Object obj;
|
||||
|
||||
public Queue(Object obj) {
|
||||
this.obj = obj;
|
||||
}
|
||||
|
||||
public Object getObj() {
|
||||
return obj;
|
||||
}
|
||||
//#boilerplate
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Queue{" +
|
||||
"obj=" + obj +
|
||||
'}';
|
||||
}
|
||||
//#boilerplate
|
||||
}
|
||||
|
||||
//#simple-events
|
||||
static
|
||||
//#simple-events
|
||||
public final class Batch {
|
||||
private final List<Object> list;
|
||||
|
||||
public Batch(List<Object> list) {
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
public List<Object> getList() {
|
||||
return list;
|
||||
}
|
||||
//#boilerplate
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Batch batch = (Batch) o;
|
||||
|
||||
return list.equals(batch.list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return list.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append( "Batch{list=");
|
||||
list.stream().forEachOrdered(e -> { builder.append(e); builder.append(","); });
|
||||
int len = builder.length();
|
||||
builder.replace(len, len, "}");
|
||||
return builder.toString();
|
||||
}
|
||||
//#boilerplate
|
||||
}
|
||||
|
||||
//#simple-events
|
||||
static
|
||||
//#simple-events
|
||||
public enum Flush {
|
||||
Flush
|
||||
}
|
||||
//#simple-events
|
||||
}
|
||||
|
|
@ -0,0 +1,179 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2014 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
|
||||
package docs.actor.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.actor.fsm.FSMDocTest.StateType.*;
|
||||
import static docs.actor.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", (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, null, (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", (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);
|
||||
assertThat(msg, CoreMatchers.startsWith("LogEntry(SomeState,Foo,Actor[akka://FSMDocTest/system/"));
|
||||
}};
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue